Merge "Start of Minikin integration"
diff --git a/Android.mk b/Android.mk
index 232f5bf..89b2884 100644
--- a/Android.mk
+++ b/Android.mk
@@ -68,6 +68,7 @@
 	core/java/android/app/IActivityController.aidl \
 	core/java/android/app/IActivityPendingResult.aidl \
 	core/java/android/app/IAlarmManager.aidl \
+	core/java/android/app/IAppTask.aidl \
 	core/java/android/app/IBackupAgent.aidl \
 	core/java/android/app/IInstrumentationWatcher.aidl \
 	core/java/android/app/INotificationManager.aidl \
@@ -76,7 +77,8 @@
 	core/java/android/app/ISearchManagerCallback.aidl \
 	core/java/android/app/IServiceConnection.aidl \
 	core/java/android/app/IStopUserCallback.aidl \
-	core/java/android/app/IThumbnailReceiver.aidl \
+	core/java/android/app/task/ITaskCallback.aidl \
+	core/java/android/app/task/ITaskService.aidl \
 	core/java/android/app/IThumbnailRetriever.aidl \
 	core/java/android/app/ITransientNotification.aidl \
 	core/java/android/app/IUiAutomationConnection.aidl \
@@ -125,6 +127,8 @@
 	core/java/android/content/pm/IPackageDeleteObserver.aidl \
 	core/java/android/content/pm/IPackageInstallObserver.aidl \
 	core/java/android/content/pm/IPackageInstallObserver2.aidl \
+	core/java/android/content/pm/IPackageInstaller.aidl \
+	core/java/android/content/pm/IPackageInstallerSession.aidl \
 	core/java/android/content/pm/IPackageManager.aidl \
 	core/java/android/content/pm/IPackageMoveObserver.aidl \
 	core/java/android/content/pm/IPackageStatsObserver.aidl \
@@ -155,6 +159,7 @@
 	core/java/android/net/INetworkManagementEventObserver.aidl \
 	core/java/android/net/INetworkPolicyListener.aidl \
 	core/java/android/net/INetworkPolicyManager.aidl \
+	core/java/android/net/INetworkScoreCache.aidl \
 	core/java/android/net/INetworkScoreService.aidl \
 	core/java/android/net/INetworkStatsService.aidl \
 	core/java/android/net/INetworkStatsSession.aidl \
@@ -197,6 +202,8 @@
 	core/java/android/service/dreams/IDozeHardware.aidl \
 	core/java/android/service/dreams/IDreamManager.aidl \
 	core/java/android/service/dreams/IDreamService.aidl \
+	core/java/android/service/fingerprint/IFingerprintService.aidl \
+	core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl \
 	core/java/android/service/trust/ITrustAgentService.aidl \
 	core/java/android/service/trust/ITrustAgentServiceCallback.aidl \
 	core/java/android/service/voice/IVoiceInteractionService.aidl \
@@ -298,24 +305,37 @@
 	media/java/android/media/IRemoteDisplayProvider.aidl \
 	media/java/android/media/IRemoteVolumeObserver.aidl \
 	media/java/android/media/IRingtonePlayer.aidl \
-	media/java/android/media/routeprovider/IRouteConnection.aidl \
-	media/java/android/media/routeprovider/IRouteProvider.aidl \
-	media/java/android/media/routeprovider/IRouteProviderCallback.aidl \
-	media/java/android/media/session/ISessionController.aidl \
-	media/java/android/media/session/ISessionControllerCallback.aidl \
-	media/java/android/media/session/ISession.aidl \
-	media/java/android/media/session/ISessionCallback.aidl \
-	media/java/android/media/session/ISessionManager.aidl \
+        media/java/android/media/routeprovider/IRouteConnection.aidl \
+        media/java/android/media/routeprovider/IRouteProvider.aidl \
+        media/java/android/media/routeprovider/IRouteProviderCallback.aidl \
+        media/java/android/media/session/ISessionController.aidl \
+        media/java/android/media/session/ISessionControllerCallback.aidl \
+        media/java/android/media/session/ISession.aidl \
+        media/java/android/media/session/ISessionCallback.aidl \
+        media/java/android/media/session/ISessionManager.aidl \
+	telecomm/java/com/android/internal/telecomm/ICallService.aidl \
+	telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl \
+	telecomm/java/com/android/internal/telecomm/ICallServiceLookupResponse.aidl \
+	telecomm/java/com/android/internal/telecomm/ICallServiceProvider.aidl \
+	telecomm/java/com/android/internal/telecomm/ICallServiceSelector.aidl \
+	telecomm/java/com/android/internal/telecomm/ICallServiceSelectorAdapter.aidl \
+	telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl \
+	telecomm/java/com/android/internal/telecomm/IInCallService.aidl \
 	telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
 	telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
 	telephony/java/com/android/internal/telephony/ITelephony.aidl \
 	telephony/java/com/android/internal/telephony/ITelephonyListener.aidl \
+	telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl \
+	telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl \
+	telephony/java/com/android/internal/telephony/IThirdPartyCallSendDtmfCallback.aidl \
+	telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl \
 	telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
 	telephony/java/com/android/internal/telephony/ISms.aidl \
 	telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
 	wifi/java/android/net/wifi/IWifiManager.aidl \
 	wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl \
 	wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
+	wifi/java/android/net/wifi/IWifiScanner.aidl \
 	packages/services/PacProcessor/com/android/net/IProxyService.aidl \
 	packages/services/Proxy/com/android/net/IProxyCallback.aidl \
 	packages/services/Proxy/com/android/net/IProxyPortListener.aidl \
@@ -716,8 +736,9 @@
 $(full_target): $(framework_built) $(gen)
 
 # Run this for checkbuild
-.PHONY: checkbuild
 checkbuild: doc-comment-check-docs
+# Check comment when you are updating the API
+update-api: doc-comment-check-docs
 
 # ====  static html in the sdk ==================================
 include $(CLEAR_VARS)
diff --git a/CleanSpec.mk b/CleanSpec.mk
index c6f6a62..c841338 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -190,6 +190,7 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/view/IMagnificationCallbacks*)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/tv/)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/media/java/android/media/)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/app)
 
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/api/current.txt b/api/current.txt
index 54c9d90..22892d8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -250,7 +250,7 @@
     field public static final int actionBarTabBarStyle = 16843508; // 0x10102f4
     field public static final int actionBarTabStyle = 16843507; // 0x10102f3
     field public static final int actionBarTabTextStyle = 16843509; // 0x10102f5
-    field public static final int actionBarTheme = 16843837; // 0x101043d
+    field public static final int actionBarTheme = 16843829; // 0x1010435
     field public static final int actionBarWidgetTheme = 16843671; // 0x1010397
     field public static final int actionButtonStyle = 16843480; // 0x10102d8
     field public static final int actionDropDownStyle = 16843479; // 0x10102d7
@@ -267,6 +267,7 @@
     field public static final int actionModeSplitBackground = 16843677; // 0x101039d
     field public static final int actionModeStyle = 16843668; // 0x1010394
     field public static final int actionOverflowButtonStyle = 16843510; // 0x10102f6
+    field public static final int actionOverflowMenuStyle = 16843849; // 0x1010449
     field public static final int actionProviderClass = 16843657; // 0x1010389
     field public static final int actionViewClass = 16843516; // 0x10102fc
     field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd
@@ -294,7 +295,6 @@
     field public static final int alwaysDrawnWithCache = 16842991; // 0x10100ef
     field public static final int alwaysRetainTaskState = 16843267; // 0x1010203
     field public static final int angle = 16843168; // 0x10101a0
-    field public static final int animate = 16843823; // 0x101042f
     field public static final int animateFirstView = 16843477; // 0x10102d5
     field public static final int animateLayoutChanges = 16843506; // 0x10102f2
     field public static final int animateOnClick = 16843356; // 0x101025c
@@ -313,6 +313,7 @@
     field public static final int autoCompleteTextViewStyle = 16842859; // 0x101006b
     field public static final int autoLink = 16842928; // 0x10100b0
     field public static final int autoMirrored = 16843754; // 0x10103ea
+    field public static final int autoRemoveFromRecents = 16843851; // 0x101044b
     field public static final int autoStart = 16843445; // 0x10102b5
     field public static final deprecated int autoText = 16843114; // 0x101016a
     field public static final int autoUrlDetect = 16843404; // 0x101028c
@@ -381,29 +382,27 @@
     field public static final int clipChildren = 16842986; // 0x10100ea
     field public static final int clipOrientation = 16843274; // 0x101020a
     field public static final int clipToPadding = 16842987; // 0x10100eb
-    field public static final int clipToPath = 16843822; // 0x101042e
+    field public static final int clipToPath = 16843818; // 0x101042a
     field public static final int codes = 16843330; // 0x1010242
     field public static final int collapseColumns = 16843083; // 0x101014b
     field public static final int color = 16843173; // 0x10101a5
-    field public static final int colorAccent = 16843842; // 0x1010442
+    field public static final int colorAccent = 16843834; // 0x101043a
     field public static final int colorActivatedHighlight = 16843664; // 0x1010390
     field public static final int colorBackground = 16842801; // 0x1010031
     field public static final int colorBackgroundCacheHint = 16843435; // 0x10102ab
-    field public static final int colorButtonNormal = 16843829; // 0x1010435
-    field public static final int colorButtonNormalColored = 16843831; // 0x1010437
-    field public static final int colorButtonPressed = 16843830; // 0x1010436
-    field public static final int colorButtonPressedColored = 16843832; // 0x1010438
-    field public static final int colorControlActivated = 16843828; // 0x1010434
-    field public static final int colorControlNormal = 16843827; // 0x1010433
+    field public static final int colorButtonNormal = 16843823; // 0x101042f
+    field public static final int colorButtonPressed = 16843824; // 0x1010430
+    field public static final int colorControlActivated = 16843822; // 0x101042e
+    field public static final int colorControlNormal = 16843821; // 0x101042d
     field public static final int colorFocusedHighlight = 16843663; // 0x101038f
     field public static final int colorForeground = 16842800; // 0x1010030
     field public static final int colorForegroundInverse = 16843270; // 0x1010206
     field public static final int colorLongPressedHighlight = 16843662; // 0x101038e
     field public static final int colorMultiSelectHighlight = 16843665; // 0x1010391
     field public static final int colorPressedHighlight = 16843661; // 0x101038d
-    field public static final int colorPrimary = 16843840; // 0x1010440
-    field public static final int colorPrimaryDark = 16843841; // 0x1010441
-    field public static final int colorPrimaryLight = 16843839; // 0x101043f
+    field public static final int colorPrimary = 16843832; // 0x1010438
+    field public static final int colorPrimaryDark = 16843833; // 0x1010439
+    field public static final int colorPrimaryLight = 16843831; // 0x1010437
     field public static final int columnCount = 16843639; // 0x1010377
     field public static final int columnDelay = 16843215; // 0x10101cf
     field public static final int columnOrderPreserved = 16843640; // 0x1010378
@@ -462,6 +461,7 @@
     field public static final int dividerHorizontal = 16843564; // 0x101032c
     field public static final int dividerPadding = 16843562; // 0x101032a
     field public static final int dividerVertical = 16843530; // 0x101030a
+    field public static final int documentLaunchMode = 16843850; // 0x101044a
     field public static final int drawSelectorOnTop = 16843004; // 0x10100fc
     field public static final int drawable = 16843161; // 0x1010199
     field public static final int drawableBottom = 16843118; // 0x101016e
@@ -484,14 +484,13 @@
     field public static final int dropDownWidth = 16843362; // 0x1010262
     field public static final int duplicateParentState = 16842985; // 0x10100e9
     field public static final int duration = 16843160; // 0x1010198
-    field public static final int durations = 16843814; // 0x1010426
     field public static final int editTextBackground = 16843602; // 0x1010352
     field public static final int editTextColor = 16843601; // 0x1010351
     field public static final int editTextPreferenceStyle = 16842898; // 0x1010092
     field public static final int editTextStyle = 16842862; // 0x101006e
     field public static final deprecated int editable = 16843115; // 0x101016b
     field public static final int editorExtras = 16843300; // 0x1010224
-    field public static final int elevation = 16843852; // 0x101044c
+    field public static final int elevation = 16843845; // 0x1010445
     field public static final int ellipsize = 16842923; // 0x10100ab
     field public static final int ems = 16843096; // 0x1010158
     field public static final int enabled = 16842766; // 0x101000e
@@ -501,9 +500,10 @@
     field public static final int entries = 16842930; // 0x10100b2
     field public static final int entryValues = 16843256; // 0x10101f8
     field public static final int eventsInterceptionEnabled = 16843389; // 0x101027d
-    field public static final int excludeClass = 16843854; // 0x101044e
+    field public static final int excludeClass = 16843847; // 0x1010447
     field public static final int excludeFromRecents = 16842775; // 0x1010017
-    field public static final int excludeId = 16843853; // 0x101044d
+    field public static final int excludeId = 16843846; // 0x1010446
+    field public static final int excludeViewName = 16843858; // 0x1010452
     field public static final int exitFadeDuration = 16843533; // 0x101030d
     field public static final int expandableListPreferredChildIndicatorLeft = 16842834; // 0x1010052
     field public static final int expandableListPreferredChildIndicatorRight = 16842835; // 0x1010053
@@ -532,11 +532,11 @@
     field public static final int fastScrollTextColor = 16843609; // 0x1010359
     field public static final int fastScrollThumbDrawable = 16843574; // 0x1010336
     field public static final int fastScrollTrackDrawable = 16843577; // 0x1010339
-    field public static final int fill = 16843809; // 0x1010421
+    field public static final int fill = 16843808; // 0x1010420
     field public static final int fillAfter = 16843197; // 0x10101bd
     field public static final int fillBefore = 16843196; // 0x10101bc
     field public static final int fillEnabled = 16843343; // 0x101024f
-    field public static final int fillOpacity = 16843808; // 0x1010420
+    field public static final int fillOpacity = 16843807; // 0x101041f
     field public static final int fillViewport = 16843130; // 0x101017a
     field public static final int filter = 16843035; // 0x101011b
     field public static final int filterTouchesWhenObscured = 16843460; // 0x10102c4
@@ -566,6 +566,7 @@
     field public static final int freezesText = 16843116; // 0x101016c
     field public static final int fromAlpha = 16843210; // 0x10101ca
     field public static final int fromDegrees = 16843187; // 0x10101b3
+    field public static final int fromId = 16843854; // 0x101044e
     field public static final int fromScene = 16843741; // 0x10103dd
     field public static final int fromXDelta = 16843206; // 0x10101c6
     field public static final int fromXScale = 16843202; // 0x10101c2
@@ -598,6 +599,7 @@
     field public static final int headerBackground = 16843055; // 0x101012f
     field public static final int headerDividersEnabled = 16843310; // 0x101022e
     field public static final int height = 16843093; // 0x1010155
+    field public static final int hideOnContentScroll = 16843848; // 0x1010448
     field public static final int hint = 16843088; // 0x1010150
     field public static final int homeAsUpIndicator = 16843531; // 0x101030b
     field public static final int homeLayout = 16843549; // 0x101031d
@@ -767,7 +769,6 @@
     field public static final int layout_x = 16843135; // 0x101017f
     field public static final int layout_y = 16843136; // 0x1010180
     field public static final int left = 16843181; // 0x10101ad
-    field public static final int limitTo = 16843824; // 0x1010430
     field public static final int lineSpacingExtra = 16843287; // 0x1010217
     field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
     field public static final int lines = 16843092; // 0x1010154
@@ -829,7 +830,7 @@
     field public static final int name = 16842755; // 0x1010003
     field public static final int navigationMode = 16843471; // 0x10102cf
     field public static final int negativeButtonText = 16843254; // 0x10101f6
-    field public static final int nestedScrollingEnabled = 16843843; // 0x1010443
+    field public static final int nestedScrollingEnabled = 16843835; // 0x101043b
     field public static final int nextFocusDown = 16842980; // 0x10100e4
     field public static final int nextFocusForward = 16843580; // 0x101033c
     field public static final int nextFocusLeft = 16842977; // 0x10100e1
@@ -871,18 +872,18 @@
     field public static final int parentActivityName = 16843687; // 0x10103a7
     field public static final deprecated int password = 16843100; // 0x101015c
     field public static final int path = 16842794; // 0x101002a
-    field public static final int pathData = 16843810; // 0x1010422
+    field public static final int pathData = 16843809; // 0x1010421
     field public static final int pathPattern = 16842796; // 0x101002c
     field public static final int pathPrefix = 16842795; // 0x101002b
     field public static final int permission = 16842758; // 0x1010006
     field public static final int permissionFlags = 16843719; // 0x10103c7
     field public static final int permissionGroup = 16842762; // 0x101000a
     field public static final int permissionGroupFlags = 16843717; // 0x10103c5
-    field public static final int persistable = 16843833; // 0x1010439
+    field public static final int persistable = 16843825; // 0x1010431
     field public static final int persistent = 16842765; // 0x101000d
     field public static final int persistentDrawingCache = 16842990; // 0x10100ee
     field public static final deprecated int phoneNumber = 16843111; // 0x1010167
-    field public static final int pinned = 16843826; // 0x1010432
+    field public static final int pinned = 16843820; // 0x101042c
     field public static final int pivotX = 16843189; // 0x10101b5
     field public static final int pivotY = 16843190; // 0x10101b6
     field public static final int popupAnimationStyle = 16843465; // 0x10102c9
@@ -937,7 +938,6 @@
     field public static final int readPermission = 16842759; // 0x1010007
     field public static final int repeatCount = 16843199; // 0x10101bf
     field public static final int repeatMode = 16843200; // 0x10101c0
-    field public static final int repeatStyle = 16843816; // 0x1010428
     field public static final int reqFiveWayNav = 16843314; // 0x1010232
     field public static final int reqHardKeyboard = 16843305; // 0x1010229
     field public static final int reqKeyboardType = 16843304; // 0x1010228
@@ -947,7 +947,7 @@
     field public static final int required = 16843406; // 0x101028e
     field public static final int requiredAccountType = 16843734; // 0x10103d6
     field public static final int requiredForAllUsers = 16843728; // 0x10103d0
-    field public static final int requiredForProfile = 16843825; // 0x1010431
+    field public static final int requiredForProfile = 16843819; // 0x101042b
     field public static final int requiresFadingEdge = 16843685; // 0x10103a5
     field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
     field public static final int resizeMode = 16843619; // 0x1010363
@@ -956,6 +956,7 @@
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
     field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
     field public static final int restrictedAccountType = 16843733; // 0x10103d5
+    field public static final int reversible = 16843855; // 0x101044f
     field public static final int right = 16843183; // 0x10101af
     field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
     field public static final int ringtoneType = 16843257; // 0x10101f9
@@ -1011,8 +1012,7 @@
     field public static final int selectableItemBackground = 16843534; // 0x101030e
     field public static final int selectedDateVerticalBar = 16843591; // 0x1010347
     field public static final int selectedWeekBackgroundColor = 16843586; // 0x1010342
-    field public static final int sequence = 16843815; // 0x1010427
-    field public static final int sessionService = 16843850; // 0x101044a
+    field public static final int sessionService = 16843842; // 0x1010442
     field public static final int settingsActivity = 16843301; // 0x1010225
     field public static final int shadowColor = 16843105; // 0x1010161
     field public static final int shadowDx = 16843106; // 0x1010162
@@ -1020,7 +1020,6 @@
     field public static final int shadowRadius = 16843108; // 0x1010164
     field public static final int shape = 16843162; // 0x101019a
     field public static final int shareInterpolator = 16843195; // 0x10101bb
-    field public static final int sharedElementName = 16843803; // 0x101041b
     field public static final int sharedUserId = 16842763; // 0x101000b
     field public static final int sharedUserLabel = 16843361; // 0x1010261
     field public static final int shouldDisableView = 16843246; // 0x10101ee
@@ -1034,7 +1033,7 @@
     field public static final int shrinkColumns = 16843082; // 0x101014a
     field public static final deprecated int singleLine = 16843101; // 0x101015d
     field public static final int singleUser = 16843711; // 0x10103bf
-    field public static final int slideEdge = 16843836; // 0x101043c
+    field public static final int slideEdge = 16843828; // 0x1010434
     field public static final int smallIcon = 16843422; // 0x101029e
     field public static final int smallScreens = 16843396; // 0x1010284
     field public static final int smoothScrollbar = 16843313; // 0x1010231
@@ -1046,16 +1045,19 @@
     field public static final int spinnerStyle = 16842881; // 0x1010081
     field public static final int spinnersShown = 16843595; // 0x101034b
     field public static final int splitMotionEvents = 16843503; // 0x10102ef
+    field public static final int splitTrack = 16843856; // 0x1010450
     field public static final int src = 16843033; // 0x1010119
     field public static final int ssp = 16843747; // 0x10103e3
     field public static final int sspPattern = 16843749; // 0x10103e5
     field public static final int sspPrefix = 16843748; // 0x10103e4
     field public static final int stackFromBottom = 16843005; // 0x10100fd
+    field public static final int stackViewStyle = 16843843; // 0x1010443
     field public static final int starStyle = 16842882; // 0x1010082
     field public static final int startColor = 16843165; // 0x101019d
     field public static final int startDelay = 16843746; // 0x10103e2
     field public static final int startOffset = 16843198; // 0x10101be
     field public static final deprecated int startYear = 16843132; // 0x101017c
+    field public static final int stateListAnimator = 16843852; // 0x101044c
     field public static final int stateNotNeeded = 16842774; // 0x1010016
     field public static final int state_above_anchor = 16842922; // 0x10100aa
     field public static final int state_accelerated = 16843547; // 0x101031b
@@ -1085,13 +1087,13 @@
     field public static final int streamType = 16843273; // 0x1010209
     field public static final int stretchColumns = 16843081; // 0x1010149
     field public static final int stretchMode = 16843030; // 0x1010116
-    field public static final int stroke = 16843811; // 0x1010423
-    field public static final int strokeLineCap = 16843820; // 0x101042c
-    field public static final int strokeLineJoin = 16843821; // 0x101042d
-    field public static final int strokeOpacity = 16843812; // 0x1010424
-    field public static final int strokeWidth = 16843813; // 0x1010425
+    field public static final int stroke = 16843810; // 0x1010422
+    field public static final int strokeLineCap = 16843816; // 0x1010428
+    field public static final int strokeLineJoin = 16843817; // 0x1010429
+    field public static final int strokeOpacity = 16843811; // 0x1010423
+    field public static final int strokeWidth = 16843812; // 0x1010424
     field public static final int subtitle = 16843473; // 0x10102d1
-    field public static final int subtitleTextAppearance = 16843835; // 0x101043b
+    field public static final int subtitleTextAppearance = 16843827; // 0x1010433
     field public static final int subtitleTextStyle = 16843513; // 0x10102f9
     field public static final int subtypeExtraValue = 16843674; // 0x101039a
     field public static final int subtypeId = 16843713; // 0x10103c1
@@ -1108,7 +1110,7 @@
     field public static final int switchMinWidth = 16843632; // 0x1010370
     field public static final int switchPadding = 16843633; // 0x1010371
     field public static final int switchPreferenceStyle = 16843629; // 0x101036d
-    field public static final int switchStyle = 16843851; // 0x101044b
+    field public static final int switchStyle = 16843844; // 0x1010444
     field public static final int switchTextAppearance = 16843630; // 0x101036e
     field public static final int switchTextOff = 16843628; // 0x101036c
     field public static final int switchTextOn = 16843627; // 0x101036b
@@ -1124,6 +1126,7 @@
     field public static final int targetId = 16843740; // 0x10103dc
     field public static final int targetPackage = 16842785; // 0x1010021
     field public static final int targetSdkVersion = 16843376; // 0x1010270
+    field public static final int targetViewName = 16843857; // 0x1010451
     field public static final int taskAffinity = 16842770; // 0x1010012
     field public static final int taskCloseEnterAnimation = 16842942; // 0x10100be
     field public static final int taskCloseExitAnimation = 16842943; // 0x10100bf
@@ -1145,7 +1148,7 @@
     field public static final int textAppearanceLargeInverse = 16842819; // 0x1010043
     field public static final int textAppearanceLargePopupMenu = 16843521; // 0x1010301
     field public static final int textAppearanceListItem = 16843678; // 0x101039e
-    field public static final int textAppearanceListItemSecondary = 16843838; // 0x101043e
+    field public static final int textAppearanceListItemSecondary = 16843830; // 0x1010436
     field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f
     field public static final int textAppearanceMedium = 16842817; // 0x1010041
     field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
@@ -1209,10 +1212,11 @@
     field public static final int tintMode = 16843798; // 0x1010416
     field public static final int title = 16843233; // 0x10101e1
     field public static final int titleCondensed = 16843234; // 0x10101e2
-    field public static final int titleTextAppearance = 16843834; // 0x101043a
+    field public static final int titleTextAppearance = 16843826; // 0x1010432
     field public static final int titleTextStyle = 16843512; // 0x10102f8
     field public static final int toAlpha = 16843211; // 0x10101cb
     field public static final int toDegrees = 16843188; // 0x10101b4
+    field public static final int toId = 16843853; // 0x101044d
     field public static final int toScene = 16843742; // 0x10103de
     field public static final int toXDelta = 16843207; // 0x10101c7
     field public static final int toXScale = 16843203; // 0x10101c3
@@ -1234,10 +1238,9 @@
     field public static final int translationX = 16843554; // 0x1010322
     field public static final int translationY = 16843555; // 0x1010323
     field public static final int translationZ = 16843797; // 0x1010415
-    field public static final int trigger = 16843805; // 0x101041d
-    field public static final int trimPathEnd = 16843818; // 0x101042a
-    field public static final int trimPathOffset = 16843819; // 0x101042b
-    field public static final int trimPathStart = 16843817; // 0x1010429
+    field public static final int trimPathEnd = 16843814; // 0x1010426
+    field public static final int trimPathOffset = 16843815; // 0x1010427
+    field public static final int trimPathStart = 16843813; // 0x1010425
     field public static final int type = 16843169; // 0x10101a1
     field public static final int typeface = 16842902; // 0x1010096
     field public static final int uiOptions = 16843672; // 0x1010398
@@ -1262,8 +1265,9 @@
     field public static final int verticalGap = 16843328; // 0x1010240
     field public static final int verticalScrollbarPosition = 16843572; // 0x1010334
     field public static final int verticalSpacing = 16843029; // 0x1010115
-    field public static final int viewportHeight = 16843807; // 0x101041f
-    field public static final int viewportWidth = 16843806; // 0x101041e
+    field public static final int viewName = 16843803; // 0x101041b
+    field public static final int viewportHeight = 16843806; // 0x101041e
+    field public static final int viewportWidth = 16843805; // 0x101041d
     field public static final int visibility = 16842972; // 0x10100dc
     field public static final int visible = 16843156; // 0x1010194
     field public static final int vmSafeMode = 16843448; // 0x10102b8
@@ -1292,8 +1296,8 @@
     field public static final int windowActionBar = 16843469; // 0x10102cd
     field public static final int windowActionBarOverlay = 16843492; // 0x10102e4
     field public static final int windowActionModeOverlay = 16843485; // 0x10102dd
-    field public static final int windowAllowEnterTransitionOverlap = 16843849; // 0x1010449
-    field public static final int windowAllowExitTransitionOverlap = 16843848; // 0x1010448
+    field public static final int windowAllowEnterTransitionOverlap = 16843841; // 0x1010441
+    field public static final int windowAllowExitTransitionOverlap = 16843840; // 0x1010440
     field public static final int windowAnimationStyle = 16842926; // 0x10100ae
     field public static final int windowBackground = 16842836; // 0x1010054
     field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b
@@ -1303,9 +1307,9 @@
     field public static final int windowDisablePreview = 16843298; // 0x1010222
     field public static final int windowEnableSplitTouch = 16843543; // 0x1010317
     field public static final int windowEnterAnimation = 16842932; // 0x10100b4
-    field public static final int windowEnterTransition = 16843844; // 0x1010444
+    field public static final int windowEnterTransition = 16843836; // 0x101043c
     field public static final int windowExitAnimation = 16842933; // 0x10100b5
-    field public static final int windowExitTransition = 16843845; // 0x1010445
+    field public static final int windowExitTransition = 16843837; // 0x101043d
     field public static final int windowFrame = 16842837; // 0x1010055
     field public static final int windowFullscreen = 16843277; // 0x101020d
     field public static final int windowHideAnimation = 16842935; // 0x10100b7
@@ -1316,8 +1320,8 @@
     field public static final int windowNoDisplay = 16843294; // 0x101021e
     field public static final int windowNoTitle = 16842838; // 0x1010056
     field public static final int windowOverscan = 16843727; // 0x10103cf
-    field public static final int windowSharedElementEnterTransition = 16843846; // 0x1010446
-    field public static final int windowSharedElementExitTransition = 16843847; // 0x1010447
+    field public static final int windowSharedElementEnterTransition = 16843838; // 0x101043e
+    field public static final int windowSharedElementExitTransition = 16843839; // 0x101043f
     field public static final int windowShowAnimation = 16842934; // 0x10100b6
     field public static final int windowShowWallpaper = 16843410; // 0x1010292
     field public static final int windowSoftInputMode = 16843307; // 0x101022b
@@ -1623,7 +1627,7 @@
     field public static final int l_resource_pad8 = 16908345; // 0x1020039
     field public static final int l_resource_pad9 = 16908344; // 0x1020038
     field public static final int list = 16908298; // 0x102000a
-    field public static final int mask = 16908354; // 0x1020042
+    field public static final int mask = 16908353; // 0x1020041
     field public static final int message = 16908299; // 0x102000b
     field public static final int paste = 16908322; // 0x1020022
     field public static final int primary = 16908300; // 0x102000c
@@ -1632,8 +1636,7 @@
     field public static final int selectAll = 16908319; // 0x102001f
     field public static final int selectTextMode = 16908333; // 0x102002d
     field public static final int selectedIcon = 16908302; // 0x102000e
-    field public static final int shared_element = 16908355; // 0x1020043
-    field public static final int shared_element_name = 16908353; // 0x1020041
+    field public static final int shared_element = 16908354; // 0x1020042
     field public static final int startSelectingText = 16908328; // 0x1020028
     field public static final int stopSelectingText = 16908329; // 0x1020029
     field public static final int summary = 16908304; // 0x1020010
@@ -1855,52 +1858,52 @@
     field public static final int TextAppearance_Large_Inverse = 16973891; // 0x1030043
     field public static final int TextAppearance_Medium = 16973892; // 0x1030044
     field public static final int TextAppearance_Medium_Inverse = 16973893; // 0x1030045
-    field public static final int TextAppearance_Quantum = 16974346; // 0x103020a
-    field public static final int TextAppearance_Quantum_Body1 = 16974538; // 0x10302ca
-    field public static final int TextAppearance_Quantum_Body2 = 16974537; // 0x10302c9
-    field public static final int TextAppearance_Quantum_Button = 16974541; // 0x10302cd
-    field public static final int TextAppearance_Quantum_Caption = 16974539; // 0x10302cb
-    field public static final int TextAppearance_Quantum_DialogWindowTitle = 16974347; // 0x103020b
-    field public static final int TextAppearance_Quantum_Display1 = 16974533; // 0x10302c5
-    field public static final int TextAppearance_Quantum_Display2 = 16974532; // 0x10302c4
-    field public static final int TextAppearance_Quantum_Display3 = 16974531; // 0x10302c3
-    field public static final int TextAppearance_Quantum_Display4 = 16974530; // 0x10302c2
-    field public static final int TextAppearance_Quantum_Headline = 16974534; // 0x10302c6
-    field public static final int TextAppearance_Quantum_Inverse = 16974348; // 0x103020c
-    field public static final int TextAppearance_Quantum_Large = 16974349; // 0x103020d
-    field public static final int TextAppearance_Quantum_Large_Inverse = 16974350; // 0x103020e
-    field public static final int TextAppearance_Quantum_Medium = 16974351; // 0x103020f
-    field public static final int TextAppearance_Quantum_Medium_Inverse = 16974352; // 0x1030210
-    field public static final int TextAppearance_Quantum_Menu = 16974540; // 0x10302cc
-    field public static final int TextAppearance_Quantum_SearchResult_Subtitle = 16974353; // 0x1030211
-    field public static final int TextAppearance_Quantum_SearchResult_Title = 16974354; // 0x1030212
-    field public static final int TextAppearance_Quantum_Small = 16974355; // 0x1030213
-    field public static final int TextAppearance_Quantum_Small_Inverse = 16974356; // 0x1030214
-    field public static final int TextAppearance_Quantum_Subhead = 16974536; // 0x10302c8
-    field public static final int TextAppearance_Quantum_Title = 16974535; // 0x10302c7
-    field public static final int TextAppearance_Quantum_Widget = 16974358; // 0x1030216
-    field public static final int TextAppearance_Quantum_Widget_ActionBar_Menu = 16974359; // 0x1030217
-    field public static final int TextAppearance_Quantum_Widget_ActionBar_Subtitle = 16974360; // 0x1030218
-    field public static final int TextAppearance_Quantum_Widget_ActionBar_Subtitle_Inverse = 16974361; // 0x1030219
-    field public static final int TextAppearance_Quantum_Widget_ActionBar_Title = 16974362; // 0x103021a
-    field public static final int TextAppearance_Quantum_Widget_ActionBar_Title_Inverse = 16974363; // 0x103021b
-    field public static final int TextAppearance_Quantum_Widget_ActionMode_Subtitle = 16974364; // 0x103021c
-    field public static final int TextAppearance_Quantum_Widget_ActionMode_Subtitle_Inverse = 16974365; // 0x103021d
-    field public static final int TextAppearance_Quantum_Widget_ActionMode_Title = 16974366; // 0x103021e
-    field public static final int TextAppearance_Quantum_Widget_ActionMode_Title_Inverse = 16974367; // 0x103021f
-    field public static final int TextAppearance_Quantum_Widget_Button = 16974368; // 0x1030220
-    field public static final int TextAppearance_Quantum_Widget_DropDownHint = 16974369; // 0x1030221
-    field public static final int TextAppearance_Quantum_Widget_DropDownItem = 16974370; // 0x1030222
-    field public static final int TextAppearance_Quantum_Widget_EditText = 16974371; // 0x1030223
-    field public static final int TextAppearance_Quantum_Widget_IconMenu_Item = 16974372; // 0x1030224
-    field public static final int TextAppearance_Quantum_Widget_PopupMenu = 16974373; // 0x1030225
-    field public static final int TextAppearance_Quantum_Widget_PopupMenu_Large = 16974374; // 0x1030226
-    field public static final int TextAppearance_Quantum_Widget_PopupMenu_Small = 16974375; // 0x1030227
-    field public static final int TextAppearance_Quantum_Widget_TabWidget = 16974376; // 0x1030228
-    field public static final int TextAppearance_Quantum_Widget_TextView = 16974377; // 0x1030229
-    field public static final int TextAppearance_Quantum_Widget_TextView_PopupMenu = 16974378; // 0x103022a
-    field public static final int TextAppearance_Quantum_Widget_TextView_SpinnerItem = 16974379; // 0x103022b
-    field public static final int TextAppearance_Quantum_WindowTitle = 16974357; // 0x1030215
+    field public static final int TextAppearance_Quantum = 16974352; // 0x1030210
+    field public static final int TextAppearance_Quantum_Body1 = 16974544; // 0x10302d0
+    field public static final int TextAppearance_Quantum_Body2 = 16974543; // 0x10302cf
+    field public static final int TextAppearance_Quantum_Button = 16974547; // 0x10302d3
+    field public static final int TextAppearance_Quantum_Caption = 16974545; // 0x10302d1
+    field public static final int TextAppearance_Quantum_DialogWindowTitle = 16974353; // 0x1030211
+    field public static final int TextAppearance_Quantum_Display1 = 16974539; // 0x10302cb
+    field public static final int TextAppearance_Quantum_Display2 = 16974538; // 0x10302ca
+    field public static final int TextAppearance_Quantum_Display3 = 16974537; // 0x10302c9
+    field public static final int TextAppearance_Quantum_Display4 = 16974536; // 0x10302c8
+    field public static final int TextAppearance_Quantum_Headline = 16974540; // 0x10302cc
+    field public static final int TextAppearance_Quantum_Inverse = 16974354; // 0x1030212
+    field public static final int TextAppearance_Quantum_Large = 16974355; // 0x1030213
+    field public static final int TextAppearance_Quantum_Large_Inverse = 16974356; // 0x1030214
+    field public static final int TextAppearance_Quantum_Medium = 16974357; // 0x1030215
+    field public static final int TextAppearance_Quantum_Medium_Inverse = 16974358; // 0x1030216
+    field public static final int TextAppearance_Quantum_Menu = 16974546; // 0x10302d2
+    field public static final int TextAppearance_Quantum_SearchResult_Subtitle = 16974359; // 0x1030217
+    field public static final int TextAppearance_Quantum_SearchResult_Title = 16974360; // 0x1030218
+    field public static final int TextAppearance_Quantum_Small = 16974361; // 0x1030219
+    field public static final int TextAppearance_Quantum_Small_Inverse = 16974362; // 0x103021a
+    field public static final int TextAppearance_Quantum_Subhead = 16974542; // 0x10302ce
+    field public static final int TextAppearance_Quantum_Title = 16974541; // 0x10302cd
+    field public static final int TextAppearance_Quantum_Widget = 16974364; // 0x103021c
+    field public static final int TextAppearance_Quantum_Widget_ActionBar_Menu = 16974365; // 0x103021d
+    field public static final int TextAppearance_Quantum_Widget_ActionBar_Subtitle = 16974366; // 0x103021e
+    field public static final int TextAppearance_Quantum_Widget_ActionBar_Subtitle_Inverse = 16974367; // 0x103021f
+    field public static final int TextAppearance_Quantum_Widget_ActionBar_Title = 16974368; // 0x1030220
+    field public static final int TextAppearance_Quantum_Widget_ActionBar_Title_Inverse = 16974369; // 0x1030221
+    field public static final int TextAppearance_Quantum_Widget_ActionMode_Subtitle = 16974370; // 0x1030222
+    field public static final int TextAppearance_Quantum_Widget_ActionMode_Subtitle_Inverse = 16974371; // 0x1030223
+    field public static final int TextAppearance_Quantum_Widget_ActionMode_Title = 16974372; // 0x1030224
+    field public static final int TextAppearance_Quantum_Widget_ActionMode_Title_Inverse = 16974373; // 0x1030225
+    field public static final int TextAppearance_Quantum_Widget_Button = 16974374; // 0x1030226
+    field public static final int TextAppearance_Quantum_Widget_DropDownHint = 16974375; // 0x1030227
+    field public static final int TextAppearance_Quantum_Widget_DropDownItem = 16974376; // 0x1030228
+    field public static final int TextAppearance_Quantum_Widget_EditText = 16974377; // 0x1030229
+    field public static final int TextAppearance_Quantum_Widget_IconMenu_Item = 16974378; // 0x103022a
+    field public static final int TextAppearance_Quantum_Widget_PopupMenu = 16974379; // 0x103022b
+    field public static final int TextAppearance_Quantum_Widget_PopupMenu_Large = 16974380; // 0x103022c
+    field public static final int TextAppearance_Quantum_Widget_PopupMenu_Small = 16974381; // 0x103022d
+    field public static final int TextAppearance_Quantum_Widget_TabWidget = 16974382; // 0x103022e
+    field public static final int TextAppearance_Quantum_Widget_TextView = 16974383; // 0x103022f
+    field public static final int TextAppearance_Quantum_Widget_TextView_PopupMenu = 16974384; // 0x1030230
+    field public static final int TextAppearance_Quantum_Widget_TextView_SpinnerItem = 16974385; // 0x1030231
+    field public static final int TextAppearance_Quantum_WindowTitle = 16974363; // 0x103021b
     field public static final int TextAppearance_Small = 16973894; // 0x1030046
     field public static final int TextAppearance_Small_Inverse = 16973895; // 0x1030047
     field public static final int TextAppearance_StatusBar_EventContent = 16973927; // 0x1030067
@@ -1995,34 +1998,34 @@
     field public static final int Theme_NoTitleBar_Fullscreen = 16973831; // 0x1030007
     field public static final int Theme_NoTitleBar_OverlayActionModes = 16973930; // 0x103006a
     field public static final int Theme_Panel = 16973913; // 0x1030059
-    field public static final int Theme_Quantum = 16974380; // 0x103022c
-    field public static final int Theme_Quantum_Dialog = 16974381; // 0x103022d
-    field public static final int Theme_Quantum_DialogWhenLarge = 16974385; // 0x1030231
-    field public static final int Theme_Quantum_DialogWhenLarge_NoActionBar = 16974386; // 0x1030232
-    field public static final int Theme_Quantum_Dialog_MinWidth = 16974382; // 0x103022e
-    field public static final int Theme_Quantum_Dialog_NoActionBar = 16974383; // 0x103022f
-    field public static final int Theme_Quantum_Dialog_NoActionBar_MinWidth = 16974384; // 0x1030230
-    field public static final int Theme_Quantum_InputMethod = 16974387; // 0x1030233
-    field public static final int Theme_Quantum_Light = 16974395; // 0x103023b
-    field public static final int Theme_Quantum_Light_DarkActionBar = 16974396; // 0x103023c
-    field public static final int Theme_Quantum_Light_Dialog = 16974397; // 0x103023d
-    field public static final int Theme_Quantum_Light_DialogWhenLarge = 16974401; // 0x1030241
-    field public static final int Theme_Quantum_Light_DialogWhenLarge_NoActionBar = 16974402; // 0x1030242
-    field public static final int Theme_Quantum_Light_Dialog_MinWidth = 16974398; // 0x103023e
-    field public static final int Theme_Quantum_Light_Dialog_NoActionBar = 16974399; // 0x103023f
-    field public static final int Theme_Quantum_Light_Dialog_NoActionBar_MinWidth = 16974400; // 0x1030240
-    field public static final int Theme_Quantum_Light_NoActionBar = 16974403; // 0x1030243
-    field public static final int Theme_Quantum_Light_NoActionBar_Fullscreen = 16974404; // 0x1030244
-    field public static final int Theme_Quantum_Light_NoActionBar_Overscan = 16974405; // 0x1030245
-    field public static final int Theme_Quantum_Light_NoActionBar_TranslucentDecor = 16974406; // 0x1030246
-    field public static final int Theme_Quantum_Light_Panel = 16974407; // 0x1030247
-    field public static final int Theme_Quantum_NoActionBar = 16974388; // 0x1030234
-    field public static final int Theme_Quantum_NoActionBar_Fullscreen = 16974389; // 0x1030235
-    field public static final int Theme_Quantum_NoActionBar_Overscan = 16974390; // 0x1030236
-    field public static final int Theme_Quantum_NoActionBar_TranslucentDecor = 16974391; // 0x1030237
-    field public static final int Theme_Quantum_Panel = 16974392; // 0x1030238
-    field public static final int Theme_Quantum_Wallpaper = 16974393; // 0x1030239
-    field public static final int Theme_Quantum_Wallpaper_NoTitleBar = 16974394; // 0x103023a
+    field public static final int Theme_Quantum = 16974386; // 0x1030232
+    field public static final int Theme_Quantum_Dialog = 16974387; // 0x1030233
+    field public static final int Theme_Quantum_DialogWhenLarge = 16974391; // 0x1030237
+    field public static final int Theme_Quantum_DialogWhenLarge_NoActionBar = 16974392; // 0x1030238
+    field public static final int Theme_Quantum_Dialog_MinWidth = 16974388; // 0x1030234
+    field public static final int Theme_Quantum_Dialog_NoActionBar = 16974389; // 0x1030235
+    field public static final int Theme_Quantum_Dialog_NoActionBar_MinWidth = 16974390; // 0x1030236
+    field public static final int Theme_Quantum_InputMethod = 16974393; // 0x1030239
+    field public static final int Theme_Quantum_Light = 16974401; // 0x1030241
+    field public static final int Theme_Quantum_Light_DarkActionBar = 16974402; // 0x1030242
+    field public static final int Theme_Quantum_Light_Dialog = 16974403; // 0x1030243
+    field public static final int Theme_Quantum_Light_DialogWhenLarge = 16974407; // 0x1030247
+    field public static final int Theme_Quantum_Light_DialogWhenLarge_NoActionBar = 16974408; // 0x1030248
+    field public static final int Theme_Quantum_Light_Dialog_MinWidth = 16974404; // 0x1030244
+    field public static final int Theme_Quantum_Light_Dialog_NoActionBar = 16974405; // 0x1030245
+    field public static final int Theme_Quantum_Light_Dialog_NoActionBar_MinWidth = 16974406; // 0x1030246
+    field public static final int Theme_Quantum_Light_NoActionBar = 16974409; // 0x1030249
+    field public static final int Theme_Quantum_Light_NoActionBar_Fullscreen = 16974410; // 0x103024a
+    field public static final int Theme_Quantum_Light_NoActionBar_Overscan = 16974411; // 0x103024b
+    field public static final int Theme_Quantum_Light_NoActionBar_TranslucentDecor = 16974412; // 0x103024c
+    field public static final int Theme_Quantum_Light_Panel = 16974413; // 0x103024d
+    field public static final int Theme_Quantum_NoActionBar = 16974394; // 0x103023a
+    field public static final int Theme_Quantum_NoActionBar_Fullscreen = 16974395; // 0x103023b
+    field public static final int Theme_Quantum_NoActionBar_Overscan = 16974396; // 0x103023c
+    field public static final int Theme_Quantum_NoActionBar_TranslucentDecor = 16974397; // 0x103023d
+    field public static final int Theme_Quantum_Panel = 16974398; // 0x103023e
+    field public static final int Theme_Quantum_Wallpaper = 16974399; // 0x103023f
+    field public static final int Theme_Quantum_Wallpaper_NoTitleBar = 16974400; // 0x1030240
     field public static final int Theme_Translucent = 16973839; // 0x103000f
     field public static final int Theme_Translucent_NoTitleBar = 16973840; // 0x1030010
     field public static final int Theme_Translucent_NoTitleBar_Fullscreen = 16973841; // 0x1030011
@@ -2079,8 +2082,8 @@
     field public static final int Widget_DeviceDefault_DropDownItem_Spinner = 16974178; // 0x1030162
     field public static final int Widget_DeviceDefault_EditText = 16974154; // 0x103014a
     field public static final int Widget_DeviceDefault_ExpandableListView = 16974155; // 0x103014b
-    field public static final int Widget_DeviceDefault_FastScroll = 16974344; // 0x1030208
-    field public static final int Widget_DeviceDefault_FragmentBreadCrumbs = 16974339; // 0x1030203
+    field public static final int Widget_DeviceDefault_FastScroll = 16974346; // 0x103020a
+    field public static final int Widget_DeviceDefault_FragmentBreadCrumbs = 16974347; // 0x103020b
     field public static final int Widget_DeviceDefault_GridView = 16974156; // 0x103014c
     field public static final int Widget_DeviceDefault_HorizontalScrollView = 16974171; // 0x103015b
     field public static final int Widget_DeviceDefault_ImageButton = 16974157; // 0x103014d
@@ -2114,8 +2117,8 @@
     field public static final int Widget_DeviceDefault_Light_DropDownItem_Spinner = 16974233; // 0x1030199
     field public static final int Widget_DeviceDefault_Light_EditText = 16974206; // 0x103017e
     field public static final int Widget_DeviceDefault_Light_ExpandableListView = 16974207; // 0x103017f
-    field public static final int Widget_DeviceDefault_Light_FastScroll = 16974345; // 0x1030209
-    field public static final int Widget_DeviceDefault_Light_FragmentBreadCrumbs = 16974340; // 0x1030204
+    field public static final int Widget_DeviceDefault_Light_FastScroll = 16974349; // 0x103020d
+    field public static final int Widget_DeviceDefault_Light_FragmentBreadCrumbs = 16974350; // 0x103020e
     field public static final int Widget_DeviceDefault_Light_GridView = 16974208; // 0x1030180
     field public static final int Widget_DeviceDefault_Light_HorizontalScrollView = 16974226; // 0x1030192
     field public static final int Widget_DeviceDefault_Light_ImageButton = 16974209; // 0x1030181
@@ -2139,6 +2142,7 @@
     field public static final int Widget_DeviceDefault_Light_ScrollView = 16974225; // 0x1030191
     field public static final int Widget_DeviceDefault_Light_SeekBar = 16974220; // 0x103018c
     field public static final int Widget_DeviceDefault_Light_Spinner = 16974227; // 0x1030193
+    field public static final int Widget_DeviceDefault_Light_StackView = 16974351; // 0x103020f
     field public static final int Widget_DeviceDefault_Light_Tab = 16974237; // 0x103019d
     field public static final int Widget_DeviceDefault_Light_TabWidget = 16974229; // 0x1030195
     field public static final int Widget_DeviceDefault_Light_TextView = 16974202; // 0x103017a
@@ -2162,6 +2166,7 @@
     field public static final int Widget_DeviceDefault_ScrollView = 16974170; // 0x103015a
     field public static final int Widget_DeviceDefault_SeekBar = 16974165; // 0x1030155
     field public static final int Widget_DeviceDefault_Spinner = 16974172; // 0x103015c
+    field public static final int Widget_DeviceDefault_StackView = 16974348; // 0x103020c
     field public static final int Widget_DeviceDefault_Tab = 16974189; // 0x103016d
     field public static final int Widget_DeviceDefault_TabWidget = 16974174; // 0x103015e
     field public static final int Widget_DeviceDefault_TextView = 16974150; // 0x1030146
@@ -2172,7 +2177,7 @@
     field public static final int Widget_DropDownItem_Spinner = 16973868; // 0x103002c
     field public static final int Widget_EditText = 16973859; // 0x1030023
     field public static final int Widget_ExpandableListView = 16973860; // 0x1030024
-    field public static final int Widget_FastScroll = 16974341; // 0x1030205
+    field public static final int Widget_FastScroll = 16974337; // 0x1030201
     field public static final int Widget_FragmentBreadCrumbs = 16973961; // 0x1030089
     field public static final int Widget_Gallery = 16973877; // 0x1030035
     field public static final int Widget_GridView = 16973874; // 0x1030032
@@ -2204,8 +2209,8 @@
     field public static final int Widget_Holo_DropDownItem_Spinner = 16973995; // 0x10300ab
     field public static final int Widget_Holo_EditText = 16973971; // 0x1030093
     field public static final int Widget_Holo_ExpandableListView = 16973972; // 0x1030094
-    field public static final int Widget_Holo_FastScroll = 16974342; // 0x1030206
-    field public static final int Widget_Holo_FragmentBreadCrumbs = 16974337; // 0x1030201
+    field public static final int Widget_Holo_FastScroll = 16974339; // 0x1030203
+    field public static final int Widget_Holo_FragmentBreadCrumbs = 16974340; // 0x1030204
     field public static final int Widget_Holo_GridView = 16973973; // 0x1030095
     field public static final int Widget_Holo_HorizontalScrollView = 16973988; // 0x10300a4
     field public static final int Widget_Holo_ImageButton = 16973974; // 0x1030096
@@ -2226,7 +2231,7 @@
     field public static final int Widget_Holo_Light_ActionMode_Inverse = 16974119; // 0x1030127
     field public static final int Widget_Holo_Light_AutoCompleteTextView = 16974011; // 0x10300bb
     field public static final int Widget_Holo_Light_Button = 16974006; // 0x10300b6
-    field public static final int Widget_Holo_Light_Button_Borderless = 16974542; // 0x10302ce
+    field public static final int Widget_Holo_Light_Button_Borderless = 16974342; // 0x1030206
     field public static final int Widget_Holo_Light_Button_Borderless_Small = 16974107; // 0x103011b
     field public static final int Widget_Holo_Light_Button_Inset = 16974008; // 0x10300b8
     field public static final int Widget_Holo_Light_Button_Small = 16974007; // 0x10300b7
@@ -2241,7 +2246,7 @@
     field public static final int Widget_Holo_Light_EditText = 16974014; // 0x10300be
     field public static final int Widget_Holo_Light_ExpandableListView = 16974015; // 0x10300bf
     field public static final int Widget_Holo_Light_FastScroll = 16974343; // 0x1030207
-    field public static final int Widget_Holo_Light_FragmentBreadCrumbs = 16974338; // 0x1030202
+    field public static final int Widget_Holo_Light_FragmentBreadCrumbs = 16974344; // 0x1030208
     field public static final int Widget_Holo_Light_GridView = 16974016; // 0x10300c0
     field public static final int Widget_Holo_Light_HorizontalScrollView = 16974034; // 0x10300d2
     field public static final int Widget_Holo_Light_ImageButton = 16974017; // 0x10300c1
@@ -2265,6 +2270,7 @@
     field public static final int Widget_Holo_Light_ScrollView = 16974033; // 0x10300d1
     field public static final int Widget_Holo_Light_SeekBar = 16974028; // 0x10300cc
     field public static final int Widget_Holo_Light_Spinner = 16974035; // 0x10300d3
+    field public static final int Widget_Holo_Light_StackView = 16974345; // 0x1030209
     field public static final int Widget_Holo_Light_Tab = 16974052; // 0x10300e4
     field public static final int Widget_Holo_Light_TabWidget = 16974037; // 0x10300d5
     field public static final int Widget_Holo_Light_TextView = 16974010; // 0x10300ba
@@ -2288,6 +2294,7 @@
     field public static final int Widget_Holo_ScrollView = 16973987; // 0x10300a3
     field public static final int Widget_Holo_SeekBar = 16973982; // 0x103009e
     field public static final int Widget_Holo_Spinner = 16973989; // 0x10300a5
+    field public static final int Widget_Holo_StackView = 16974341; // 0x1030205
     field public static final int Widget_Holo_Tab = 16974051; // 0x10300e3
     field public static final int Widget_Holo_TabWidget = 16973991; // 0x10300a7
     field public static final int Widget_Holo_TextView = 16973967; // 0x103008f
@@ -2311,133 +2318,134 @@
     field public static final int Widget_ProgressBar_Large_Inverse = 16973916; // 0x103005c
     field public static final int Widget_ProgressBar_Small = 16973854; // 0x103001e
     field public static final int Widget_ProgressBar_Small_Inverse = 16973917; // 0x103005d
-    field public static final int Widget_Quantum = 16974408; // 0x1030248
-    field public static final int Widget_Quantum_ActionBar = 16974409; // 0x1030249
-    field public static final int Widget_Quantum_ActionBar_Solid = 16974410; // 0x103024a
-    field public static final int Widget_Quantum_ActionBar_TabBar = 16974411; // 0x103024b
-    field public static final int Widget_Quantum_ActionBar_TabText = 16974412; // 0x103024c
-    field public static final int Widget_Quantum_ActionBar_TabView = 16974413; // 0x103024d
-    field public static final int Widget_Quantum_ActionButton = 16974414; // 0x103024e
-    field public static final int Widget_Quantum_ActionButton_CloseMode = 16974415; // 0x103024f
-    field public static final int Widget_Quantum_ActionButton_Overflow = 16974416; // 0x1030250
-    field public static final int Widget_Quantum_ActionButton_TextButton = 16974417; // 0x1030251
-    field public static final int Widget_Quantum_ActionMode = 16974418; // 0x1030252
-    field public static final int Widget_Quantum_AutoCompleteTextView = 16974419; // 0x1030253
-    field public static final int Widget_Quantum_Button = 16974420; // 0x1030254
-    field public static final int Widget_Quantum_ButtonBar = 16974426; // 0x103025a
-    field public static final int Widget_Quantum_ButtonBar_AlertDialog = 16974427; // 0x103025b
-    field public static final int Widget_Quantum_Button_Borderless = 16974421; // 0x1030255
-    field public static final int Widget_Quantum_Button_Borderless_Small = 16974422; // 0x1030256
-    field public static final int Widget_Quantum_Button_Inset = 16974423; // 0x1030257
-    field public static final int Widget_Quantum_Button_Paper = 16974526; // 0x10302be
-    field public static final int Widget_Quantum_Button_Paper_Color = 16974527; // 0x10302bf
-    field public static final int Widget_Quantum_Button_Small = 16974424; // 0x1030258
-    field public static final int Widget_Quantum_Button_Toggle = 16974425; // 0x1030259
-    field public static final int Widget_Quantum_CalendarView = 16974428; // 0x103025c
-    field public static final int Widget_Quantum_CheckedTextView = 16974429; // 0x103025d
-    field public static final int Widget_Quantum_CompoundButton_CheckBox = 16974430; // 0x103025e
-    field public static final int Widget_Quantum_CompoundButton_RadioButton = 16974431; // 0x103025f
-    field public static final int Widget_Quantum_CompoundButton_Star = 16974432; // 0x1030260
-    field public static final int Widget_Quantum_DatePicker = 16974433; // 0x1030261
-    field public static final int Widget_Quantum_DropDownItem = 16974434; // 0x1030262
-    field public static final int Widget_Quantum_DropDownItem_Spinner = 16974435; // 0x1030263
-    field public static final int Widget_Quantum_EditText = 16974436; // 0x1030264
-    field public static final int Widget_Quantum_ExpandableListView = 16974437; // 0x1030265
-    field public static final int Widget_Quantum_FastScroll = 16974438; // 0x1030266
-    field public static final int Widget_Quantum_FragmentBreadCrumbs = 16974439; // 0x1030267
-    field public static final int Widget_Quantum_GridView = 16974440; // 0x1030268
-    field public static final int Widget_Quantum_HorizontalScrollView = 16974441; // 0x1030269
-    field public static final int Widget_Quantum_ImageButton = 16974442; // 0x103026a
-    field public static final int Widget_Quantum_Light = 16974467; // 0x1030283
-    field public static final int Widget_Quantum_Light_ActionBar = 16974468; // 0x1030284
-    field public static final int Widget_Quantum_Light_ActionBar_Solid = 16974469; // 0x1030285
-    field public static final int Widget_Quantum_Light_ActionBar_TabBar = 16974470; // 0x1030286
-    field public static final int Widget_Quantum_Light_ActionBar_TabText = 16974471; // 0x1030287
-    field public static final int Widget_Quantum_Light_ActionBar_TabView = 16974472; // 0x1030288
-    field public static final int Widget_Quantum_Light_ActionButton = 16974473; // 0x1030289
-    field public static final int Widget_Quantum_Light_ActionButton_CloseMode = 16974474; // 0x103028a
-    field public static final int Widget_Quantum_Light_ActionButton_Overflow = 16974475; // 0x103028b
-    field public static final int Widget_Quantum_Light_ActionMode = 16974476; // 0x103028c
-    field public static final int Widget_Quantum_Light_AutoCompleteTextView = 16974477; // 0x103028d
-    field public static final int Widget_Quantum_Light_Button = 16974478; // 0x103028e
-    field public static final int Widget_Quantum_Light_ButtonBar = 16974483; // 0x1030293
-    field public static final int Widget_Quantum_Light_ButtonBar_AlertDialog = 16974484; // 0x1030294
-    field public static final int Widget_Quantum_Light_Button_Borderless_Small = 16974479; // 0x103028f
-    field public static final int Widget_Quantum_Light_Button_Inset = 16974480; // 0x1030290
-    field public static final int Widget_Quantum_Light_Button_Paper = 16974528; // 0x10302c0
-    field public static final int Widget_Quantum_Light_Button_Paper_Color = 16974529; // 0x10302c1
-    field public static final int Widget_Quantum_Light_Button_Small = 16974481; // 0x1030291
-    field public static final int Widget_Quantum_Light_Button_Toggle = 16974482; // 0x1030292
-    field public static final int Widget_Quantum_Light_CalendarView = 16974485; // 0x1030295
-    field public static final int Widget_Quantum_Light_CheckedTextView = 16974486; // 0x1030296
-    field public static final int Widget_Quantum_Light_CompoundButton_CheckBox = 16974487; // 0x1030297
-    field public static final int Widget_Quantum_Light_CompoundButton_RadioButton = 16974488; // 0x1030298
-    field public static final int Widget_Quantum_Light_CompoundButton_Star = 16974489; // 0x1030299
-    field public static final int Widget_Quantum_Light_DropDownItem = 16974490; // 0x103029a
-    field public static final int Widget_Quantum_Light_DropDownItem_Spinner = 16974491; // 0x103029b
-    field public static final int Widget_Quantum_Light_EditText = 16974492; // 0x103029c
-    field public static final int Widget_Quantum_Light_ExpandableListView = 16974493; // 0x103029d
-    field public static final int Widget_Quantum_Light_FastScroll = 16974494; // 0x103029e
-    field public static final int Widget_Quantum_Light_FragmentBreadCrumbs = 16974495; // 0x103029f
-    field public static final int Widget_Quantum_Light_GridView = 16974496; // 0x10302a0
-    field public static final int Widget_Quantum_Light_HorizontalScrollView = 16974497; // 0x10302a1
-    field public static final int Widget_Quantum_Light_ImageButton = 16974498; // 0x10302a2
-    field public static final int Widget_Quantum_Light_ListPopupWindow = 16974499; // 0x10302a3
-    field public static final int Widget_Quantum_Light_ListView = 16974500; // 0x10302a4
-    field public static final int Widget_Quantum_Light_ListView_DropDown = 16974501; // 0x10302a5
-    field public static final int Widget_Quantum_Light_MediaRouteButton = 16974502; // 0x10302a6
-    field public static final int Widget_Quantum_Light_PopupMenu = 16974503; // 0x10302a7
-    field public static final int Widget_Quantum_Light_PopupWindow = 16974504; // 0x10302a8
-    field public static final int Widget_Quantum_Light_ProgressBar = 16974505; // 0x10302a9
-    field public static final int Widget_Quantum_Light_ProgressBar_Horizontal = 16974506; // 0x10302aa
-    field public static final int Widget_Quantum_Light_ProgressBar_Inverse = 16974507; // 0x10302ab
-    field public static final int Widget_Quantum_Light_ProgressBar_Large = 16974508; // 0x10302ac
-    field public static final int Widget_Quantum_Light_ProgressBar_Large_Inverse = 16974509; // 0x10302ad
-    field public static final int Widget_Quantum_Light_ProgressBar_Small = 16974510; // 0x10302ae
-    field public static final int Widget_Quantum_Light_ProgressBar_Small_Inverse = 16974511; // 0x10302af
-    field public static final int Widget_Quantum_Light_ProgressBar_Small_Title = 16974512; // 0x10302b0
-    field public static final int Widget_Quantum_Light_RatingBar = 16974513; // 0x10302b1
-    field public static final int Widget_Quantum_Light_RatingBar_Indicator = 16974514; // 0x10302b2
-    field public static final int Widget_Quantum_Light_RatingBar_Small = 16974515; // 0x10302b3
-    field public static final int Widget_Quantum_Light_ScrollView = 16974516; // 0x10302b4
-    field public static final int Widget_Quantum_Light_SeekBar = 16974517; // 0x10302b5
-    field public static final int Widget_Quantum_Light_SegmentedButton = 16974518; // 0x10302b6
-    field public static final int Widget_Quantum_Light_Spinner = 16974519; // 0x10302b7
-    field public static final int Widget_Quantum_Light_Tab = 16974520; // 0x10302b8
-    field public static final int Widget_Quantum_Light_TabWidget = 16974521; // 0x10302b9
-    field public static final int Widget_Quantum_Light_TextView = 16974522; // 0x10302ba
-    field public static final int Widget_Quantum_Light_TextView_SpinnerItem = 16974523; // 0x10302bb
-    field public static final int Widget_Quantum_Light_WebTextView = 16974524; // 0x10302bc
-    field public static final int Widget_Quantum_Light_WebView = 16974525; // 0x10302bd
-    field public static final int Widget_Quantum_ListPopupWindow = 16974443; // 0x103026b
-    field public static final int Widget_Quantum_ListView = 16974444; // 0x103026c
-    field public static final int Widget_Quantum_ListView_DropDown = 16974445; // 0x103026d
-    field public static final int Widget_Quantum_MediaRouteButton = 16974446; // 0x103026e
-    field public static final int Widget_Quantum_PopupMenu = 16974447; // 0x103026f
-    field public static final int Widget_Quantum_PopupWindow = 16974448; // 0x1030270
-    field public static final int Widget_Quantum_ProgressBar = 16974449; // 0x1030271
-    field public static final int Widget_Quantum_ProgressBar_Horizontal = 16974450; // 0x1030272
-    field public static final int Widget_Quantum_ProgressBar_Large = 16974451; // 0x1030273
-    field public static final int Widget_Quantum_ProgressBar_Small = 16974452; // 0x1030274
-    field public static final int Widget_Quantum_ProgressBar_Small_Title = 16974453; // 0x1030275
-    field public static final int Widget_Quantum_RatingBar = 16974454; // 0x1030276
-    field public static final int Widget_Quantum_RatingBar_Indicator = 16974455; // 0x1030277
-    field public static final int Widget_Quantum_RatingBar_Small = 16974456; // 0x1030278
-    field public static final int Widget_Quantum_ScrollView = 16974457; // 0x1030279
-    field public static final int Widget_Quantum_SeekBar = 16974458; // 0x103027a
-    field public static final int Widget_Quantum_SegmentedButton = 16974459; // 0x103027b
-    field public static final int Widget_Quantum_Spinner = 16974460; // 0x103027c
-    field public static final int Widget_Quantum_Tab = 16974461; // 0x103027d
-    field public static final int Widget_Quantum_TabWidget = 16974462; // 0x103027e
-    field public static final int Widget_Quantum_TextView = 16974463; // 0x103027f
-    field public static final int Widget_Quantum_TextView_SpinnerItem = 16974464; // 0x1030280
-    field public static final int Widget_Quantum_WebTextView = 16974465; // 0x1030281
-    field public static final int Widget_Quantum_WebView = 16974466; // 0x1030282
+    field public static final int Widget_Quantum = 16974414; // 0x103024e
+    field public static final int Widget_Quantum_ActionBar = 16974415; // 0x103024f
+    field public static final int Widget_Quantum_ActionBar_Solid = 16974416; // 0x1030250
+    field public static final int Widget_Quantum_ActionBar_TabBar = 16974417; // 0x1030251
+    field public static final int Widget_Quantum_ActionBar_TabText = 16974418; // 0x1030252
+    field public static final int Widget_Quantum_ActionBar_TabView = 16974419; // 0x1030253
+    field public static final int Widget_Quantum_ActionButton = 16974420; // 0x1030254
+    field public static final int Widget_Quantum_ActionButton_CloseMode = 16974421; // 0x1030255
+    field public static final int Widget_Quantum_ActionButton_Overflow = 16974422; // 0x1030256
+    field public static final int Widget_Quantum_ActionMode = 16974423; // 0x1030257
+    field public static final int Widget_Quantum_AutoCompleteTextView = 16974424; // 0x1030258
+    field public static final int Widget_Quantum_Button = 16974425; // 0x1030259
+    field public static final int Widget_Quantum_ButtonBar = 16974431; // 0x103025f
+    field public static final int Widget_Quantum_ButtonBar_AlertDialog = 16974432; // 0x1030260
+    field public static final int Widget_Quantum_Button_Borderless = 16974426; // 0x103025a
+    field public static final int Widget_Quantum_Button_Borderless_Small = 16974427; // 0x103025b
+    field public static final int Widget_Quantum_Button_Inset = 16974428; // 0x103025c
+    field public static final int Widget_Quantum_Button_Small = 16974429; // 0x103025d
+    field public static final int Widget_Quantum_Button_Toggle = 16974430; // 0x103025e
+    field public static final int Widget_Quantum_CalendarView = 16974433; // 0x1030261
+    field public static final int Widget_Quantum_CheckedTextView = 16974434; // 0x1030262
+    field public static final int Widget_Quantum_CompoundButton_CheckBox = 16974435; // 0x1030263
+    field public static final int Widget_Quantum_CompoundButton_RadioButton = 16974436; // 0x1030264
+    field public static final int Widget_Quantum_CompoundButton_Star = 16974437; // 0x1030265
+    field public static final int Widget_Quantum_DatePicker = 16974438; // 0x1030266
+    field public static final int Widget_Quantum_DropDownItem = 16974439; // 0x1030267
+    field public static final int Widget_Quantum_DropDownItem_Spinner = 16974440; // 0x1030268
+    field public static final int Widget_Quantum_EditText = 16974441; // 0x1030269
+    field public static final int Widget_Quantum_ExpandableListView = 16974442; // 0x103026a
+    field public static final int Widget_Quantum_FastScroll = 16974443; // 0x103026b
+    field public static final int Widget_Quantum_FragmentBreadCrumbs = 16974444; // 0x103026c
+    field public static final int Widget_Quantum_GridView = 16974445; // 0x103026d
+    field public static final int Widget_Quantum_HorizontalScrollView = 16974446; // 0x103026e
+    field public static final int Widget_Quantum_ImageButton = 16974447; // 0x103026f
+    field public static final int Widget_Quantum_Light = 16974474; // 0x103028a
+    field public static final int Widget_Quantum_Light_ActionBar = 16974475; // 0x103028b
+    field public static final int Widget_Quantum_Light_ActionBar_Solid = 16974476; // 0x103028c
+    field public static final int Widget_Quantum_Light_ActionBar_TabBar = 16974477; // 0x103028d
+    field public static final int Widget_Quantum_Light_ActionBar_TabText = 16974478; // 0x103028e
+    field public static final int Widget_Quantum_Light_ActionBar_TabView = 16974479; // 0x103028f
+    field public static final int Widget_Quantum_Light_ActionButton = 16974480; // 0x1030290
+    field public static final int Widget_Quantum_Light_ActionButton_CloseMode = 16974481; // 0x1030291
+    field public static final int Widget_Quantum_Light_ActionButton_Overflow = 16974482; // 0x1030292
+    field public static final int Widget_Quantum_Light_ActionMode = 16974483; // 0x1030293
+    field public static final int Widget_Quantum_Light_AutoCompleteTextView = 16974484; // 0x1030294
+    field public static final int Widget_Quantum_Light_Button = 16974485; // 0x1030295
+    field public static final int Widget_Quantum_Light_ButtonBar = 16974491; // 0x103029b
+    field public static final int Widget_Quantum_Light_ButtonBar_AlertDialog = 16974492; // 0x103029c
+    field public static final int Widget_Quantum_Light_Button_Borderless = 16974486; // 0x1030296
+    field public static final int Widget_Quantum_Light_Button_Borderless_Small = 16974487; // 0x1030297
+    field public static final int Widget_Quantum_Light_Button_Inset = 16974488; // 0x1030298
+    field public static final int Widget_Quantum_Light_Button_Small = 16974489; // 0x1030299
+    field public static final int Widget_Quantum_Light_Button_Toggle = 16974490; // 0x103029a
+    field public static final int Widget_Quantum_Light_CalendarView = 16974493; // 0x103029d
+    field public static final int Widget_Quantum_Light_CheckedTextView = 16974494; // 0x103029e
+    field public static final int Widget_Quantum_Light_CompoundButton_CheckBox = 16974495; // 0x103029f
+    field public static final int Widget_Quantum_Light_CompoundButton_RadioButton = 16974496; // 0x10302a0
+    field public static final int Widget_Quantum_Light_CompoundButton_Star = 16974497; // 0x10302a1
+    field public static final int Widget_Quantum_Light_DropDownItem = 16974498; // 0x10302a2
+    field public static final int Widget_Quantum_Light_DropDownItem_Spinner = 16974499; // 0x10302a3
+    field public static final int Widget_Quantum_Light_EditText = 16974500; // 0x10302a4
+    field public static final int Widget_Quantum_Light_ExpandableListView = 16974501; // 0x10302a5
+    field public static final int Widget_Quantum_Light_FastScroll = 16974502; // 0x10302a6
+    field public static final int Widget_Quantum_Light_FragmentBreadCrumbs = 16974503; // 0x10302a7
+    field public static final int Widget_Quantum_Light_GridView = 16974504; // 0x10302a8
+    field public static final int Widget_Quantum_Light_HorizontalScrollView = 16974505; // 0x10302a9
+    field public static final int Widget_Quantum_Light_ImageButton = 16974506; // 0x10302aa
+    field public static final int Widget_Quantum_Light_ListPopupWindow = 16974507; // 0x10302ab
+    field public static final int Widget_Quantum_Light_ListView = 16974508; // 0x10302ac
+    field public static final int Widget_Quantum_Light_ListView_DropDown = 16974509; // 0x10302ad
+    field public static final int Widget_Quantum_Light_MediaRouteButton = 16974510; // 0x10302ae
+    field public static final int Widget_Quantum_Light_PopupMenu = 16974511; // 0x10302af
+    field public static final int Widget_Quantum_Light_PopupMenu_Overflow = 16974512; // 0x10302b0
+    field public static final int Widget_Quantum_Light_PopupWindow = 16974513; // 0x10302b1
+    field public static final int Widget_Quantum_Light_ProgressBar = 16974514; // 0x10302b2
+    field public static final int Widget_Quantum_Light_ProgressBar_Horizontal = 16974515; // 0x10302b3
+    field public static final int Widget_Quantum_Light_ProgressBar_Inverse = 16974516; // 0x10302b4
+    field public static final int Widget_Quantum_Light_ProgressBar_Large = 16974517; // 0x10302b5
+    field public static final int Widget_Quantum_Light_ProgressBar_Large_Inverse = 16974518; // 0x10302b6
+    field public static final int Widget_Quantum_Light_ProgressBar_Small = 16974519; // 0x10302b7
+    field public static final int Widget_Quantum_Light_ProgressBar_Small_Inverse = 16974520; // 0x10302b8
+    field public static final int Widget_Quantum_Light_ProgressBar_Small_Title = 16974521; // 0x10302b9
+    field public static final int Widget_Quantum_Light_RatingBar = 16974522; // 0x10302ba
+    field public static final int Widget_Quantum_Light_RatingBar_Indicator = 16974523; // 0x10302bb
+    field public static final int Widget_Quantum_Light_RatingBar_Small = 16974524; // 0x10302bc
+    field public static final int Widget_Quantum_Light_ScrollView = 16974525; // 0x10302bd
+    field public static final int Widget_Quantum_Light_SeekBar = 16974526; // 0x10302be
+    field public static final int Widget_Quantum_Light_SegmentedButton = 16974527; // 0x10302bf
+    field public static final int Widget_Quantum_Light_Spinner = 16974529; // 0x10302c1
+    field public static final int Widget_Quantum_Light_StackView = 16974528; // 0x10302c0
+    field public static final int Widget_Quantum_Light_Tab = 16974530; // 0x10302c2
+    field public static final int Widget_Quantum_Light_TabWidget = 16974531; // 0x10302c3
+    field public static final int Widget_Quantum_Light_TextView = 16974532; // 0x10302c4
+    field public static final int Widget_Quantum_Light_TextView_SpinnerItem = 16974533; // 0x10302c5
+    field public static final int Widget_Quantum_Light_WebTextView = 16974534; // 0x10302c6
+    field public static final int Widget_Quantum_Light_WebView = 16974535; // 0x10302c7
+    field public static final int Widget_Quantum_ListPopupWindow = 16974448; // 0x1030270
+    field public static final int Widget_Quantum_ListView = 16974449; // 0x1030271
+    field public static final int Widget_Quantum_ListView_DropDown = 16974450; // 0x1030272
+    field public static final int Widget_Quantum_MediaRouteButton = 16974451; // 0x1030273
+    field public static final int Widget_Quantum_PopupMenu = 16974452; // 0x1030274
+    field public static final int Widget_Quantum_PopupMenu_Overflow = 16974453; // 0x1030275
+    field public static final int Widget_Quantum_PopupWindow = 16974454; // 0x1030276
+    field public static final int Widget_Quantum_ProgressBar = 16974455; // 0x1030277
+    field public static final int Widget_Quantum_ProgressBar_Horizontal = 16974456; // 0x1030278
+    field public static final int Widget_Quantum_ProgressBar_Large = 16974457; // 0x1030279
+    field public static final int Widget_Quantum_ProgressBar_Small = 16974458; // 0x103027a
+    field public static final int Widget_Quantum_ProgressBar_Small_Title = 16974459; // 0x103027b
+    field public static final int Widget_Quantum_RatingBar = 16974460; // 0x103027c
+    field public static final int Widget_Quantum_RatingBar_Indicator = 16974461; // 0x103027d
+    field public static final int Widget_Quantum_RatingBar_Small = 16974462; // 0x103027e
+    field public static final int Widget_Quantum_ScrollView = 16974463; // 0x103027f
+    field public static final int Widget_Quantum_SeekBar = 16974464; // 0x1030280
+    field public static final int Widget_Quantum_SegmentedButton = 16974465; // 0x1030281
+    field public static final int Widget_Quantum_Spinner = 16974467; // 0x1030283
+    field public static final int Widget_Quantum_StackView = 16974466; // 0x1030282
+    field public static final int Widget_Quantum_Tab = 16974468; // 0x1030284
+    field public static final int Widget_Quantum_TabWidget = 16974469; // 0x1030285
+    field public static final int Widget_Quantum_TextView = 16974470; // 0x1030286
+    field public static final int Widget_Quantum_TextView_SpinnerItem = 16974471; // 0x1030287
+    field public static final int Widget_Quantum_WebTextView = 16974472; // 0x1030288
+    field public static final int Widget_Quantum_WebView = 16974473; // 0x1030289
     field public static final int Widget_RatingBar = 16973857; // 0x1030021
     field public static final int Widget_ScrollView = 16973869; // 0x103002d
     field public static final int Widget_SeekBar = 16973856; // 0x1030020
     field public static final int Widget_Spinner = 16973864; // 0x1030028
     field public static final int Widget_Spinner_DropDown = 16973955; // 0x1030083
+    field public static final int Widget_StackView = 16974338; // 0x1030202
     field public static final int Widget_TabWidget = 16973876; // 0x1030034
     field public static final int Widget_TextView = 16973858; // 0x1030022
     field public static final int Widget_TextView_PopupMenu = 16973865; // 0x1030029
@@ -2778,6 +2786,7 @@
   public class AnimatorInflater {
     ctor public AnimatorInflater();
     method public static android.animation.Animator loadAnimator(android.content.Context, int) throws android.content.res.Resources.NotFoundException;
+    method public static android.animation.StateListAnimator loadStateListAnimator(android.content.Context, int) throws android.content.res.Resources.NotFoundException;
   }
 
   public abstract class AnimatorListenerAdapter implements android.animation.Animator.AnimatorListener android.animation.Animator.AnimatorPauseListener {
@@ -2974,6 +2983,12 @@
     method public android.graphics.Rect evaluate(float, android.graphics.Rect, android.graphics.Rect);
   }
 
+  public class StateListAnimator {
+    ctor public StateListAnimator();
+    method public void addState(int[], android.animation.Animator);
+    method public void jumpToCurrentState();
+  }
+
   public class TimeAnimator extends android.animation.ValueAnimator {
     ctor public TimeAnimator();
     method public void setTimeListener(android.animation.TimeAnimator.TimeListener);
@@ -3064,6 +3079,7 @@
     method public abstract android.view.View getCustomView();
     method public abstract int getDisplayOptions();
     method public abstract int getHeight();
+    method public int getHideOffset();
     method public abstract deprecated int getNavigationItemCount();
     method public abstract deprecated int getNavigationMode();
     method public abstract deprecated int getSelectedNavigationIndex();
@@ -3074,6 +3090,7 @@
     method public android.content.Context getThemedContext();
     method public abstract java.lang.CharSequence getTitle();
     method public abstract void hide();
+    method public boolean isHideOnContentScrollEnabled();
     method public abstract boolean isShowing();
     method public abstract deprecated android.app.ActionBar.Tab newTab();
     method public abstract deprecated void removeAllTabs();
@@ -3092,6 +3109,8 @@
     method public abstract void setDisplayShowHomeEnabled(boolean);
     method public abstract void setDisplayShowTitleEnabled(boolean);
     method public abstract void setDisplayUseLogoEnabled(boolean);
+    method public void setHideOffset(int);
+    method public void setHideOnContentScrollEnabled(boolean);
     method public void setHomeActionContentDescription(java.lang.CharSequence);
     method public void setHomeActionContentDescription(int);
     method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
@@ -3242,6 +3261,7 @@
     method public boolean onContextItemSelected(android.view.MenuItem);
     method public void onContextMenuClosed(android.view.Menu);
     method protected void onCreate(android.os.Bundle);
+    method protected void onCreate(android.os.Bundle, android.os.PersistableBundle);
     method public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo);
     method public java.lang.CharSequence onCreateDescription();
     method protected deprecated android.app.Dialog onCreateDialog(int);
@@ -3272,6 +3292,7 @@
     method public void onPanelClosed(int, android.view.Menu);
     method protected void onPause();
     method protected void onPostCreate(android.os.Bundle);
+    method protected void onPostCreate(android.os.Bundle, android.os.PersistableBundle);
     method protected void onPostResume();
     method protected deprecated void onPrepareDialog(int, android.app.Dialog);
     method protected deprecated void onPrepareDialog(int, android.app.Dialog, android.os.Bundle);
@@ -3281,9 +3302,11 @@
     method public void onProvideAssistData(android.os.Bundle);
     method protected void onRestart();
     method protected void onRestoreInstanceState(android.os.Bundle);
+    method protected void onRestoreInstanceState(android.os.Bundle, android.os.PersistableBundle);
     method protected void onResume();
     method public deprecated java.lang.Object onRetainNonConfigurationInstance();
     method protected void onSaveInstanceState(android.os.Bundle);
+    method protected void onSaveInstanceState(android.os.Bundle, android.os.PersistableBundle);
     method public boolean onSearchRequested();
     method protected void onStart();
     method protected void onStop();
@@ -3294,7 +3317,6 @@
     method public void onUserInteraction();
     method protected void onUserLeaveHint();
     method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
-    method public void onWindowDismissed();
     method public void onWindowFocusChanged(boolean);
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
     method public void openContextMenu(android.view.View);
@@ -3307,7 +3329,6 @@
     method public final boolean requestWindowFeature(int);
     method public final void runOnUiThread(java.lang.Runnable);
     method public void setActionBar(android.widget.Toolbar);
-    method public void setActivityLabelAndIcon(java.lang.CharSequence, android.graphics.Bitmap);
     method public void setActivityTransitionListener(android.app.ActivityOptions.ActivityTransitionListener);
     method public void setContentTransitionManager(android.transition.TransitionManager);
     method public void setContentView(int);
@@ -3325,6 +3346,7 @@
     method public final void setProgressBarIndeterminate(boolean);
     method public final void setProgressBarIndeterminateVisibility(boolean);
     method public final void setProgressBarVisibility(boolean);
+    method public void setRecentsActivityValues(android.app.ActivityManager.RecentsActivityValues);
     method public void setRequestedOrientation(int);
     method public final void setResult(int);
     method public final void setResult(int, android.content.Intent);
@@ -3350,10 +3372,12 @@
     method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
     method public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+    method public void startLockTask();
     method public deprecated void startManagingCursor(android.database.Cursor);
     method public boolean startNextMatchingActivity(android.content.Intent);
     method public boolean startNextMatchingActivity(android.content.Intent, android.os.Bundle);
     method public void startSearch(java.lang.String, boolean, android.os.Bundle, boolean);
+    method public void stopLockTask();
     method public deprecated void stopManagingCursor(android.database.Cursor);
     method public void takeKeyEvents(boolean);
     method public void triggerSearch(java.lang.String, android.os.Bundle);
@@ -3379,6 +3403,7 @@
   public class ActivityManager {
     method public boolean clearApplicationUserData();
     method public void dumpPackageState(java.io.FileDescriptor, java.lang.String);
+    method public java.util.List<android.app.ActivityManager.AppTask> getAppTasks();
     method public android.content.pm.ConfigurationInfo getDeviceConfigurationInfo();
     method public int getLargeMemoryClass();
     method public int getLauncherLargeIconDensity();
@@ -3407,6 +3432,11 @@
     field public static final int RECENT_WITH_EXCLUDED = 1; // 0x1
   }
 
+  public static class ActivityManager.AppTask {
+    method public void finishAndRemoveTask();
+    method public android.app.ActivityManager.RecentTaskInfo getTaskInfo();
+  }
+
   public static class ActivityManager.MemoryInfo implements android.os.Parcelable {
     ctor public ActivityManager.MemoryInfo();
     method public int describeContents();
@@ -3445,8 +3475,7 @@
     method public void readFromParcel(android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
-    field public android.graphics.Bitmap activityIcon;
-    field public java.lang.CharSequence activityLabel;
+    field public android.app.ActivityManager.RecentsActivityValues activityValues;
     field public android.content.Intent baseIntent;
     field public java.lang.CharSequence description;
     field public int id;
@@ -3454,6 +3483,21 @@
     field public int persistentId;
   }
 
+  public static class ActivityManager.RecentsActivityValues implements android.os.Parcelable {
+    ctor public ActivityManager.RecentsActivityValues(android.app.ActivityManager.RecentsActivityValues);
+    ctor public ActivityManager.RecentsActivityValues(java.lang.CharSequence, android.graphics.Bitmap, int);
+    ctor public ActivityManager.RecentsActivityValues(java.lang.CharSequence, android.graphics.Bitmap);
+    ctor public ActivityManager.RecentsActivityValues(java.lang.CharSequence);
+    ctor public ActivityManager.RecentsActivityValues();
+    method public int describeContents();
+    method public void readFromParcel(android.os.Parcel);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public int colorPrimary;
+    field public android.graphics.Bitmap icon;
+    field public java.lang.CharSequence label;
+  }
+
   public static class ActivityManager.RunningAppProcessInfo implements android.os.Parcelable {
     ctor public ActivityManager.RunningAppProcessInfo();
     ctor public ActivityManager.RunningAppProcessInfo(java.lang.String, int, java.lang.String[]);
@@ -3836,7 +3880,6 @@
     method public boolean onTouchEvent(android.view.MotionEvent);
     method public boolean onTrackballEvent(android.view.MotionEvent);
     method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
-    method public void onWindowDismissed();
     method public void onWindowFocusChanged(boolean);
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
     method public void openContextMenu(android.view.View);
@@ -4165,14 +4208,18 @@
     method public android.app.Instrumentation.ActivityMonitor addMonitor(android.content.IntentFilter, android.app.Instrumentation.ActivityResult, boolean);
     method public android.app.Instrumentation.ActivityMonitor addMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean);
     method public void callActivityOnCreate(android.app.Activity, android.os.Bundle);
+    method public void callActivityOnCreate(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
     method public void callActivityOnDestroy(android.app.Activity);
     method public void callActivityOnNewIntent(android.app.Activity, android.content.Intent);
     method public void callActivityOnPause(android.app.Activity);
     method public void callActivityOnPostCreate(android.app.Activity, android.os.Bundle);
+    method public void callActivityOnPostCreate(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
     method public void callActivityOnRestart(android.app.Activity);
     method public void callActivityOnRestoreInstanceState(android.app.Activity, android.os.Bundle);
+    method public void callActivityOnRestoreInstanceState(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
     method public void callActivityOnResume(android.app.Activity);
     method public void callActivityOnSaveInstanceState(android.app.Activity, android.os.Bundle);
+    method public void callActivityOnSaveInstanceState(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
     method public void callActivityOnStart(android.app.Activity);
     method public void callActivityOnStop(android.app.Activity);
     method public void callActivityOnUserLeaving(android.app.Activity);
@@ -4402,6 +4449,7 @@
     field public static final java.lang.String CATEGORY_STATUS = "status";
     field public static final java.lang.String CATEGORY_SYSTEM = "sys";
     field public static final java.lang.String CATEGORY_TRANSPORT = "transport";
+    field public static final int COLOR_DEFAULT = 0; // 0x0
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int DEFAULT_ALL = -1; // 0xffffffff
     field public static final int DEFAULT_LIGHTS = 4; // 0x4
@@ -4447,6 +4495,7 @@
     field public int audioStreamType;
     field public android.widget.RemoteViews bigContentView;
     field public java.lang.String category;
+    field public int color;
     field public android.app.PendingIntent contentIntent;
     field public android.widget.RemoteViews contentView;
     field public int defaults;
@@ -4509,6 +4558,7 @@
     method public deprecated android.app.Notification getNotification();
     method public android.app.Notification.Builder setAutoCancel(boolean);
     method public android.app.Notification.Builder setCategory(java.lang.String);
+    method public android.app.Notification.Builder setColor(int);
     method public android.app.Notification.Builder setContent(android.widget.RemoteViews);
     method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
     method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);
@@ -4805,6 +4855,7 @@
     method public void clearWindowAnimationFrameStats();
     method public boolean clearWindowContentFrameStats(int);
     method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
+    method public android.os.ParcelFileDescriptor executeShellCommand(java.lang.String);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
     method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
@@ -4983,10 +5034,15 @@
   }
 
   public class DevicePolicyManager {
+    method public void addForwardingIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
     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 clearForwardingIntentFilters(android.content.ComponentName);
     method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
     method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
+    method public void enableSystemApp(android.content.ComponentName, java.lang.String);
+    method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
+    method public java.lang.String[] getAccountTypesWithManagementDisabled();
     method public java.util.List<android.content.ComponentName> getActiveAdmins();
     method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
     method public boolean getCameraDisabled(android.content.ComponentName);
@@ -5012,13 +5068,16 @@
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isDeviceOwnerApp(java.lang.String);
+    method public boolean isLockTaskPermitted(android.content.ComponentName);
     method public boolean isProfileOwnerApp(java.lang.String);
     method public void lockNow();
     method public void removeActiveAdmin(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
+    method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
     method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
     method public void setCameraDisabled(android.content.ComponentName, boolean);
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
+    method public void setLockTaskComponents(android.content.ComponentName[]) throws java.lang.SecurityException;
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
@@ -5046,6 +5105,8 @@
     field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
     field public static final java.lang.String EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME = "defaultManagedProfileName";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "deviceAdminPackageName";
+    field public static int FLAG_TO_MANAGED_PROFILE;
+    field public static int FLAG_TO_PRIMARY_USER;
     field public static final int KEYGUARD_DISABLE_FEATURES_ALL = 2147483647; // 0x7fffffff
     field public static final int KEYGUARD_DISABLE_FEATURES_NONE = 0; // 0x0
     field public static final int KEYGUARD_DISABLE_SECURE_CAMERA = 2; // 0x2
@@ -5162,6 +5223,27 @@
 
 }
 
+package android.app.task {
+
+  public class TaskParams implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.os.Bundle getExtras();
+    method public int getTaskId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public abstract class TaskService extends android.app.Service {
+    ctor public TaskService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract void onStartTask(android.app.task.TaskParams);
+    method public abstract boolean onStopTask(android.app.task.TaskParams);
+    method public final void taskFinished(android.app.task.TaskParams, boolean);
+    field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_TASK_SERVICE";
+  }
+
+}
+
 package android.appwidget {
 
   public class AppWidgetHost {
@@ -5261,6 +5343,7 @@
     field public static final int RESIZE_VERTICAL = 2; // 0x2
     field public static final int WIDGET_CATEGORY_HOME_SCREEN = 1; // 0x1
     field public static final int WIDGET_CATEGORY_KEYGUARD = 2; // 0x2
+    field public static final int WIDGET_CATEGORY_RECENTS = 4; // 0x4
     field public int autoAdvanceViewId;
     field public android.content.ComponentName configure;
     field public int icon;
@@ -6564,6 +6647,7 @@
     field public static final java.lang.String DISPLAY_SERVICE = "display";
     field public static final java.lang.String DOWNLOAD_SERVICE = "download";
     field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
+    field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
     field public static final java.lang.String HDMI_CEC_SERVICE = "hdmi_cec";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
     field public static final java.lang.String INPUT_SERVICE = "input";
@@ -7099,6 +7183,7 @@
     field public static final int FILL_IN_PACKAGE = 16; // 0x10
     field public static final int FILL_IN_SELECTOR = 64; // 0x40
     field public static final int FILL_IN_SOURCE_BOUNDS = 32; // 0x20
+    field public static final int FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000
     field public static final int FLAG_ACTIVITY_BROUGHT_TO_FRONT = 4194304; // 0x400000
     field public static final int FLAG_ACTIVITY_CLEAR_TASK = 32768; // 0x8000
     field public static final int FLAG_ACTIVITY_CLEAR_TOP = 67108864; // 0x4000000
@@ -7524,6 +7609,55 @@
     method public abstract void onStatusChanged(int);
   }
 
+  public class Task implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getBackoffPolicy();
+    method public android.os.Bundle getExtras();
+    method public long getInitialBackoffMillis();
+    method public long getIntervalMillis();
+    method public long getMaxExecutionDelayMillis();
+    method public long getMinLatencyMillis();
+    method public int getNetworkCapabilities();
+    method public android.content.ComponentName getService();
+    method public int getTaskId();
+    method public boolean isPeriodic();
+    method public boolean isRequireCharging();
+    method public boolean isRequireDeviceIdle();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public static abstract interface Task.BackoffPolicy {
+    field public static final int EXPONENTIAL = 1; // 0x1
+    field public static final int LINEAR = 0; // 0x0
+  }
+
+  public final class Task.Builder {
+    ctor public Task.Builder(int, android.content.ComponentName);
+    method public android.content.Task build();
+    method public android.content.Task.Builder setBackoffCriteria(long, int);
+    method public android.content.Task.Builder setExtras(android.os.Bundle);
+    method public android.content.Task.Builder setMinimumLatency(long);
+    method public android.content.Task.Builder setOverrideDeadline(long);
+    method public android.content.Task.Builder setPeriodic(long);
+    method public android.content.Task.Builder setRequiredNetworkCapabilities(int);
+    method public android.content.Task.Builder setRequiresCharging(boolean);
+    method public android.content.Task.Builder setRequiresDeviceIdle(boolean);
+  }
+
+  public static abstract interface Task.NetworkType {
+    field public static final int ANY = 0; // 0x0
+    field public static final int UNMETERED = 1; // 0x1
+  }
+
+  public abstract class TaskManager {
+    ctor public TaskManager();
+    method public abstract void cancel(int);
+    method public abstract void cancelAll();
+    method public abstract java.util.List<android.content.Task> getAllPendingTasks();
+    method public abstract int schedule(android.content.Task);
+  }
+
   public class UriMatcher {
     ctor public UriMatcher(int);
     method public void addURI(java.lang.String, java.lang.String, int);
@@ -7568,8 +7702,12 @@
     field public static final int CONFIG_TOUCHSCREEN = 8; // 0x8
     field public static final int CONFIG_UI_MODE = 512; // 0x200
     field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int DOCUMENT_LAUNCH_ALWAYS = 2; // 0x2
+    field public static final int DOCUMENT_LAUNCH_INTO_EXISTING = 1; // 0x1
+    field public static final int DOCUMENT_LAUNCH_NONE = 0; // 0x0
     field public static final int FLAG_ALLOW_TASK_REPARENTING = 64; // 0x40
     field public static final int FLAG_ALWAYS_RETAIN_TASK_STATE = 8; // 0x8
+    field public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000
     field public static final int FLAG_CLEAR_TASK_ON_LAUNCH = 4; // 0x4
     field public static final int FLAG_EXCLUDE_FROM_RECENTS = 32; // 0x20
     field public static final int FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS = 256; // 0x100
@@ -7578,6 +7716,7 @@
     field public static final int FLAG_IMMERSIVE = 2048; // 0x800
     field public static final int FLAG_MULTIPROCESS = 1; // 0x1
     field public static final int FLAG_NO_HISTORY = 128; // 0x80
+    field public static final int FLAG_PERSISTABLE = 4096; // 0x1000
     field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
     field public static final int FLAG_STATE_NOT_NEEDED = 16; // 0x10
     field public static final int LAUNCH_MULTIPLE = 0; // 0x0
@@ -7602,6 +7741,7 @@
     field public static final int SCREEN_ORIENTATION_USER_PORTRAIT = 12; // 0xc
     field public static final int UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW = 1; // 0x1
     field public int configChanges;
+    field public int documentLaunchMode;
     field public int flags;
     field public int launchMode;
     field public java.lang.String parentActivityName;
@@ -7762,6 +7902,8 @@
   public class LauncherApps {
     method public synchronized void addOnAppsChangedListener(android.content.pm.LauncherApps.OnAppsChangedListener);
     method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
+    method public boolean isActivityEnabledForProfile(android.content.ComponentName, android.os.UserHandle);
+    method public boolean isPackageEnabledForProfile(java.lang.String, android.os.UserHandle);
     method public synchronized void removeOnAppsChangedListener(android.content.pm.LauncherApps.OnAppsChangedListener);
     method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
     method public void startActivityForProfile(android.content.ComponentName, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
@@ -7925,6 +8067,7 @@
     field public static final java.lang.String FEATURE_CAMERA = "android.hardware.camera";
     field public static final java.lang.String FEATURE_CAMERA_ANY = "android.hardware.camera.any";
     field public static final java.lang.String FEATURE_CAMERA_AUTOFOCUS = "android.hardware.camera.autofocus";
+    field public static final java.lang.String FEATURE_CAMERA_EXTERNAL = "android.hardware.camera.external";
     field public static final java.lang.String FEATURE_CAMERA_FLASH = "android.hardware.camera.flash";
     field public static final java.lang.String FEATURE_CAMERA_FRONT = "android.hardware.camera.front";
     field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
@@ -7950,6 +8093,7 @@
     field public static final java.lang.String FEATURE_SENSOR_BAROMETER = "android.hardware.sensor.barometer";
     field public static final java.lang.String FEATURE_SENSOR_COMPASS = "android.hardware.sensor.compass";
     field public static final java.lang.String FEATURE_SENSOR_GYROSCOPE = "android.hardware.sensor.gyroscope";
+    field public static final java.lang.String FEATURE_SENSOR_HEART_RATE = "android.hardware.sensor.heartrate";
     field public static final java.lang.String FEATURE_SENSOR_LIGHT = "android.hardware.sensor.light";
     field public static final java.lang.String FEATURE_SENSOR_PROXIMITY = "android.hardware.sensor.proximity";
     field public static final java.lang.String FEATURE_SENSOR_STEP_COUNTER = "android.hardware.sensor.stepcounter";
@@ -10633,6 +10777,7 @@
     method public void releaseTexImage();
     method public void setDefaultBufferSize(int, int);
     method public void setOnFrameAvailableListener(android.graphics.SurfaceTexture.OnFrameAvailableListener);
+    method public void setOnFrameAvailableListener(android.graphics.SurfaceTexture.OnFrameAvailableListener, android.os.Handler);
     method public void updateTexImage();
   }
 
@@ -10695,6 +10840,12 @@
     method public abstract void stop();
   }
 
+  public class AnimatedStateListDrawable extends android.graphics.drawable.StateListDrawable {
+    ctor public AnimatedStateListDrawable();
+    method public void addState(int[], android.graphics.drawable.Drawable, int);
+    method public void addTransition(int, int, android.graphics.drawable.AnimationDrawable, boolean);
+  }
+
   public class AnimationDrawable extends android.graphics.drawable.DrawableContainer implements android.graphics.drawable.Animatable java.lang.Runnable {
     ctor public AnimationDrawable();
     method public void addFrame(android.graphics.drawable.Drawable, int);
@@ -11128,19 +11279,11 @@
   public class VectorDrawable extends android.graphics.drawable.Drawable {
     ctor public VectorDrawable();
     method public void draw(android.graphics.Canvas);
-    method public float geAnimationFraction();
     method public int getOpacity();
-    method public int getRepeatCount();
     method public void setAlpha(int);
-    method public void setAnimationFraction(float);
     method public void setColorFilter(android.graphics.ColorFilter);
-    method public void setDuration(long);
     method public void setPadding(android.graphics.Rect);
     method public void setPadding(int, int, int, int);
-    method public void setRepeatCount(int);
-    method public void setRepeatMode(int);
-    method public void start();
-    method public void stop();
   }
 
 }
@@ -11745,7 +11888,6 @@
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_WHITE_LEVEL;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_MAX_ANALOG_SENSITIVITY;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_ORIENTATION;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_REFERENCE_ILLUMINANT1;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_REFERENCE_ILLUMINANT2;
     field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
@@ -11903,6 +12045,8 @@
     field public static final int CONTROL_SCENE_MODE_STEADYPHOTO = 11; // 0xb
     field public static final int CONTROL_SCENE_MODE_SUNSET = 10; // 0xa
     field public static final int CONTROL_SCENE_MODE_THEATRE = 7; // 0x7
+    field public static final int CONTROL_VIDEO_STABILIZATION_MODE_OFF = 0; // 0x0
+    field public static final int CONTROL_VIDEO_STABILIZATION_MODE_ON = 1; // 0x1
     field public static final int EDGE_MODE_FAST = 1; // 0x1
     field public static final int EDGE_MODE_HIGH_QUALITY = 2; // 0x2
     field public static final int EDGE_MODE_OFF = 0; // 0x0
@@ -12076,17 +12220,29 @@
     method public int getSequenceId();
     field public static final android.hardware.camera2.CameraMetadata.Key BLACK_LEVEL_LOCK;
     field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_GAINS;
+    field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_MODE;
     field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_TRANSFORM;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_ANTIBANDING_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_EXPOSURE_COMPENSATION;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_LOCK;
     field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_PRECAPTURE_TRIGGER;
     field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_REGIONS;
     field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_STATE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_TARGET_FPS_RANGE;
     field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_MODE;
     field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_REGIONS;
     field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_STATE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_TRIGGER;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_LOCK;
     field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_MODE;
     field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_REGIONS;
     field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_STATE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_CAPTURE_INTENT;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_EFFECT_MODE;
     field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_SCENE_MODE;
+    field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_VIDEO_STABILIZATION_MODE;
     field public static final android.hardware.camera2.CameraMetadata.Key EDGE_MODE;
     field public static final android.hardware.camera2.CameraMetadata.Key FLASH_MODE;
     field public static final android.hardware.camera2.CameraMetadata.Key FLASH_STATE;
@@ -12113,10 +12269,9 @@
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FRAME_DURATION;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_GREEN_SPLIT;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_NEUTRAL_COLOR_POINT;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_HUE_SAT_MAP;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_TONE_CURVE;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_SENSITIVITY;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEMPERATURE;
+    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEST_PATTERN_DATA;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEST_PATTERN_MODE;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TIMESTAMP;
     field public static final android.hardware.camera2.CameraMetadata.Key SHADING_MODE;
@@ -12125,6 +12280,7 @@
     field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_HOT_PIXEL_MAP;
     field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_HOT_PIXEL_MAP_MODE;
     field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_LENS_SHADING_MAP;
+    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_LENS_SHADING_MAP_MODE;
     field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_SCENE_FLICKER;
     field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_BLUE;
     field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_GREEN;
@@ -12132,6 +12288,14 @@
     field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MODE;
   }
 
+  public final class ColorSpaceTransform {
+    ctor public ColorSpaceTransform(android.hardware.camera2.Rational[]);
+    ctor public ColorSpaceTransform(int[]);
+    method public void copyElements(android.hardware.camera2.Rational[], int);
+    method public void copyElements(int[], int);
+    method public android.hardware.camera2.Rational getElement(int, int);
+  }
+
   public final class Face {
     method public android.graphics.Rect getBounds();
     method public int getId();
@@ -12144,18 +12308,83 @@
     field public static final int SCORE_MIN = 1; // 0x1
   }
 
+  public final class LensShadingMap {
+    method public void copyGainFactors(float[], int);
+    method public int getColumnCount();
+    method public float getGainFactor(int, int, int);
+    method public int getGainFactorCount();
+    method public android.hardware.camera2.RggbChannelVector getGainFactorVector(int, int);
+    method public int getRowCount();
+    field public static final float MINIMUM_GAIN_FACTOR = 1.0f;
+  }
+
+  public final class MeteringRectangle {
+    ctor public MeteringRectangle(int, int, int, int, int);
+    ctor public MeteringRectangle(android.graphics.Point, android.util.Size, int);
+    ctor public MeteringRectangle(android.graphics.Rect, int);
+    method public boolean equals(android.hardware.camera2.MeteringRectangle);
+    method public int getHeight();
+    method public int getMeteringWeight();
+    method public android.graphics.Rect getRect();
+    method public android.util.Size getSize();
+    method public android.graphics.Point getUpperLeftPoint();
+    method public int getWidth();
+    method public int getX();
+    method public int getY();
+  }
+
   public final class Rational {
     ctor public Rational(int, int);
     method public int getDenominator();
     method public int getNumerator();
   }
 
+  public final class RggbChannelVector {
+    ctor public RggbChannelVector(float, float, float, float);
+    method public void copyTo(float[], int);
+    method public float getBlue();
+    method public float getComponent(int);
+    method public float getGreenEven();
+    method public float getGreenOdd();
+    method public final float getRed();
+    field public static final int BLUE = 3; // 0x3
+    field public static final int COUNT = 4; // 0x4
+    field public static final int GREEN_EVEN = 1; // 0x1
+    field public static final int GREEN_ODD = 2; // 0x2
+    field public static final int RED = 0; // 0x0
+  }
+
   public final class Size {
     ctor public Size(int, int);
     method public final int getHeight();
     method public final int getWidth();
   }
 
+  public final class StreamConfigurationMap {
+    method public final int[] getOutputFormats();
+    method public long getOutputMinFrameDuration(int, android.util.Size);
+    method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
+    method public android.util.Size[] getOutputSizes(java.lang.Class<T>);
+    method public android.util.Size[] getOutputSizes(int);
+    method public long getOutputStallDuration(int, android.util.Size);
+    method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
+    method public boolean isOutputSupportedFor(int);
+    method public static boolean isOutputSupportedFor(java.lang.Class<T>);
+    method public boolean isOutputSupportedFor(android.view.Surface);
+  }
+
+  public final class TonemapCurve {
+    method public void copyColorCurve(int, float[], int);
+    method public android.graphics.PointF getPoint(int, int);
+    method public int getPointCount(int);
+    field public static final int CHANNEL_BLUE = 2; // 0x2
+    field public static final int CHANNEL_GREEN = 1; // 0x1
+    field public static final int CHANNEL_RED = 0; // 0x0
+    field public static final float LEVEL_BLACK = 0.0f;
+    field public static final float LEVEL_WHITE = 1.0f;
+    field public static final int POINT_SIZE = 2; // 0x2
+  }
+
 }
 
 package android.hardware.display {
@@ -12198,7 +12427,6 @@
     method public static boolean isValidType(int);
     field public static final int ADDR_AUDIO_SYSTEM = 5; // 0x5
     field public static final int ADDR_BROADCAST = 15; // 0xf
-    field public static final int ADDR_FREE_USE = 14; // 0xe
     field public static final int ADDR_INVALID = -1; // 0xffffffff
     field public static final int ADDR_PLAYBACK_1 = 4; // 0x4
     field public static final int ADDR_PLAYBACK_2 = 8; // 0x8
@@ -12208,6 +12436,7 @@
     field public static final int ADDR_RECORDER_3 = 9; // 0x9
     field public static final int ADDR_RESERVED_1 = 12; // 0xc
     field public static final int ADDR_RESERVED_2 = 13; // 0xd
+    field public static final int ADDR_SPECIFIC_USE = 14; // 0xe
     field public static final int ADDR_TUNER_1 = 3; // 0x3
     field public static final int ADDR_TUNER_2 = 6; // 0x6
     field public static final int ADDR_TUNER_3 = 7; // 0x7
@@ -12288,6 +12517,7 @@
     field public static final int POWER_STATUS_UNKNOWN = -1; // 0xffffffff
     field public static final int POWER_TRANSIENT_TO_ON = 2; // 0x2
     field public static final int POWER_TRANSIENT_TO_STANDBY = 3; // 0x3
+    field public static final int UNKNOWN_VENDOR_ID = 16777215; // 0xffffff
   }
 
   public final class HdmiCecClient {
@@ -12305,6 +12535,17 @@
     method public void onMessageReceived(android.hardware.hdmi.HdmiCecMessage);
   }
 
+  public final class HdmiCecDeviceInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getDeviceType();
+    method public java.lang.String getDisplayName();
+    method public int getLogicalAddress();
+    method public int getPhysicalAddress();
+    method public int getVendorId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
   public final class HdmiCecManager {
     method public android.hardware.hdmi.HdmiCecClient getClient(int, android.hardware.hdmi.HdmiCecClient.Listener);
   }
@@ -12318,6 +12559,7 @@
     method public int getSource();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final byte[] EMPTY_PARAM;
   }
 
 }
@@ -12652,6 +12894,7 @@
     method public void onStartInputView(android.view.inputmethod.EditorInfo, boolean);
     method public void onUnbindInput();
     method public void onUpdateCursor(android.graphics.Rect);
+    method public void onUpdateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo);
     method public void onUpdateExtractedText(int, android.view.inputmethod.ExtractedText);
     method public void onUpdateExtractingViews(android.view.inputmethod.EditorInfo);
     method public void onUpdateExtractingVisibility(android.view.inputmethod.EditorInfo);
@@ -12701,6 +12944,7 @@
     method public void finishInput();
     method public void toggleSoftInput(int, int);
     method public void updateCursor(android.graphics.Rect);
+    method public void updateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo);
     method public void updateExtractedText(int, android.view.inputmethod.ExtractedText);
     method public void updateSelection(int, int, int, int, int, int);
     method public void viewClicked(boolean);
@@ -13102,6 +13346,45 @@
     method public void stop();
   }
 
+  public final class AudioAttributes {
+    method public int getContentType();
+    method public int getFlags();
+    method public java.util.Set<java.lang.String> getTags();
+    method public int getUsage();
+    field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
+    field public static final int CONTENT_TYPE_MUSIC = 2; // 0x2
+    field public static final int CONTENT_TYPE_SONIFICATION = 4; // 0x4
+    field public static final int CONTENT_TYPE_SPEECH = 1; // 0x1
+    field public static final int CONTENT_TYPE_UNKNOWN = 0; // 0x0
+    field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
+    field public static final int USAGE_ALARM = 4; // 0x4
+    field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
+    field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
+    field public static final int USAGE_ASSISTANCE_SONIFICATION = 13; // 0xd
+    field public static final int USAGE_GAME = 14; // 0xe
+    field public static final int USAGE_MEDIA = 1; // 0x1
+    field public static final int USAGE_NOTIFICATION = 5; // 0x5
+    field public static final int USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9; // 0x9
+    field public static final int USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8; // 0x8
+    field public static final int USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7; // 0x7
+    field public static final int USAGE_NOTIFICATION_EVENT = 10; // 0xa
+    field public static final int USAGE_NOTIFICATION_TELEPHONY_RINGTONE = 6; // 0x6
+    field public static final int USAGE_UNKNOWN = 0; // 0x0
+    field public static final int USAGE_VOICE_COMMUNICATION = 2; // 0x2
+    field public static final int USAGE_VOICE_COMMUNICATION_SIGNALLING = 3; // 0x3
+  }
+
+  public static class AudioAttributes.Builder {
+    ctor public AudioAttributes.Builder();
+    ctor public AudioAttributes.Builder(android.media.AudioAttributes);
+    method public android.media.AudioAttributes.Builder addTag(java.lang.String);
+    method public android.media.AudioAttributes build();
+    method public android.media.AudioAttributes.Builder setContentType(int);
+    method public android.media.AudioAttributes.Builder setFlags(int);
+    method public android.media.AudioAttributes.Builder setLegacyStreamType(int);
+    method public android.media.AudioAttributes.Builder setUsage(int);
+  }
+
   public class AudioFormat {
     ctor public AudioFormat();
     field public static final deprecated int CHANNEL_CONFIGURATION_DEFAULT = 1; // 0x1
@@ -13146,6 +13429,7 @@
     field public static final int ENCODING_INVALID = 0; // 0x0
     field public static final int ENCODING_PCM_16BIT = 2; // 0x2
     field public static final int ENCODING_PCM_8BIT = 3; // 0x3
+    field public static final int ENCODING_PCM_FLOAT = 4; // 0x4
   }
 
   public class AudioManager {
@@ -13363,6 +13647,8 @@
     method public void stop() throws java.lang.IllegalStateException;
     method public int write(byte[], int, int);
     method public int write(short[], int, int);
+    method public int write(float[], int, int, int);
+    method public int write(java.nio.ByteBuffer, int, int);
     field public static final int ERROR = -1; // 0xffffffff
     field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe
     field public static final int ERROR_INVALID_OPERATION = -3; // 0xfffffffd
@@ -13375,6 +13661,8 @@
     field public static final int STATE_NO_STATIC_DATA = 2; // 0x2
     field public static final int STATE_UNINITIALIZED = 0; // 0x0
     field public static final int SUCCESS = 0; // 0x0
+    field public static final int WRITE_BLOCKING = 0; // 0x0
+    field public static final int WRITE_NON_BLOCKING = 1; // 0x1
   }
 
   public static abstract interface AudioTrack.OnPlaybackPositionUpdateListener {
@@ -13592,6 +13880,7 @@
     method public final void queueSecureInputBuffer(int, int, android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
     method public final void release();
     method public final void releaseOutputBuffer(int, boolean);
+    method public final void releaseOutputBuffer(int, long);
     method public void setNotificationCallback(android.media.MediaCodec.NotificationCallback);
     method public final void setParameters(android.os.Bundle);
     method public final void setVideoScalingMode(int);
@@ -15097,11 +15386,13 @@
 package android.media.session {
 
   public final class MediaMetadata implements android.os.Parcelable {
+    method public boolean containsKey(java.lang.String);
     method public int describeContents();
     method public android.graphics.Bitmap getBitmap(java.lang.String);
     method public long getLong(java.lang.String);
     method public android.media.Rating getRating(java.lang.String);
     method public java.lang.String getString(java.lang.String);
+    method public int size();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final java.lang.String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
@@ -15112,6 +15403,7 @@
     field public static final java.lang.String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
     field public static final java.lang.String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
     field public static final java.lang.String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
+    field public static final java.lang.String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
     field public static final java.lang.String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
     field public static final java.lang.String METADATA_KEY_DATE = "android.media.metadata.DATE";
     field public static final java.lang.String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
@@ -15144,25 +15436,25 @@
     method public long getBufferPosition();
     method public java.lang.String getErrorMessage();
     method public long getPosition();
-    method public float getSpeed();
+    method public float getRate();
     method public int getState();
     method public void setActions(long);
     method public void setBufferPosition(long);
     method public void setErrorMessage(java.lang.String);
-    method public void setPosition(long);
-    method public void setSpeed(float);
-    method public void setState(int);
+    method public void setState(int, long, float);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final long ACTION_FASTFORWARD = 64L; // 0x40L
     field public static final long ACTION_NEXT_ITEM = 32L; // 0x20L
     field public static final long ACTION_PAUSE = 2L; // 0x2L
     field public static final long ACTION_PLAY = 4L; // 0x4L
+    field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
     field public static final long ACTION_PREVIOUS_ITEM = 16L; // 0x10L
     field public static final long ACTION_RATING = 128L; // 0x80L
     field public static final long ACTION_REWIND = 8L; // 0x8L
     field public static final long ACTION_SEEK_TO = 256L; // 0x100L
     field public static final long ACTION_STOP = 1L; // 0x1L
     field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
     field public static final int PLAYSTATE_BUFFERING = 6; // 0x6
     field public static final int PLAYSTATE_CONNECTING = 8; // 0x8
     field public static final int PLAYSTATE_ERROR = 7; // 0x7
@@ -15171,6 +15463,8 @@
     field public static final int PLAYSTATE_PAUSED = 2; // 0x2
     field public static final int PLAYSTATE_PLAYING = 3; // 0x3
     field public static final int PLAYSTATE_REWINDING = 5; // 0x5
+    field public static final int PLAYSTATE_SKIPPING_BACKWARDS = 9; // 0x9
+    field public static final int PLAYSTATE_SKIPPING_FORWARDS = 10; // 0xa
     field public static final int PLAYSTATE_STOPPED = 1; // 0x1
   }
 
@@ -15262,12 +15556,15 @@
     method public void disconnect(android.media.session.RouteInfo);
     method public android.media.session.SessionToken getSessionToken();
     method public android.media.session.TransportPerformer getTransportPerformer();
-    method public void publish();
+    method public boolean isActive();
     method public void release();
     method public void removeCallback(android.media.session.Session.Callback);
     method public void sendEvent(java.lang.String, android.os.Bundle);
+    method public void setActive(boolean);
+    method public void setFlags(int);
     method public void setRouteOptions(java.util.List<android.media.session.RouteOptions>);
-    method public android.media.session.TransportPerformer setTransportPerformerEnabled();
+    field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+    field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
 
   public static abstract class Session.Callback {
@@ -15306,7 +15603,7 @@
 
   public final class SessionManager {
     method public android.media.session.Session createSession(java.lang.String);
-    method public java.util.List<android.media.session.SessionController> getActiveSessions();
+    method public java.util.List<android.media.session.SessionController> getActiveSessions(android.content.ComponentName);
   }
 
   public class SessionToken implements android.os.Parcelable {
@@ -15496,6 +15793,7 @@
     method public android.net.NetworkInfo getActiveNetworkInfo();
     method public android.net.NetworkInfo[] getAllNetworkInfo();
     method public deprecated boolean getBackgroundDataSetting();
+    method public android.net.ProxyInfo getGlobalProxy();
     method public android.net.NetworkInfo getNetworkInfo(int);
     method public int getNetworkPreference();
     method public boolean isActiveNetworkMetered();
@@ -15503,6 +15801,7 @@
     method public static boolean isNetworkTypeValid(int);
     method public void registerNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
     method public boolean requestRouteToHost(int, int);
+    method public void setGlobalProxy(android.net.ProxyInfo);
     method public void setNetworkPreference(int);
     method public int startUsingNetworkFeature(int, java.lang.String);
     method public int stopUsingNetworkFeature(int, java.lang.String);
@@ -15678,9 +15977,22 @@
     method public static final deprecated int getDefaultPort();
     method public static final deprecated java.lang.String getHost(android.content.Context);
     method public static final deprecated int getPort(android.content.Context);
+    field public static final java.lang.String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
     field public static final java.lang.String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
   }
 
+  public class ProxyInfo implements android.os.Parcelable {
+    method public static android.net.ProxyInfo buildDirectProxy(java.lang.String, int);
+    method public static android.net.ProxyInfo buildDirectProxy(java.lang.String, int, java.util.List<java.lang.String>);
+    method public static android.net.ProxyInfo buildPacProxy(android.net.Uri);
+    method public int describeContents();
+    method public java.lang.String[] getExclusionList();
+    method public java.lang.String getHost();
+    method public android.net.Uri getPacFileUrl();
+    method public int getPort();
+    method public void writeToParcel(android.os.Parcel, int);
+  }
+
   public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
     ctor public deprecated SSLCertificateSocketFactory(int);
     method public java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException;
@@ -16892,6 +17204,7 @@
   }
 
   public final class CardEmulation {
+    method public boolean categoryAllowsForegroundPreference(java.lang.String);
     method public android.nfc.cardemulation.AidGroup getAidGroupForService(android.content.ComponentName, java.lang.String);
     method public static synchronized android.nfc.cardemulation.CardEmulation getInstance(android.nfc.NfcAdapter);
     method public int getSelectionModeForCategory(java.lang.String);
@@ -16899,6 +17212,8 @@
     method public boolean isDefaultServiceForCategory(android.content.ComponentName, java.lang.String);
     method public boolean registerAidGroupForService(android.content.ComponentName, android.nfc.cardemulation.AidGroup);
     method public boolean removeAidGroupForService(android.content.ComponentName, java.lang.String);
+    method public boolean setPreferredService(android.app.Activity, android.content.ComponentName);
+    method public boolean unsetPreferredService(android.app.Activity);
     field public static final java.lang.String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
     field public static final java.lang.String CATEGORY_OTHER = "other";
     field public static final java.lang.String CATEGORY_PAYMENT = "payment";
@@ -19333,7 +19648,7 @@
     field public static final int JELLY_BEAN_MR1 = 17; // 0x11
     field public static final int JELLY_BEAN_MR2 = 18; // 0x12
     field public static final int KITKAT = 19; // 0x13
-    field public static final int KITKAT_WATCH = 10000; // 0x2710
+    field public static final int KITKAT_WATCH = 20; // 0x14
     field public static final int L = 10000; // 0x2710
   }
 
@@ -20304,16 +20619,28 @@
     method public void setUserRestriction(java.lang.String, boolean);
     method public void setUserRestrictions(android.os.Bundle);
     method public void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
+    field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user";
+    field public static final java.lang.String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
+    field public static final java.lang.String DISALLOW_CONFIG_APPS = "no_config_apps";
     field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
+    field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
     field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
+    field public static final java.lang.String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
+    field public static final java.lang.String DISALLOW_CONFIG_TETHERING = "no_config_tethering";
+    field public static final java.lang.String DISALLOW_CONFIG_VPN = "no_config_vpn";
     field public static final java.lang.String DISALLOW_CONFIG_WIFI = "no_config_wifi";
+    field public static final java.lang.String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features";
+    field public static final java.lang.String DISALLOW_FACTORY_RESET = "no_factory_reset";
     field public static final java.lang.String DISALLOW_INSTALL_APPS = "no_install_apps";
     field public static final java.lang.String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
     field public static final java.lang.String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
+    field public static final java.lang.String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media";
     field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user";
     field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
     field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
+    field public static final java.lang.String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone";
     field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
+    field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
   }
 
   public abstract class Vibrator {
@@ -23176,6 +23503,7 @@
     method public static boolean putLong(android.content.ContentResolver, java.lang.String, long);
     method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String);
     method public static final deprecated void setLocationProviderEnabled(android.content.ContentResolver, java.lang.String, boolean);
+    field public static final java.lang.String ACCESSIBILITY_DISPLAY_INVERSION_ENABLED = "accessibility_display_inversion_enabled";
     field public static final java.lang.String ACCESSIBILITY_ENABLED = "accessibility_enabled";
     field public static final java.lang.String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password";
     field public static final deprecated java.lang.String ADB_ENABLED = "adb_enabled";
@@ -23684,25 +24012,32 @@
   }
 
   public static abstract interface TvContract.BaseTvColumns implements android.provider.BaseColumns {
-    field public static final java.lang.String PACKAGE_NAME = "package_name";
+    field public static final java.lang.String COLUMN_PACKAGE_NAME = "package_name";
   }
 
   public static final class TvContract.Channels implements android.provider.TvContract.BaseTvColumns {
-    field public static final java.lang.String BROWSABLE = "browsable";
+    field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
+    field public static final java.lang.String COLUMN_DATA = "data";
+    field public static final java.lang.String COLUMN_DESCRIPTION = "description";
+    field public static final java.lang.String COLUMN_DISPLAY_NAME = "display_name";
+    field public static final java.lang.String COLUMN_DISPLAY_NUMBER = "display_number";
+    field public static final java.lang.String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
+    field public static final java.lang.String COLUMN_SERVICE_ID = "service_id";
+    field public static final java.lang.String COLUMN_SERVICE_NAME = "service_name";
+    field public static final java.lang.String COLUMN_SERVICE_TYPE = "service_type";
+    field public static final java.lang.String COLUMN_TRANSPORT_STREAM_ID = "transport_stream_id";
+    field public static final java.lang.String COLUMN_TYPE = "type";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.com.android.tv.channels";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.com.android.tv.channels";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DATA = "data";
-    field public static final java.lang.String DESCRIPTION = "description";
-    field public static final java.lang.String DISPLAY_NAME = "display_name";
-    field public static final java.lang.String DISPLAY_NUMBER = "display_number";
-    field public static final java.lang.String SERVICE_NAME = "service_name";
-    field public static final java.lang.String TRANSPORT_STREAM_ID = "transport_stream_id";
-    field public static final java.lang.String TYPE = "type";
+    field public static final int SERVICE_TYPE_OTHER = 0; // 0x0
+    field public static final int SERVICE_TYPE_RADIO = 2; // 0x2
+    field public static final int SERVICE_TYPE_TV = 1; // 0x1
     field public static final int TYPE_1SEG = 263168; // 0x40400
-    field public static final int TYPE_ATSC = 196608; // 0x30000
-    field public static final int TYPE_ATSC_2_0 = 196609; // 0x30001
-    field public static final int TYPE_ATSC_M_H = 196864; // 0x30100
+    field public static final int TYPE_ATSC_C = 197120; // 0x30200
+    field public static final int TYPE_ATSC_M_H = 197120; // 0x30200
+    field public static final int TYPE_ATSC_T = 196608; // 0x30000
     field public static final int TYPE_CMMB = 327936; // 0x50100
     field public static final int TYPE_DTMB = 327680; // 0x50000
     field public static final int TYPE_DVB_C = 131584; // 0x20200
@@ -23721,21 +24056,20 @@
     field public static final int TYPE_PASSTHROUGH = 65536; // 0x10000
     field public static final int TYPE_S_DMB = 393472; // 0x60100
     field public static final int TYPE_T_DMB = 393216; // 0x60000
-    field public static final java.lang.String VERSION_NUMBER = "version_number";
   }
 
   public static final class TvContract.Programs implements android.provider.TvContract.BaseTvColumns {
-    field public static final java.lang.String CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final java.lang.String COLUMN_DATA = "data";
+    field public static final java.lang.String COLUMN_DESCRIPTION = "description";
+    field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
+    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.com.android.tv.programs";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.com.android.tv.programs";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DATA = "data";
-    field public static final java.lang.String DESCRIPTION = "description";
-    field public static final java.lang.String END_TIME_UTC_MILLIS = "end_time_utc_millis";
-    field public static final java.lang.String LONG_DESCRIPTION = "long_description";
-    field public static final java.lang.String START_TIME_UTC_MILLIS = "start_time_utc_millis";
-    field public static final java.lang.String TITLE = "title";
-    field public static final java.lang.String VERSION_NUMBER = "version_number";
   }
 
   public class UserDictionary {
@@ -24336,6 +24670,7 @@
     method public void contextDump();
     method public static android.renderscript.RenderScript create(android.content.Context);
     method public static android.renderscript.RenderScript create(android.content.Context, android.renderscript.RenderScript.ContextType);
+    method public static android.renderscript.RenderScript create(android.content.Context, android.renderscript.RenderScript.ContextType, long);
     method public void destroy();
     method public void finish();
     method public final android.content.Context getApplicationContext();
@@ -24345,6 +24680,9 @@
     method public void setErrorHandler(android.renderscript.RenderScript.RSErrorHandler);
     method public void setMessageHandler(android.renderscript.RenderScript.RSMessageHandler);
     method public void setPriority(android.renderscript.RenderScript.Priority);
+    field public static final long CREATE_FLAG_LOW_LATENCY = 1L; // 0x1L
+    field public static final long CREATE_FLAG_LOW_POWER = 2L; // 0x2L
+    field public static final long CREATE_FLAG_NONE = 0L; // 0x0L
   }
 
   public static final class RenderScript.ContextType extends java.lang.Enum {
@@ -24844,7 +25182,6 @@
     method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
     method public boolean onSearchRequested();
     method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
-    method public void onWindowDismissed();
     method public void onWindowFocusChanged(boolean);
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
     method public void setContentView(int);
@@ -24859,6 +25196,36 @@
 
 }
 
+package android.service.fingerprint {
+
+  public class FingerprintManager {
+    ctor public FingerprintManager(android.content.Context);
+    method public void enroll(long);
+    method public void remove(int);
+    method public void startListening(android.service.fingerprint.FingerprintManagerReceiver);
+    method public void stopListening();
+    field protected static final boolean DEBUG = true;
+    field public static final int FINGERPRINT_ERROR = -1; // 0xffffffff
+    field public static final int FINGERPRINT_ERROR_BAD_CAPTURE = 2; // 0x2
+    field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
+    field public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10; // 0xfffffff6
+    field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
+    field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
+    field public static final int FINGERPRINT_SCANNED = 1; // 0x1
+    field public static final int FINGERPRINT_TEMPLATE_ENROLLING = 2; // 0x2
+    field public static final int FINGERPRINT_TEMPLATE_REMOVED = 4; // 0x4
+  }
+
+  public class FingerprintManagerReceiver {
+    ctor public FingerprintManagerReceiver();
+    method public void onEnrollResult(int, int);
+    method public void onError(int);
+    method public void onRemoved(int);
+    method public void onScanned(int, int);
+  }
+
+}
+
 package android.service.notification {
 
   public abstract class NotificationListenerService extends android.app.Service {
@@ -24867,16 +25234,24 @@
     method public final deprecated void cancelNotification(java.lang.String, java.lang.String, int);
     method public final void cancelNotification(java.lang.String);
     method public final void cancelNotifications(java.lang.String[]);
-    method public java.lang.String[] getActiveNotificationKeys();
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
     method public android.service.notification.StatusBarNotification[] getActiveNotifications(java.lang.String[]);
+    method public java.lang.String[] getOrderedNotificationKeys();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onListenerConnected(java.lang.String[]);
+    method public void onNotificationOrderUpdate();
     method public abstract void onNotificationPosted(android.service.notification.StatusBarNotification);
     method public abstract void onNotificationRemoved(android.service.notification.StatusBarNotification);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
   }
 
+  public class NotificationOrderUpdate implements android.os.Parcelable {
+    ctor public NotificationOrderUpdate(android.os.Parcel);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
   public class StatusBarNotification implements android.os.Parcelable {
     ctor public StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long);
     ctor public StatusBarNotification(android.os.Parcel);
@@ -24940,23 +25315,53 @@
   public class VoiceInteractionService extends android.app.Service {
     ctor public VoiceInteractionService();
     method public android.os.IBinder onBind(android.content.Intent);
-    method public void startVoiceActivity(android.content.Intent, android.os.Bundle);
+    method public void startSession(android.os.Bundle);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
     field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
   }
 
-  public abstract class VoiceInteractionSession {
+  public abstract class VoiceInteractionSession implements android.view.KeyEvent.Callback {
     ctor public VoiceInteractionSession(android.content.Context);
     ctor public VoiceInteractionSession(android.content.Context, android.os.Handler);
+    method public void finish();
+    method public android.view.LayoutInflater getLayoutInflater();
+    method public android.app.Dialog getWindow();
+    method public void hideWindow();
+    method public void onBackPressed();
     method public abstract void onCancel(android.service.voice.VoiceInteractionSession.Request);
+    method public void onCloseSystemDialogs();
     method public abstract void onCommand(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.String, android.os.Bundle);
+    method public void onComputeInsets(android.service.voice.VoiceInteractionSession.Insets);
     method public abstract void onConfirm(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.String, android.os.Bundle);
+    method public void onCreate(android.os.Bundle);
+    method public android.view.View onCreateContentView();
+    method public void onDestroy();
     method public abstract boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
+    method public boolean onKeyDown(int, android.view.KeyEvent);
+    method public boolean onKeyLongPress(int, android.view.KeyEvent);
+    method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
+    method public boolean onKeyUp(int, android.view.KeyEvent);
+    method public void onTaskFinished(android.content.Intent, int);
+    method public void onTaskStarted(android.content.Intent, int);
+    method public void setContentView(android.view.View);
+    method public void setTheme(int);
+    method public void showWindow();
+    method public void startVoiceActivity(android.content.Intent);
   }
 
   public static class VoiceInteractionSession.Caller {
   }
 
+  public static final class VoiceInteractionSession.Insets {
+    ctor public VoiceInteractionSession.Insets();
+    field public static final int TOUCHABLE_INSETS_CONTENT = 1; // 0x1
+    field public static final int TOUCHABLE_INSETS_FRAME = 0; // 0x0
+    field public static final int TOUCHABLE_INSETS_REGION = 3; // 0x3
+    field public int contentTopInsets;
+    field public int touchableInsets;
+    field public final android.graphics.Region touchableRegion;
+  }
+
   public static class VoiceInteractionSession.Request {
     method public void sendCancelResult();
     method public void sendCommandResult(boolean, android.os.Bundle);
@@ -25400,6 +25805,848 @@
 
 }
 
+package android.system {
+
+  public final class ErrnoException extends java.lang.Exception {
+    ctor public ErrnoException(java.lang.String, int);
+    ctor public ErrnoException(java.lang.String, int, java.lang.Throwable);
+    field public final int errno;
+  }
+
+  public final class Os {
+    method public static java.io.FileDescriptor accept(java.io.FileDescriptor, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
+    method public static boolean access(java.lang.String, int) throws android.system.ErrnoException;
+    method public static void bind(java.io.FileDescriptor, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
+    method public static void chmod(java.lang.String, int) throws android.system.ErrnoException;
+    method public static void chown(java.lang.String, int, int) throws android.system.ErrnoException;
+    method public static void close(java.io.FileDescriptor) throws android.system.ErrnoException;
+    method public static void connect(java.io.FileDescriptor, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
+    method public static java.io.FileDescriptor dup(java.io.FileDescriptor) throws android.system.ErrnoException;
+    method public static java.io.FileDescriptor dup2(java.io.FileDescriptor, int) throws android.system.ErrnoException;
+    method public static java.lang.String[] environ();
+    method public static void execv(java.lang.String, java.lang.String[]) throws android.system.ErrnoException;
+    method public static void execve(java.lang.String, java.lang.String[], java.lang.String[]) throws android.system.ErrnoException;
+    method public static void fchmod(java.io.FileDescriptor, int) throws android.system.ErrnoException;
+    method public static void fchown(java.io.FileDescriptor, int, int) throws android.system.ErrnoException;
+    method public static void fdatasync(java.io.FileDescriptor) throws android.system.ErrnoException;
+    method public static android.system.StructStat fstat(java.io.FileDescriptor) throws android.system.ErrnoException;
+    method public static android.system.StructStatVfs fstatvfs(java.io.FileDescriptor) throws android.system.ErrnoException;
+    method public static void fsync(java.io.FileDescriptor) throws android.system.ErrnoException;
+    method public static void ftruncate(java.io.FileDescriptor, long) throws android.system.ErrnoException;
+    method public static java.lang.String gai_strerror(int);
+    method public static int getegid();
+    method public static java.lang.String getenv(java.lang.String);
+    method public static int geteuid();
+    method public static int getgid();
+    method public static java.net.SocketAddress getpeername(java.io.FileDescriptor) throws android.system.ErrnoException;
+    method public static int getpid();
+    method public static int getppid();
+    method public static java.net.SocketAddress getsockname(java.io.FileDescriptor) throws android.system.ErrnoException;
+    method public static int gettid();
+    method public static int getuid();
+    method public static java.lang.String if_indextoname(int);
+    method public static java.net.InetAddress inet_pton(int, java.lang.String);
+    method public static boolean isatty(java.io.FileDescriptor);
+    method public static void kill(int, int) throws android.system.ErrnoException;
+    method public static void lchown(java.lang.String, int, int) throws android.system.ErrnoException;
+    method public static void link(java.lang.String, java.lang.String) throws android.system.ErrnoException;
+    method public static void listen(java.io.FileDescriptor, int) throws android.system.ErrnoException;
+    method public static long lseek(java.io.FileDescriptor, long, int) throws android.system.ErrnoException;
+    method public static android.system.StructStat lstat(java.lang.String) throws android.system.ErrnoException;
+    method public static void mincore(long, long, byte[]) throws android.system.ErrnoException;
+    method public static void mkdir(java.lang.String, int) throws android.system.ErrnoException;
+    method public static void mkfifo(java.lang.String, int) throws android.system.ErrnoException;
+    method public static void mlock(long, long) throws android.system.ErrnoException;
+    method public static long mmap(long, long, int, int, java.io.FileDescriptor, long) throws android.system.ErrnoException;
+    method public static void msync(long, long, int) throws android.system.ErrnoException;
+    method public static void munlock(long, long) throws android.system.ErrnoException;
+    method public static void munmap(long, long) throws android.system.ErrnoException;
+    method public static java.io.FileDescriptor open(java.lang.String, int, int) throws android.system.ErrnoException;
+    method public static java.io.FileDescriptor[] pipe() throws android.system.ErrnoException;
+    method public static int poll(android.system.StructPollfd[], int) throws android.system.ErrnoException;
+    method public static void posix_fallocate(java.io.FileDescriptor, long, long) throws android.system.ErrnoException;
+    method public static int prctl(int, long, long, long, long) throws android.system.ErrnoException;
+    method public static int pread(java.io.FileDescriptor, java.nio.ByteBuffer, long) throws android.system.ErrnoException, java.io.InterruptedIOException;
+    method public static int pread(java.io.FileDescriptor, byte[], int, int, long) throws android.system.ErrnoException, java.io.InterruptedIOException;
+    method public static int pwrite(java.io.FileDescriptor, java.nio.ByteBuffer, long) throws android.system.ErrnoException, java.io.InterruptedIOException;
+    method public static int pwrite(java.io.FileDescriptor, byte[], int, int, long) throws android.system.ErrnoException, java.io.InterruptedIOException;
+    method public static int read(java.io.FileDescriptor, java.nio.ByteBuffer) throws android.system.ErrnoException, java.io.InterruptedIOException;
+    method public static int read(java.io.FileDescriptor, byte[], int, int) throws android.system.ErrnoException, java.io.InterruptedIOException;
+    method public static java.lang.String readlink(java.lang.String) throws android.system.ErrnoException;
+    method public static int readv(java.io.FileDescriptor, java.lang.Object[], int[], int[]) throws android.system.ErrnoException, java.io.InterruptedIOException;
+    method public static int recvfrom(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
+    method public static int recvfrom(java.io.FileDescriptor, byte[], int, int, int, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
+    method public static void remove(java.lang.String) throws android.system.ErrnoException;
+    method public static void rename(java.lang.String, java.lang.String) throws android.system.ErrnoException;
+    method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
+    method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
+    method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
+    method public static void setegid(int) throws android.system.ErrnoException;
+    method public static void setenv(java.lang.String, java.lang.String, boolean) throws android.system.ErrnoException;
+    method public static void seteuid(int) throws android.system.ErrnoException;
+    method public static void setgid(int) throws android.system.ErrnoException;
+    method public static int setsid() throws android.system.ErrnoException;
+    method public static void setuid(int) throws android.system.ErrnoException;
+    method public static void shutdown(java.io.FileDescriptor, int) throws android.system.ErrnoException;
+    method public static java.io.FileDescriptor socket(int, int, int) throws android.system.ErrnoException;
+    method public static void socketpair(int, int, int, java.io.FileDescriptor, java.io.FileDescriptor) throws android.system.ErrnoException;
+    method public static android.system.StructStat stat(java.lang.String) throws android.system.ErrnoException;
+    method public static android.system.StructStatVfs statvfs(java.lang.String) throws android.system.ErrnoException;
+    method public static java.lang.String strerror(int);
+    method public static java.lang.String strsignal(int);
+    method public static void symlink(java.lang.String, java.lang.String) throws android.system.ErrnoException;
+    method public static long sysconf(int);
+    method public static void tcdrain(java.io.FileDescriptor) throws android.system.ErrnoException;
+    method public static void tcsendbreak(java.io.FileDescriptor, int) throws android.system.ErrnoException;
+    method public static int umask(int);
+    method public static android.system.StructUtsname uname();
+    method public static void unsetenv(java.lang.String) throws android.system.ErrnoException;
+    method public static int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
+    method public static int write(java.io.FileDescriptor, java.nio.ByteBuffer) throws android.system.ErrnoException, java.io.InterruptedIOException;
+    method public static int write(java.io.FileDescriptor, byte[], int, int) throws android.system.ErrnoException, java.io.InterruptedIOException;
+    method public static int writev(java.io.FileDescriptor, java.lang.Object[], int[], int[]) throws android.system.ErrnoException, java.io.InterruptedIOException;
+  }
+
+  public final class OsConstants {
+    method public static boolean S_ISBLK(int);
+    method public static boolean S_ISCHR(int);
+    method public static boolean S_ISDIR(int);
+    method public static boolean S_ISFIFO(int);
+    method public static boolean S_ISLNK(int);
+    method public static boolean S_ISREG(int);
+    method public static boolean S_ISSOCK(int);
+    method public static boolean WCOREDUMP(int);
+    method public static int WEXITSTATUS(int);
+    method public static boolean WIFEXITED(int);
+    method public static boolean WIFSIGNALED(int);
+    method public static boolean WIFSTOPPED(int);
+    method public static int WSTOPSIG(int);
+    method public static int WTERMSIG(int);
+    method public static java.lang.String errnoName(int);
+    method public static java.lang.String gaiName(int);
+    field public static final int AF_INET;
+    field public static final int AF_INET6;
+    field public static final int AF_UNIX;
+    field public static final int AF_UNSPEC;
+    field public static final int AI_ADDRCONFIG;
+    field public static final int AI_ALL;
+    field public static final int AI_CANONNAME;
+    field public static final int AI_NUMERICHOST;
+    field public static final int AI_NUMERICSERV;
+    field public static final int AI_PASSIVE;
+    field public static final int AI_V4MAPPED;
+    field public static final int CAP_AUDIT_CONTROL;
+    field public static final int CAP_AUDIT_WRITE;
+    field public static final int CAP_BLOCK_SUSPEND;
+    field public static final int CAP_CHOWN;
+    field public static final int CAP_DAC_OVERRIDE;
+    field public static final int CAP_DAC_READ_SEARCH;
+    field public static final int CAP_FOWNER;
+    field public static final int CAP_FSETID;
+    field public static final int CAP_IPC_LOCK;
+    field public static final int CAP_IPC_OWNER;
+    field public static final int CAP_KILL;
+    field public static final int CAP_LAST_CAP;
+    field public static final int CAP_LEASE;
+    field public static final int CAP_LINUX_IMMUTABLE;
+    field public static final int CAP_MAC_ADMIN;
+    field public static final int CAP_MAC_OVERRIDE;
+    field public static final int CAP_MKNOD;
+    field public static final int CAP_NET_ADMIN;
+    field public static final int CAP_NET_BIND_SERVICE;
+    field public static final int CAP_NET_BROADCAST;
+    field public static final int CAP_NET_RAW;
+    field public static final int CAP_SETFCAP;
+    field public static final int CAP_SETGID;
+    field public static final int CAP_SETPCAP;
+    field public static final int CAP_SETUID;
+    field public static final int CAP_SYSLOG;
+    field public static final int CAP_SYS_ADMIN;
+    field public static final int CAP_SYS_BOOT;
+    field public static final int CAP_SYS_CHROOT;
+    field public static final int CAP_SYS_MODULE;
+    field public static final int CAP_SYS_NICE;
+    field public static final int CAP_SYS_PACCT;
+    field public static final int CAP_SYS_PTRACE;
+    field public static final int CAP_SYS_RAWIO;
+    field public static final int CAP_SYS_RESOURCE;
+    field public static final int CAP_SYS_TIME;
+    field public static final int CAP_SYS_TTY_CONFIG;
+    field public static final int CAP_WAKE_ALARM;
+    field public static final int E2BIG;
+    field public static final int EACCES;
+    field public static final int EADDRINUSE;
+    field public static final int EADDRNOTAVAIL;
+    field public static final int EAFNOSUPPORT;
+    field public static final int EAGAIN;
+    field public static final int EAI_AGAIN;
+    field public static final int EAI_BADFLAGS;
+    field public static final int EAI_FAIL;
+    field public static final int EAI_FAMILY;
+    field public static final int EAI_MEMORY;
+    field public static final int EAI_NODATA;
+    field public static final int EAI_NONAME;
+    field public static final int EAI_OVERFLOW;
+    field public static final int EAI_SERVICE;
+    field public static final int EAI_SOCKTYPE;
+    field public static final int EAI_SYSTEM;
+    field public static final int EALREADY;
+    field public static final int EBADF;
+    field public static final int EBADMSG;
+    field public static final int EBUSY;
+    field public static final int ECANCELED;
+    field public static final int ECHILD;
+    field public static final int ECONNABORTED;
+    field public static final int ECONNREFUSED;
+    field public static final int ECONNRESET;
+    field public static final int EDEADLK;
+    field public static final int EDESTADDRREQ;
+    field public static final int EDOM;
+    field public static final int EDQUOT;
+    field public static final int EEXIST;
+    field public static final int EFAULT;
+    field public static final int EFBIG;
+    field public static final int EHOSTUNREACH;
+    field public static final int EIDRM;
+    field public static final int EILSEQ;
+    field public static final int EINPROGRESS;
+    field public static final int EINTR;
+    field public static final int EINVAL;
+    field public static final int EIO;
+    field public static final int EISCONN;
+    field public static final int EISDIR;
+    field public static final int ELOOP;
+    field public static final int EMFILE;
+    field public static final int EMLINK;
+    field public static final int EMSGSIZE;
+    field public static final int EMULTIHOP;
+    field public static final int ENAMETOOLONG;
+    field public static final int ENETDOWN;
+    field public static final int ENETRESET;
+    field public static final int ENETUNREACH;
+    field public static final int ENFILE;
+    field public static final int ENOBUFS;
+    field public static final int ENODATA;
+    field public static final int ENODEV;
+    field public static final int ENOENT;
+    field public static final int ENOEXEC;
+    field public static final int ENOLCK;
+    field public static final int ENOLINK;
+    field public static final int ENOMEM;
+    field public static final int ENOMSG;
+    field public static final int ENOPROTOOPT;
+    field public static final int ENOSPC;
+    field public static final int ENOSR;
+    field public static final int ENOSTR;
+    field public static final int ENOSYS;
+    field public static final int ENOTCONN;
+    field public static final int ENOTDIR;
+    field public static final int ENOTEMPTY;
+    field public static final int ENOTSOCK;
+    field public static final int ENOTSUP;
+    field public static final int ENOTTY;
+    field public static final int ENXIO;
+    field public static final int EOPNOTSUPP;
+    field public static final int EOVERFLOW;
+    field public static final int EPERM;
+    field public static final int EPIPE;
+    field public static final int EPROTO;
+    field public static final int EPROTONOSUPPORT;
+    field public static final int EPROTOTYPE;
+    field public static final int ERANGE;
+    field public static final int EROFS;
+    field public static final int ESPIPE;
+    field public static final int ESRCH;
+    field public static final int ESTALE;
+    field public static final int ETIME;
+    field public static final int ETIMEDOUT;
+    field public static final int ETXTBSY;
+    field public static final int EXDEV;
+    field public static final int EXIT_FAILURE;
+    field public static final int EXIT_SUCCESS;
+    field public static final int FD_CLOEXEC;
+    field public static final int FIONREAD;
+    field public static final int F_DUPFD;
+    field public static final int F_GETFD;
+    field public static final int F_GETFL;
+    field public static final int F_GETLK;
+    field public static final int F_GETLK64;
+    field public static final int F_GETOWN;
+    field public static final int F_OK;
+    field public static final int F_RDLCK;
+    field public static final int F_SETFD;
+    field public static final int F_SETFL;
+    field public static final int F_SETLK;
+    field public static final int F_SETLK64;
+    field public static final int F_SETLKW;
+    field public static final int F_SETLKW64;
+    field public static final int F_SETOWN;
+    field public static final int F_UNLCK;
+    field public static final int F_WRLCK;
+    field public static final int IFA_F_DADFAILED;
+    field public static final int IFA_F_DEPRECATED;
+    field public static final int IFA_F_HOMEADDRESS;
+    field public static final int IFA_F_NODAD;
+    field public static final int IFA_F_OPTIMISTIC;
+    field public static final int IFA_F_PERMANENT;
+    field public static final int IFA_F_SECONDARY;
+    field public static final int IFA_F_TEMPORARY;
+    field public static final int IFA_F_TENTATIVE;
+    field public static final int IFF_ALLMULTI;
+    field public static final int IFF_AUTOMEDIA;
+    field public static final int IFF_BROADCAST;
+    field public static final int IFF_DEBUG;
+    field public static final int IFF_DYNAMIC;
+    field public static final int IFF_LOOPBACK;
+    field public static final int IFF_MASTER;
+    field public static final int IFF_MULTICAST;
+    field public static final int IFF_NOARP;
+    field public static final int IFF_NOTRAILERS;
+    field public static final int IFF_POINTOPOINT;
+    field public static final int IFF_PORTSEL;
+    field public static final int IFF_PROMISC;
+    field public static final int IFF_RUNNING;
+    field public static final int IFF_SLAVE;
+    field public static final int IFF_UP;
+    field public static final int IPPROTO_ICMP;
+    field public static final int IPPROTO_ICMPV6;
+    field public static final int IPPROTO_IP;
+    field public static final int IPPROTO_IPV6;
+    field public static final int IPPROTO_RAW;
+    field public static final int IPPROTO_TCP;
+    field public static final int IPPROTO_UDP;
+    field public static final int IPV6_CHECKSUM;
+    field public static final int IPV6_MULTICAST_HOPS;
+    field public static final int IPV6_MULTICAST_IF;
+    field public static final int IPV6_MULTICAST_LOOP;
+    field public static final int IPV6_RECVDSTOPTS;
+    field public static final int IPV6_RECVHOPLIMIT;
+    field public static final int IPV6_RECVHOPOPTS;
+    field public static final int IPV6_RECVPKTINFO;
+    field public static final int IPV6_RECVRTHDR;
+    field public static final int IPV6_RECVTCLASS;
+    field public static final int IPV6_TCLASS;
+    field public static final int IPV6_UNICAST_HOPS;
+    field public static final int IPV6_V6ONLY;
+    field public static final int IP_MULTICAST_IF;
+    field public static final int IP_MULTICAST_LOOP;
+    field public static final int IP_MULTICAST_TTL;
+    field public static final int IP_TOS;
+    field public static final int IP_TTL;
+    field public static final int MAP_FIXED;
+    field public static final int MAP_PRIVATE;
+    field public static final int MAP_SHARED;
+    field public static final int MCAST_BLOCK_SOURCE;
+    field public static final int MCAST_JOIN_GROUP;
+    field public static final int MCAST_JOIN_SOURCE_GROUP;
+    field public static final int MCAST_LEAVE_GROUP;
+    field public static final int MCAST_LEAVE_SOURCE_GROUP;
+    field public static final int MCAST_UNBLOCK_SOURCE;
+    field public static final int MCL_CURRENT;
+    field public static final int MCL_FUTURE;
+    field public static final int MSG_CTRUNC;
+    field public static final int MSG_DONTROUTE;
+    field public static final int MSG_EOR;
+    field public static final int MSG_OOB;
+    field public static final int MSG_PEEK;
+    field public static final int MSG_TRUNC;
+    field public static final int MSG_WAITALL;
+    field public static final int MS_ASYNC;
+    field public static final int MS_INVALIDATE;
+    field public static final int MS_SYNC;
+    field public static final int NI_DGRAM;
+    field public static final int NI_NAMEREQD;
+    field public static final int NI_NOFQDN;
+    field public static final int NI_NUMERICHOST;
+    field public static final int NI_NUMERICSERV;
+    field public static final int O_ACCMODE;
+    field public static final int O_APPEND;
+    field public static final int O_CREAT;
+    field public static final int O_EXCL;
+    field public static final int O_NOCTTY;
+    field public static final int O_NOFOLLOW;
+    field public static final int O_NONBLOCK;
+    field public static final int O_RDONLY;
+    field public static final int O_RDWR;
+    field public static final int O_SYNC;
+    field public static final int O_TRUNC;
+    field public static final int O_WRONLY;
+    field public static final int POLLERR;
+    field public static final int POLLHUP;
+    field public static final int POLLIN;
+    field public static final int POLLNVAL;
+    field public static final int POLLOUT;
+    field public static final int POLLPRI;
+    field public static final int POLLRDBAND;
+    field public static final int POLLRDNORM;
+    field public static final int POLLWRBAND;
+    field public static final int POLLWRNORM;
+    field public static final int PROT_EXEC;
+    field public static final int PROT_NONE;
+    field public static final int PROT_READ;
+    field public static final int PROT_WRITE;
+    field public static final int PR_SET_NO_NEW_PRIVS;
+    field public static final int RT_SCOPE_HOST;
+    field public static final int RT_SCOPE_LINK;
+    field public static final int RT_SCOPE_NOWHERE;
+    field public static final int RT_SCOPE_SITE;
+    field public static final int RT_SCOPE_UNIVERSE;
+    field public static final int R_OK;
+    field public static final int SEEK_CUR;
+    field public static final int SEEK_END;
+    field public static final int SEEK_SET;
+    field public static final int SHUT_RD;
+    field public static final int SHUT_RDWR;
+    field public static final int SHUT_WR;
+    field public static final int SIGABRT;
+    field public static final int SIGALRM;
+    field public static final int SIGBUS;
+    field public static final int SIGCHLD;
+    field public static final int SIGCONT;
+    field public static final int SIGFPE;
+    field public static final int SIGHUP;
+    field public static final int SIGILL;
+    field public static final int SIGINT;
+    field public static final int SIGIO;
+    field public static final int SIGKILL;
+    field public static final int SIGPIPE;
+    field public static final int SIGPROF;
+    field public static final int SIGPWR;
+    field public static final int SIGQUIT;
+    field public static final int SIGRTMAX;
+    field public static final int SIGRTMIN;
+    field public static final int SIGSEGV;
+    field public static final int SIGSTKFLT;
+    field public static final int SIGSTOP;
+    field public static final int SIGSYS;
+    field public static final int SIGTERM;
+    field public static final int SIGTRAP;
+    field public static final int SIGTSTP;
+    field public static final int SIGTTIN;
+    field public static final int SIGTTOU;
+    field public static final int SIGURG;
+    field public static final int SIGUSR1;
+    field public static final int SIGUSR2;
+    field public static final int SIGVTALRM;
+    field public static final int SIGWINCH;
+    field public static final int SIGXCPU;
+    field public static final int SIGXFSZ;
+    field public static final int SIOCGIFADDR;
+    field public static final int SIOCGIFBRDADDR;
+    field public static final int SIOCGIFDSTADDR;
+    field public static final int SIOCGIFNETMASK;
+    field public static final int SOCK_DGRAM;
+    field public static final int SOCK_RAW;
+    field public static final int SOCK_SEQPACKET;
+    field public static final int SOCK_STREAM;
+    field public static final int SOL_SOCKET;
+    field public static final int SO_BINDTODEVICE;
+    field public static final int SO_BROADCAST;
+    field public static final int SO_DEBUG;
+    field public static final int SO_DONTROUTE;
+    field public static final int SO_ERROR;
+    field public static final int SO_KEEPALIVE;
+    field public static final int SO_LINGER;
+    field public static final int SO_OOBINLINE;
+    field public static final int SO_PASSCRED;
+    field public static final int SO_PEERCRED;
+    field public static final int SO_RCVBUF;
+    field public static final int SO_RCVLOWAT;
+    field public static final int SO_RCVTIMEO;
+    field public static final int SO_REUSEADDR;
+    field public static final int SO_SNDBUF;
+    field public static final int SO_SNDLOWAT;
+    field public static final int SO_SNDTIMEO;
+    field public static final int SO_TYPE;
+    field public static final int STDERR_FILENO;
+    field public static final int STDIN_FILENO;
+    field public static final int STDOUT_FILENO;
+    field public static final int S_IFBLK;
+    field public static final int S_IFCHR;
+    field public static final int S_IFDIR;
+    field public static final int S_IFIFO;
+    field public static final int S_IFLNK;
+    field public static final int S_IFMT;
+    field public static final int S_IFREG;
+    field public static final int S_IFSOCK;
+    field public static final int S_IRGRP;
+    field public static final int S_IROTH;
+    field public static final int S_IRUSR;
+    field public static final int S_IRWXG;
+    field public static final int S_IRWXO;
+    field public static final int S_IRWXU;
+    field public static final int S_ISGID;
+    field public static final int S_ISUID;
+    field public static final int S_ISVTX;
+    field public static final int S_IWGRP;
+    field public static final int S_IWOTH;
+    field public static final int S_IWUSR;
+    field public static final int S_IXGRP;
+    field public static final int S_IXOTH;
+    field public static final int S_IXUSR;
+    field public static final int TCP_NODELAY;
+    field public static final int WCONTINUED;
+    field public static final int WEXITED;
+    field public static final int WNOHANG;
+    field public static final int WNOWAIT;
+    field public static final int WSTOPPED;
+    field public static final int WUNTRACED;
+    field public static final int W_OK;
+    field public static final int X_OK;
+    field public static final int _SC_2_CHAR_TERM;
+    field public static final int _SC_2_C_BIND;
+    field public static final int _SC_2_C_DEV;
+    field public static final int _SC_2_C_VERSION;
+    field public static final int _SC_2_FORT_DEV;
+    field public static final int _SC_2_FORT_RUN;
+    field public static final int _SC_2_LOCALEDEF;
+    field public static final int _SC_2_SW_DEV;
+    field public static final int _SC_2_UPE;
+    field public static final int _SC_2_VERSION;
+    field public static final int _SC_AIO_LISTIO_MAX;
+    field public static final int _SC_AIO_MAX;
+    field public static final int _SC_AIO_PRIO_DELTA_MAX;
+    field public static final int _SC_ARG_MAX;
+    field public static final int _SC_ASYNCHRONOUS_IO;
+    field public static final int _SC_ATEXIT_MAX;
+    field public static final int _SC_AVPHYS_PAGES;
+    field public static final int _SC_BC_BASE_MAX;
+    field public static final int _SC_BC_DIM_MAX;
+    field public static final int _SC_BC_SCALE_MAX;
+    field public static final int _SC_BC_STRING_MAX;
+    field public static final int _SC_CHILD_MAX;
+    field public static final int _SC_CLK_TCK;
+    field public static final int _SC_COLL_WEIGHTS_MAX;
+    field public static final int _SC_DELAYTIMER_MAX;
+    field public static final int _SC_EXPR_NEST_MAX;
+    field public static final int _SC_FSYNC;
+    field public static final int _SC_GETGR_R_SIZE_MAX;
+    field public static final int _SC_GETPW_R_SIZE_MAX;
+    field public static final int _SC_IOV_MAX;
+    field public static final int _SC_JOB_CONTROL;
+    field public static final int _SC_LINE_MAX;
+    field public static final int _SC_LOGIN_NAME_MAX;
+    field public static final int _SC_MAPPED_FILES;
+    field public static final int _SC_MEMLOCK;
+    field public static final int _SC_MEMLOCK_RANGE;
+    field public static final int _SC_MEMORY_PROTECTION;
+    field public static final int _SC_MESSAGE_PASSING;
+    field public static final int _SC_MQ_OPEN_MAX;
+    field public static final int _SC_MQ_PRIO_MAX;
+    field public static final int _SC_NGROUPS_MAX;
+    field public static final int _SC_NPROCESSORS_CONF;
+    field public static final int _SC_NPROCESSORS_ONLN;
+    field public static final int _SC_OPEN_MAX;
+    field public static final int _SC_PAGESIZE;
+    field public static final int _SC_PAGE_SIZE;
+    field public static final int _SC_PASS_MAX;
+    field public static final int _SC_PHYS_PAGES;
+    field public static final int _SC_PRIORITIZED_IO;
+    field public static final int _SC_PRIORITY_SCHEDULING;
+    field public static final int _SC_REALTIME_SIGNALS;
+    field public static final int _SC_RE_DUP_MAX;
+    field public static final int _SC_RTSIG_MAX;
+    field public static final int _SC_SAVED_IDS;
+    field public static final int _SC_SEMAPHORES;
+    field public static final int _SC_SEM_NSEMS_MAX;
+    field public static final int _SC_SEM_VALUE_MAX;
+    field public static final int _SC_SHARED_MEMORY_OBJECTS;
+    field public static final int _SC_SIGQUEUE_MAX;
+    field public static final int _SC_STREAM_MAX;
+    field public static final int _SC_SYNCHRONIZED_IO;
+    field public static final int _SC_THREADS;
+    field public static final int _SC_THREAD_ATTR_STACKADDR;
+    field public static final int _SC_THREAD_ATTR_STACKSIZE;
+    field public static final int _SC_THREAD_DESTRUCTOR_ITERATIONS;
+    field public static final int _SC_THREAD_KEYS_MAX;
+    field public static final int _SC_THREAD_PRIORITY_SCHEDULING;
+    field public static final int _SC_THREAD_PRIO_INHERIT;
+    field public static final int _SC_THREAD_PRIO_PROTECT;
+    field public static final int _SC_THREAD_SAFE_FUNCTIONS;
+    field public static final int _SC_THREAD_STACK_MIN;
+    field public static final int _SC_THREAD_THREADS_MAX;
+    field public static final int _SC_TIMERS;
+    field public static final int _SC_TIMER_MAX;
+    field public static final int _SC_TTY_NAME_MAX;
+    field public static final int _SC_TZNAME_MAX;
+    field public static final int _SC_VERSION;
+    field public static final int _SC_XBS5_ILP32_OFF32;
+    field public static final int _SC_XBS5_ILP32_OFFBIG;
+    field public static final int _SC_XBS5_LP64_OFF64;
+    field public static final int _SC_XBS5_LPBIG_OFFBIG;
+    field public static final int _SC_XOPEN_CRYPT;
+    field public static final int _SC_XOPEN_ENH_I18N;
+    field public static final int _SC_XOPEN_LEGACY;
+    field public static final int _SC_XOPEN_REALTIME;
+    field public static final int _SC_XOPEN_REALTIME_THREADS;
+    field public static final int _SC_XOPEN_SHM;
+    field public static final int _SC_XOPEN_UNIX;
+    field public static final int _SC_XOPEN_VERSION;
+    field public static final int _SC_XOPEN_XCU_VERSION;
+  }
+
+  public final class StructPollfd {
+    ctor public StructPollfd();
+    field public short events;
+    field public java.io.FileDescriptor fd;
+    field public short revents;
+    field public java.lang.Object userData;
+  }
+
+  public final class StructStat {
+    ctor public StructStat(long, long, int, long, int, int, long, long, long, long, long, long, long);
+    field public final long st_atime;
+    field public final long st_blksize;
+    field public final long st_blocks;
+    field public final long st_ctime;
+    field public final long st_dev;
+    field public final int st_gid;
+    field public final long st_ino;
+    field public final int st_mode;
+    field public final long st_mtime;
+    field public final long st_nlink;
+    field public final long st_rdev;
+    field public final long st_size;
+    field public final int st_uid;
+  }
+
+  public final class StructStatVfs {
+    ctor public StructStatVfs(long, long, long, long, long, long, long, long, long, long, long);
+    field public final long f_bavail;
+    field public final long f_bfree;
+    field public final long f_blocks;
+    field public final long f_bsize;
+    field public final long f_favail;
+    field public final long f_ffree;
+    field public final long f_files;
+    field public final long f_flag;
+    field public final long f_frsize;
+    field public final long f_fsid;
+    field public final long f_namemax;
+  }
+
+  public final class StructUtsname {
+    ctor public StructUtsname(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    field public final java.lang.String machine;
+    field public final java.lang.String nodename;
+    field public final java.lang.String release;
+    field public final java.lang.String sysname;
+    field public final java.lang.String version;
+  }
+
+}
+
+package android.telecomm {
+
+  public final class CallAudioState implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static int ROUTE_ALL;
+    field public static int ROUTE_BLUETOOTH;
+    field public static int ROUTE_EARPIECE;
+    field public static int ROUTE_SPEAKER;
+    field public static int ROUTE_WIRED_HEADSET;
+    field public static int ROUTE_WIRED_OR_EARPIECE;
+    field public final boolean isMuted;
+    field public final int route;
+    field public final int supportedRouteMask;
+  }
+
+  public class CallCapabilities {
+    ctor public CallCapabilities();
+    field public static final int ADD_CALL = 16; // 0x10
+    field public static final int ALL = 511; // 0x1ff
+    field public static final int CONNECTION_HANDOFF = 256; // 0x100
+    field public static final int GENERIC_CONFERENCE = 128; // 0x80
+    field public static final int HOLD = 1; // 0x1
+    field public static final int MERGE_CALLS = 4; // 0x4
+    field public static final int MUTE = 64; // 0x40
+    field public static final int RESPOND_VIA_TEXT = 32; // 0x20
+    field public static final int SUPPORT_HOLD = 2; // 0x2
+    field public static final int SWAP_CALLS = 8; // 0x8
+  }
+
+  public final class CallInfo implements android.os.Parcelable {
+    ctor public CallInfo(java.lang.String, android.telecomm.CallState, android.net.Uri);
+    method public int describeContents();
+    method public android.telecomm.CallServiceDescriptor getCurrentCallServiceDescriptor();
+    method public android.os.Bundle getExtras();
+    method public android.telecomm.GatewayInfo getGatewayInfo();
+    method public android.net.Uri getHandle();
+    method public java.lang.String getId();
+    method public android.net.Uri getOriginalHandle();
+    method public android.telecomm.CallState getState();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public final class CallNumberPresentation extends java.lang.Enum {
+    method public static android.telecomm.CallNumberPresentation valueOf(java.lang.String);
+    method public static final android.telecomm.CallNumberPresentation[] values();
+    enum_constant public static final android.telecomm.CallNumberPresentation ALLOWED;
+    enum_constant public static final android.telecomm.CallNumberPresentation PAYPHONE;
+    enum_constant public static final android.telecomm.CallNumberPresentation RESTRICTED;
+    enum_constant public static final android.telecomm.CallNumberPresentation UNKNOWN;
+  }
+
+  public abstract class CallService extends android.app.Service {
+    ctor public CallService();
+    method public abstract void abort(java.lang.String);
+    method public abstract void answer(java.lang.String);
+    method public abstract void call(android.telecomm.CallInfo);
+    method public abstract void disconnect(java.lang.String);
+    method protected final android.telecomm.CallServiceAdapter getAdapter();
+    method public final android.os.IBinder getBinder();
+    method public abstract void hold(java.lang.String);
+    method public abstract void isCompatibleWith(android.telecomm.CallInfo);
+    method protected void onAdapterAttached(android.telecomm.CallServiceAdapter);
+    method public abstract void onAudioStateChanged(java.lang.String, android.telecomm.CallAudioState);
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract void playDtmfTone(java.lang.String, char);
+    method public abstract void reject(java.lang.String);
+    method public abstract void setIncomingCallId(java.lang.String, android.os.Bundle);
+    method public abstract void stopDtmfTone(java.lang.String);
+    method public abstract void unhold(java.lang.String);
+  }
+
+  public final class CallServiceAdapter {
+    method public void handleFailedOutgoingCall(java.lang.String, java.lang.String);
+    method public void handleSuccessfulOutgoingCall(java.lang.String);
+    method public void notifyIncomingCall(android.telecomm.CallInfo);
+    method public void setActive(java.lang.String);
+    method public void setDialing(java.lang.String);
+    method public void setDisconnected(java.lang.String, int, java.lang.String);
+    method public void setIsCompatibleWith(java.lang.String, boolean);
+    method public void setOnHold(java.lang.String);
+    method public void setRinging(java.lang.String);
+  }
+
+  public final class CallServiceDescriptor implements android.os.Parcelable {
+    method public int describeContents();
+    method public java.lang.String getCallServiceId();
+    method public int getNetworkType();
+    method public android.content.ComponentName getServiceComponent();
+    method public static android.telecomm.CallServiceDescriptor.Builder newBuilder(android.content.Context);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int FLAG_MOBILE = 4; // 0x4
+    field public static final int FLAG_PSTN = 2; // 0x2
+    field public static final int FLAG_WIFI = 1; // 0x1
+  }
+
+  public static class CallServiceDescriptor.Builder {
+    method public android.telecomm.CallServiceDescriptor build();
+    method public android.telecomm.CallServiceDescriptor.Builder setCallService(java.lang.Class<? extends android.telecomm.CallService>);
+    method public android.telecomm.CallServiceDescriptor.Builder setNetworkType(int);
+  }
+
+  public final class CallServiceLookupResponse {
+    method public void setCallServiceDescriptors(java.util.List<android.telecomm.CallServiceDescriptor>);
+  }
+
+  public abstract class CallServiceProvider extends android.app.Service {
+    ctor protected CallServiceProvider();
+    method public abstract void lookupCallServices(android.telecomm.CallServiceLookupResponse);
+    method public android.os.IBinder onBind(android.content.Intent);
+  }
+
+  public abstract class CallServiceSelector extends android.app.Service {
+    ctor protected CallServiceSelector();
+    method protected final void cancelOutgoingCall(android.telecomm.CallInfo);
+    method protected final android.telecomm.CallServiceSelectorAdapter getAdapter();
+    method protected final java.util.Collection<android.telecomm.CallInfo> getCalls();
+    method protected void onAdapterAttached(android.telecomm.CallServiceSelectorAdapter);
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method protected abstract void select(android.telecomm.CallInfo, java.util.List<android.telecomm.CallServiceDescriptor>);
+  }
+
+  public final class CallServiceSelectorAdapter {
+    method public void cancelOutgoingCall(java.lang.String);
+    method public void setHandoffInfo(java.lang.String, android.net.Uri, android.os.Bundle);
+    method public void setSelectedCallServices(java.lang.String, java.util.List<android.telecomm.CallServiceDescriptor>);
+  }
+
+  public final class CallState extends java.lang.Enum {
+    method public static android.telecomm.CallState valueOf(java.lang.String);
+    method public static final android.telecomm.CallState[] values();
+    enum_constant public static final android.telecomm.CallState ACTIVE;
+    enum_constant public static final android.telecomm.CallState DIALING;
+    enum_constant public static final android.telecomm.CallState DISCONNECTED;
+    enum_constant public static final android.telecomm.CallState NEW;
+    enum_constant public static final android.telecomm.CallState ON_HOLD;
+    enum_constant public static final android.telecomm.CallState POST_DIAL;
+    enum_constant public static final android.telecomm.CallState POST_DIAL_WAIT;
+    enum_constant public static final android.telecomm.CallState RINGING;
+  }
+
+  public class GatewayInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.net.Uri getGatewayHandle();
+    method public java.lang.String getGatewayProviderPackageName();
+    method public android.net.Uri getOriginalHandle();
+    method public boolean isEmpty();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public final class InCallAdapter {
+    method public void answerCall(java.lang.String);
+    method public void disconnectCall(java.lang.String);
+    method public void handoffCall(java.lang.String);
+    method public void holdCall(java.lang.String);
+    method public void mute(boolean);
+    method public void playDtmfTone(java.lang.String, char);
+    method public void postDialContinue(java.lang.String);
+    method public void rejectCall(java.lang.String);
+    method public void setAudioRoute(int);
+    method public void stopDtmfTone(java.lang.String);
+    method public void unholdCall(java.lang.String);
+  }
+
+  public final class InCallCall implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getCapabilities();
+    method public long getConnectTimeMillis();
+    method public android.telecomm.CallServiceDescriptor getCurrentCallServiceDescriptor();
+    method public int getDisconnectCause();
+    method public android.telecomm.GatewayInfo getGatewayInfo();
+    method public android.net.Uri getHandle();
+    method public android.telecomm.CallServiceDescriptor getHandoffCallServiceDescriptor();
+    method public java.lang.String getId();
+    method public android.telecomm.CallState getState();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public abstract class InCallService extends android.app.Service {
+    ctor protected InCallService();
+    method protected abstract void addCall(android.telecomm.InCallCall);
+    method protected final android.telecomm.InCallAdapter getAdapter();
+    method protected void onAdapterAttached(android.telecomm.InCallAdapter);
+    method protected abstract void onAudioStateChanged(android.telecomm.CallAudioState);
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method protected abstract void setPostDial(java.lang.String, java.lang.String);
+    method protected abstract void setPostDialWait(java.lang.String, java.lang.String);
+    method protected abstract void updateCall(android.telecomm.InCallCall);
+  }
+
+  public final class TelecommConstants {
+    ctor public TelecommConstants();
+    field public static final java.lang.String ACTION_CALL_SERVICE;
+    field public static final java.lang.String ACTION_CALL_SERVICE_PROVIDER;
+    field public static final java.lang.String ACTION_CALL_SERVICE_SELECTOR;
+    field public static final java.lang.String ACTION_INCOMING_CALL = "android.intent.action.INCOMING_CALL";
+    field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
+    field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
+    field public static final java.lang.String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecomm.extra.CALL_DISCONNECT_CAUSE";
+    field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecomm.extra.CALL_DISCONNECT_MESSAGE";
+    field public static final java.lang.String EXTRA_CALL_SERVICE_DESCRIPTOR = "android.intent.extra.CALL_SERVICE_DESCRIPTOR";
+    field public static final java.lang.String EXTRA_INCOMING_CALL_EXTRAS = "android.intent.extra.INCOMING_CALL_EXTRAS";
+  }
+
+}
+
 package android.telephony {
 
   public final class CellIdentityCdma implements android.os.Parcelable {
@@ -25548,6 +26795,50 @@
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
+  public class DisconnectCause {
+    method public static java.lang.String toString(int);
+    field public static final int BUSY = 4; // 0x4
+    field public static final int CALL_BARRED = 20; // 0x14
+    field public static final int CDMA_ACCESS_BLOCKED = 35; // 0x23
+    field public static final int CDMA_ACCESS_FAILURE = 32; // 0x20
+    field public static final int CDMA_DROP = 27; // 0x1b
+    field public static final int CDMA_INTERCEPT = 28; // 0x1c
+    field public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 26; // 0x1a
+    field public static final int CDMA_NOT_EMERGENCY = 34; // 0x22
+    field public static final int CDMA_PREEMPTED = 33; // 0x21
+    field public static final int CDMA_REORDER = 29; // 0x1d
+    field public static final int CDMA_RETRY_ORDER = 31; // 0x1f
+    field public static final int CDMA_SO_REJECT = 30; // 0x1e
+    field public static final int CONGESTION = 5; // 0x5
+    field public static final int CS_RESTRICTED = 22; // 0x16
+    field public static final int CS_RESTRICTED_EMERGENCY = 24; // 0x18
+    field public static final int CS_RESTRICTED_NORMAL = 23; // 0x17
+    field public static final int ERROR_UNSPECIFIED = 36; // 0x24
+    field public static final int FDN_BLOCKED = 21; // 0x15
+    field public static final int ICC_ERROR = 19; // 0x13
+    field public static final int INCOMING_MISSED = 1; // 0x1
+    field public static final int INCOMING_REJECTED = 16; // 0x10
+    field public static final int INVALID_CREDENTIALS = 10; // 0xa
+    field public static final int INVALID_NUMBER = 7; // 0x7
+    field public static final int LIMIT_EXCEEDED = 15; // 0xf
+    field public static final int LOCAL = 3; // 0x3
+    field public static final int LOST_SIGNAL = 14; // 0xe
+    field public static final int MAXIMUM_VALID_VALUE = 36; // 0x24
+    field public static final int MINIMUM_VALID_VALUE = 0; // 0x0
+    field public static final int MMI = 6; // 0x6
+    field public static final int NORMAL = 2; // 0x2
+    field public static final int NOT_DISCONNECTED = 0; // 0x0
+    field public static final int NOT_VALID = -1; // 0xffffffff
+    field public static final int NUMBER_UNREACHABLE = 8; // 0x8
+    field public static final int OUT_OF_NETWORK = 11; // 0xb
+    field public static final int OUT_OF_SERVICE = 18; // 0x12
+    field public static final int POWER_OFF = 17; // 0x11
+    field public static final int SERVER_ERROR = 12; // 0xc
+    field public static final int SERVER_UNREACHABLE = 9; // 0x9
+    field public static final int TIMED_OUT = 13; // 0xd
+    field public static final int UNOBTAINABLE_NUMBER = 25; // 0x19
+  }
+
   public class NeighboringCellInfo implements android.os.Parcelable {
     ctor public deprecated NeighboringCellInfo();
     ctor public deprecated NeighboringCellInfo(int, int);
@@ -28030,6 +29321,7 @@
     ctor public Transition();
     method public android.transition.Transition addListener(android.transition.Transition.TransitionListener);
     method public android.transition.Transition addTarget(int);
+    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 public boolean canRemoveViews();
@@ -28041,6 +29333,7 @@
     method public android.transition.Transition excludeChildren(android.view.View, boolean);
     method public android.transition.Transition excludeChildren(java.lang.Class, boolean);
     method public android.transition.Transition excludeTarget(int, boolean);
+    method public android.transition.Transition excludeTarget(java.lang.String, boolean);
     method public android.transition.Transition excludeTarget(android.view.View, boolean);
     method public android.transition.Transition excludeTarget(java.lang.Class, boolean);
     method public long getDuration();
@@ -28051,12 +29344,16 @@
     method public android.transition.TransitionPropagation getPropagation();
     method public long getStartDelay();
     method public java.util.List<java.lang.Integer> getTargetIds();
+    method public java.util.List<java.lang.Class> getTargetTypes();
+    method public java.util.List<java.lang.String> getTargetViewNames();
     method public java.util.List<android.view.View> getTargets();
     method public java.lang.String[] getTransitionProperties();
     method public android.transition.TransitionValues getTransitionValues(android.view.View, boolean);
     method public android.transition.Transition removeListener(android.transition.Transition.TransitionListener);
     method public android.transition.Transition removeTarget(int);
+    method public android.transition.Transition removeTarget(java.lang.String);
     method public android.transition.Transition removeTarget(android.view.View);
+    method public android.transition.Transition removeTarget(java.lang.Class);
     method public android.transition.Transition setDuration(long);
     method public void setEpicenterCallback(android.transition.Transition.EpicenterCallback);
     method public android.transition.Transition setInterpolator(android.animation.TimeInterpolator);
@@ -28154,11 +29451,11 @@
   }
 
   public final class TvInputManager {
-    method public void createSession(android.content.ComponentName, android.tv.TvInputManager.SessionCreateCallback, android.os.Handler);
-    method public boolean getAvailability(android.content.ComponentName);
+    method public void createSession(java.lang.String, android.tv.TvInputManager.SessionCallback, android.os.Handler);
+    method public boolean getAvailability(java.lang.String);
     method public java.util.List<android.tv.TvInputInfo> getTvInputList();
-    method public void registerListener(android.content.ComponentName, android.tv.TvInputManager.TvInputListener, android.os.Handler);
-    method public void unregisterListener(android.content.ComponentName, android.tv.TvInputManager.TvInputListener);
+    method public void registerListener(java.lang.String, android.tv.TvInputManager.TvInputListener, android.os.Handler);
+    method public void unregisterListener(java.lang.String, android.tv.TvInputManager.TvInputListener);
   }
 
   public static final class TvInputManager.Session {
@@ -28167,13 +29464,15 @@
     method public void tune(android.net.Uri);
   }
 
-  public static abstract interface TvInputManager.SessionCreateCallback {
-    method public abstract void onSessionCreated(android.tv.TvInputManager.Session);
+  public static abstract class TvInputManager.SessionCallback {
+    ctor public TvInputManager.SessionCallback();
+    method public void onSessionCreated(android.tv.TvInputManager.Session);
+    method public void onSessionReleased(android.tv.TvInputManager.Session);
   }
 
   public static abstract class TvInputManager.TvInputListener {
     ctor public TvInputManager.TvInputListener();
-    method public void onAvailabilityChanged(android.content.ComponentName, boolean);
+    method public void onAvailabilityChanged(java.lang.String, boolean);
   }
 
   public abstract class TvInputService extends android.app.Service {
@@ -28205,7 +29504,7 @@
     ctor public TvView(android.content.Context);
     ctor public TvView(android.content.Context, android.util.AttributeSet);
     ctor public TvView(android.content.Context, android.util.AttributeSet, int);
-    method public void bindTvInput(android.content.ComponentName, android.tv.TvInputManager.SessionCreateCallback);
+    method public void bindTvInput(java.lang.String, android.tv.TvInputManager.SessionCallback);
     method public boolean dispatchUnhandledInputEvent(android.view.InputEvent);
     method public boolean onUnhandledInputEvent(android.view.InputEvent);
     method public void setOnUnhandledInputEventListener(android.tv.TvView.OnUnhandledInputEventListener);
@@ -28559,6 +29858,46 @@
     method public void previousMonth();
   }
 
+  public final class MutableBoolean {
+    ctor public MutableBoolean(boolean);
+    field public boolean value;
+  }
+
+  public final class MutableByte {
+    ctor public MutableByte(byte);
+    field public byte value;
+  }
+
+  public final class MutableChar {
+    ctor public MutableChar(char);
+    field public char value;
+  }
+
+  public final class MutableDouble {
+    ctor public MutableDouble(double);
+    field public double value;
+  }
+
+  public final class MutableFloat {
+    ctor public MutableFloat(float);
+    field public float value;
+  }
+
+  public final class MutableInt {
+    ctor public MutableInt(int);
+    field public int value;
+  }
+
+  public final class MutableLong {
+    ctor public MutableLong(long);
+    field public long value;
+  }
+
+  public final class MutableShort {
+    ctor public MutableShort(short);
+    field public short value;
+  }
+
   public class NoSuchPropertyException extends java.lang.RuntimeException {
     ctor public NoSuchPropertyException(java.lang.String);
   }
@@ -28608,6 +29947,25 @@
     method public void set(T, V);
   }
 
+  public final class Range {
+    ctor public Range(T, T);
+    method public static android.util.Range<T> create(T, T);
+    method public T getLower();
+    method public T getUpper();
+  }
+
+  public final class Size {
+    ctor public Size(int, int);
+    method public int getHeight();
+    method public int getWidth();
+  }
+
+  public final class SizeF {
+    ctor public SizeF(float, float);
+    method public float getHeight();
+    method public float getWidth();
+  }
+
   public class SparseArray implements java.lang.Cloneable {
     ctor public SparseArray();
     ctor public SparseArray(int);
@@ -30105,7 +31463,7 @@
     method public boolean dispatchKeyEvent(android.view.KeyEvent);
     method public boolean dispatchKeyEventPreIme(android.view.KeyEvent);
     method public boolean dispatchKeyShortcutEvent(android.view.KeyEvent);
-    method public boolean dispatchNestedFling(float, float);
+    method public boolean dispatchNestedFling(float, float, boolean);
     method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
     method public boolean dispatchNestedScroll(int, int, int, int, int[]);
     method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
@@ -30225,8 +31583,8 @@
     method public int getScrollBarStyle();
     method public final int getScrollX();
     method public final int getScrollY();
-    method public java.lang.String getSharedElementName();
     method public int getSolidColor();
+    method public android.animation.StateListAnimator getStateListAnimator();
     method protected int getSuggestedMinimumHeight();
     method protected int getSuggestedMinimumWidth();
     method public int getSystemUiVisibility();
@@ -30245,6 +31603,7 @@
     method public int getVerticalFadingEdgeLength();
     method public int getVerticalScrollbarPosition();
     method public int getVerticalScrollbarWidth();
+    method public java.lang.String getViewName();
     method public android.view.ViewTreeObserver getViewTreeObserver();
     method public int getVisibility();
     method public final int getWidth();
@@ -30489,8 +31848,8 @@
     method public void setScrollY(int);
     method public void setScrollbarFadingEnabled(boolean);
     method public void setSelected(boolean);
-    method public void setSharedElementName(java.lang.String);
     method public void setSoundEffectsEnabled(boolean);
+    method public void setStateListAnimator(android.animation.StateListAnimator);
     method public void setSystemUiVisibility(int);
     method public void setTag(java.lang.Object);
     method public void setTag(int, java.lang.Object);
@@ -30504,6 +31863,7 @@
     method public void setVerticalFadingEdgeEnabled(boolean);
     method public void setVerticalScrollBarEnabled(boolean);
     method public void setVerticalScrollbarPosition(int);
+    method public final void setViewName(java.lang.String);
     method public void setVisibility(int);
     method public void setWillNotCacheDrawing(boolean);
     method public void setWillNotDraw(boolean);
@@ -30743,7 +32103,7 @@
     method public static int getDoubleTapTimeout();
     method public static deprecated int getEdgeSlop();
     method public static deprecated int getFadingEdgeLength();
-    method public static long getGlobalActionKeyTimeout();
+    method public static deprecated long getGlobalActionKeyTimeout();
     method public static int getJumpTapTimeout();
     method public static int getKeyRepeatDelay();
     method public static int getKeyRepeatTimeout();
@@ -30898,7 +32258,7 @@
     method public boolean onInterceptHoverEvent(android.view.MotionEvent);
     method public boolean onInterceptTouchEvent(android.view.MotionEvent);
     method protected abstract void onLayout(boolean, int, int, int, int);
-    method public boolean onNestedFling(android.view.View, float, float);
+    method public boolean onNestedFling(android.view.View, float, float, boolean);
     method public void onNestedPreScroll(android.view.View, int, int, int[]);
     method public void onNestedScroll(android.view.View, int, int, int, int);
     method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
@@ -31036,7 +32396,7 @@
     method public abstract boolean isTextAlignmentResolved();
     method public abstract boolean isTextDirectionResolved();
     method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
-    method public abstract boolean onNestedFling(android.view.View, float, float);
+    method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
     method public abstract void onNestedPreScroll(android.view.View, int, int, int[]);
     method public abstract void onNestedScroll(android.view.View, int, int, int, int);
     method public abstract void onNestedScrollAccepted(android.view.View, android.view.View, int);
@@ -31314,7 +32674,6 @@
     method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
     method public abstract boolean onSearchRequested();
     method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
-    method public abstract void onWindowDismissed();
     method public abstract void onWindowFocusChanged(boolean);
     method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
   }
@@ -31348,26 +32707,17 @@
     method public abstract void onFocusLost(android.view.WindowId);
   }
 
-  public class WindowInsets {
+  public final class WindowInsets {
     ctor public WindowInsets(android.view.WindowInsets);
-    method public android.view.WindowInsets cloneWithSystemWindowInsets(int, int, int, int);
-    method public android.view.WindowInsets cloneWithSystemWindowInsetsConsumed();
-    method public android.view.WindowInsets cloneWithSystemWindowInsetsConsumed(boolean, boolean, boolean, boolean);
-    method public android.view.WindowInsets cloneWithWindowDecorInsets(int, int, int, int);
-    method public android.view.WindowInsets cloneWithWindowDecorInsetsConsumed();
-    method public android.view.WindowInsets cloneWithWindowDecorInsetsConsumed(boolean, boolean, boolean, boolean);
+    method public android.view.WindowInsets consumeSystemWindowInsets();
     method public int getSystemWindowInsetBottom();
     method public int getSystemWindowInsetLeft();
     method public int getSystemWindowInsetRight();
     method public int getSystemWindowInsetTop();
-    method public int getWindowDecorInsetBottom();
-    method public int getWindowDecorInsetLeft();
-    method public int getWindowDecorInsetRight();
-    method public int getWindowDecorInsetTop();
     method public boolean hasInsets();
     method public boolean hasSystemWindowInsets();
-    method public boolean hasWindowDecorInsets();
     method public boolean isRound();
+    method public android.view.WindowInsets replaceSystemWindowInsets(int, int, int, int);
   }
 
   public abstract interface WindowManager implements android.view.ViewManager {
@@ -32221,6 +33571,34 @@
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
+  public final class CursorAnchorInfo implements android.os.Parcelable {
+    ctor public CursorAnchorInfo(android.os.Parcel);
+    method public int describeContents();
+    method public android.graphics.RectF getCharacterRect(int);
+    method public java.lang.String getComposingText();
+    method public int getComposingTextStart();
+    method public float getInsertionMarkerBaseline();
+    method public float getInsertionMarkerBottom();
+    method public float getInsertionMarkerHorizontal();
+    method public float getInsertionMarkerTop();
+    method public android.graphics.Matrix getMatrix();
+    method public int getSelectionEnd();
+    method public int getSelectionStart();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public static final class CursorAnchorInfo.CursorAnchorInfoBuilder {
+    ctor public CursorAnchorInfo.CursorAnchorInfoBuilder();
+    method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder addCharacterRect(int, float, float, float, float);
+    method public android.view.inputmethod.CursorAnchorInfo build();
+    method public void reset();
+    method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setComposingText(int, java.lang.CharSequence);
+    method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setInsertionMarkerLocation(float, float, float, float);
+    method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setMatrix(android.graphics.Matrix);
+    method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setSelectionRange(int, int);
+  }
+
   public class EditorInfo implements android.text.InputType android.os.Parcelable {
     ctor public EditorInfo();
     method public int describeContents();
@@ -32429,6 +33807,7 @@
     method public void toggleSoftInput(int, int);
     method public void toggleSoftInputFromWindow(android.os.IBinder, int, int);
     method public void updateCursor(android.view.View, int, int, int, int);
+    method public void updateCursorAnchorInfo(android.view.View, android.view.inputmethod.CursorAnchorInfo);
     method public void updateExtractedText(android.view.View, int, android.view.inputmethod.ExtractedText);
     method public void updateSelection(android.view.View, int, int, int, int);
     method public void viewClicked(android.view.View);
@@ -32451,6 +33830,7 @@
     method public abstract void finishInput();
     method public abstract void toggleSoftInput(int, int);
     method public abstract void updateCursor(android.graphics.Rect);
+    method public abstract void updateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo);
     method public abstract void updateExtractedText(int, android.view.inputmethod.ExtractedText);
     method public abstract void updateSelection(int, int, int, int, int, int);
     method public abstract void viewClicked(boolean);
@@ -32591,6 +33971,16 @@
 
 package android.webkit {
 
+  public abstract interface ClientCertRequest {
+    method public abstract void cancel();
+    method public abstract java.lang.String getHost();
+    method public abstract java.lang.String[] getKeyTypes();
+    method public abstract int getPort();
+    method public abstract java.security.Principal[] getPrincipals();
+    method public abstract void ignore();
+    method public abstract void proceed(java.security.PrivateKey, java.security.cert.X509Certificate[]);
+  }
+
   public class ConsoleMessage {
     ctor public ConsoleMessage(java.lang.String, java.lang.String, int, android.webkit.ConsoleMessage.MessageLevel);
     method public int lineNumber();
@@ -32684,6 +34074,15 @@
     method public boolean hasMimeType(java.lang.String);
   }
 
+  public abstract interface PermissionRequest {
+    method public abstract void deny();
+    method public abstract android.net.Uri getOrigin();
+    method public abstract long getResources();
+    method public abstract void grant(long);
+    field public static final long RESOURCE_AUDIO_CAPTURE = 4L; // 0x4L
+    field public static final long RESOURCE_VIDEO_CAPTURE = 2L; // 0x2L
+  }
+
   public abstract interface PluginStub {
     method public abstract android.view.View getEmbeddedView(int, android.content.Context);
     method public abstract android.view.View getFullScreenView(int, android.content.Context);
@@ -32743,6 +34142,8 @@
     method public boolean onJsConfirm(android.webkit.WebView, java.lang.String, java.lang.String, android.webkit.JsResult);
     method public boolean onJsPrompt(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String, android.webkit.JsPromptResult);
     method public deprecated boolean onJsTimeout();
+    method public void onPermissionRequest(android.webkit.PermissionRequest);
+    method public void onPermissionRequestCanceled(android.webkit.PermissionRequest);
     method public void onProgressChanged(android.webkit.WebView, int);
     method public deprecated void onReachedMaxAppCacheSize(long, long, android.webkit.WebStorage.QuotaUpdater);
     method public void onReceivedIcon(android.webkit.WebView, android.graphics.Bitmap);
@@ -32819,6 +34220,7 @@
     method public boolean getMediaPlaybackRequiresUserGesture();
     method public synchronized int getMinimumFontSize();
     method public synchronized int getMinimumLogicalFontSize();
+    method public abstract int getMixedContentMode();
     method public deprecated synchronized android.webkit.WebSettings.PluginState getPluginState();
     method public synchronized java.lang.String getSansSerifFontFamily();
     method public boolean getSaveFormData();
@@ -32863,6 +34265,7 @@
     method public void setMediaPlaybackRequiresUserGesture(boolean);
     method public synchronized void setMinimumFontSize(int);
     method public synchronized void setMinimumLogicalFontSize(int);
+    method public abstract void setMixedContentMode(int);
     method public void setNeedInitialFocus(boolean);
     method public deprecated synchronized void setPluginState(android.webkit.WebSettings.PluginState);
     method public deprecated synchronized void setRenderPriority(android.webkit.WebSettings.RenderPriority);
@@ -32884,6 +34287,9 @@
     field public static final int LOAD_DEFAULT = -1; // 0xffffffff
     field public static final deprecated int LOAD_NORMAL = 0; // 0x0
     field public static final int LOAD_NO_CACHE = 2; // 0x2
+    field public static final int MIXED_CONTENT_ALWAYS_ALLOW = 0; // 0x0
+    field public static final int MIXED_CONTENT_COMPATIBILITY_MODE = 2; // 0x2
+    field public static final int MIXED_CONTENT_NEVER_ALLOW = 1; // 0x1
   }
 
   public static final class WebSettings.LayoutAlgorithm extends java.lang.Enum {
@@ -32976,6 +34382,7 @@
     method public deprecated boolean canZoomOut();
     method public deprecated android.graphics.Picture capturePicture();
     method public void clearCache(boolean);
+    method public static void clearClientCertPreferences(java.lang.Runnable);
     method public void clearFormData();
     method public void clearHistory();
     method public void clearMatches();
@@ -33024,6 +34431,7 @@
     method public boolean pageUp(boolean);
     method public void pauseTimers();
     method public void postUrl(java.lang.String, byte[]);
+    method public void preauthorizePermission(android.net.Uri, long);
     method public void reload();
     method public void removeJavascriptInterface(java.lang.String);
     method public void requestFocusNodeHref(android.os.Message);
@@ -33092,13 +34500,15 @@
     method public void onLoadResource(android.webkit.WebView, java.lang.String);
     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 void onReceivedHttpAuthRequest(android.webkit.WebView, android.webkit.HttpAuthHandler, java.lang.String, java.lang.String);
     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);
     method public deprecated void onTooManyRedirects(android.webkit.WebView, android.os.Message, android.os.Message);
-    method public void onUnhandledKeyEvent(android.webkit.WebView, android.view.KeyEvent);
+    method public void onUnhandledInputEvent(android.webkit.WebView, android.view.InputEvent);
+    method public deprecated void onUnhandledKeyEvent(android.webkit.WebView, android.view.KeyEvent);
     method public android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebView, java.lang.String);
     method public boolean shouldOverrideKeyEvent(android.webkit.WebView, android.view.KeyEvent);
     method public boolean shouldOverrideUrlLoading(android.webkit.WebView, java.lang.String);
@@ -33260,9 +34670,11 @@
     ctor public AbsSeekBar(android.content.Context, android.util.AttributeSet, int);
     ctor public AbsSeekBar(android.content.Context, android.util.AttributeSet, int, int);
     method public int getKeyProgressIncrement();
+    method public boolean getSplitTrack();
     method public android.graphics.drawable.Drawable getThumb();
     method public int getThumbOffset();
     method public void setKeyProgressIncrement(int);
+    method public void setSplitTrack(boolean);
     method public void setThumb(android.graphics.drawable.Drawable);
     method public void setThumbOffset(int);
   }
@@ -33799,9 +35211,11 @@
     ctor public EdgeEffect(android.content.Context);
     method public boolean draw(android.graphics.Canvas);
     method public void finish();
+    method public int getMaxHeight();
     method public boolean isFinished();
     method public void onAbsorb(int);
     method public void onPull(float);
+    method public void onPull(float, float);
     method public void onRelease();
     method public void setSize(int, int);
   }
@@ -35065,6 +36479,7 @@
     ctor public Switch(android.content.Context, android.util.AttributeSet);
     ctor public Switch(android.content.Context, android.util.AttributeSet, int);
     ctor public Switch(android.content.Context, android.util.AttributeSet, int, int);
+    method public boolean getSplitTrack();
     method public int getSwitchMinWidth();
     method public int getSwitchPadding();
     method public java.lang.CharSequence getTextOff();
@@ -35073,6 +36488,7 @@
     method public int getThumbTextPadding();
     method public android.graphics.drawable.Drawable getTrackDrawable();
     method public void onMeasure(int, int);
+    method public void setSplitTrack(boolean);
     method public void setSwitchMinWidth(int);
     method public void setSwitchPadding(int);
     method public void setSwitchTextAppearance(android.content.Context, int);
@@ -39474,11 +40890,13 @@
     method public java.lang.String getValue();
     method public int getVersion();
     method public boolean hasExpired();
+    method public boolean isHttpOnly();
     method public static java.util.List<java.net.HttpCookie> parse(java.lang.String);
     method public void setComment(java.lang.String);
     method public void setCommentURL(java.lang.String);
     method public void setDiscard(boolean);
     method public void setDomain(java.lang.String);
+    method public void setHttpOnly(boolean);
     method public void setMaxAge(long);
     method public void setPath(java.lang.String);
     method public void setPortlist(java.lang.String);
@@ -40431,7 +41849,7 @@
     ctor public ConnectionPendingException();
   }
 
-  public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel {
+  public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.MulticastChannel java.nio.channels.ScatteringByteChannel {
     ctor protected DatagramChannel(java.nio.channels.spi.SelectorProvider);
     method public java.nio.channels.DatagramChannel bind(java.net.SocketAddress) throws java.io.IOException;
     method public abstract java.nio.channels.DatagramChannel connect(java.net.SocketAddress) throws java.io.IOException;
@@ -40439,6 +41857,8 @@
     method public java.net.SocketAddress getLocalAddress() throws java.io.IOException;
     method public T getOption(java.net.SocketOption<T>) throws java.io.IOException;
     method public abstract boolean isConnected();
+    method public java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface) throws java.io.IOException;
+    method public java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface, java.net.InetAddress) throws java.io.IOException;
     method public static java.nio.channels.DatagramChannel open() throws java.io.IOException;
     method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
     method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
@@ -40486,6 +41906,7 @@
 
   public abstract class FileLock implements java.lang.AutoCloseable {
     ctor protected FileLock(java.nio.channels.FileChannel, long, long, boolean);
+    method public java.nio.channels.Channel acquiredBy();
     method public final java.nio.channels.FileChannel channel();
     method public final void close() throws java.io.IOException;
     method public final boolean isShared();
@@ -40518,6 +41939,24 @@
     method public abstract void close() throws java.io.IOException;
   }
 
+  public abstract class MembershipKey {
+    ctor protected MembershipKey();
+    method public abstract java.nio.channels.MembershipKey block(java.net.InetAddress) throws java.io.IOException;
+    method public abstract java.nio.channels.MulticastChannel channel();
+    method public abstract void drop();
+    method public abstract java.net.InetAddress group();
+    method public abstract boolean isValid();
+    method public abstract java.net.NetworkInterface networkInterface();
+    method public abstract java.net.InetAddress sourceAddress();
+    method public abstract java.nio.channels.MembershipKey unblock(java.net.InetAddress);
+  }
+
+  public abstract interface MulticastChannel implements java.nio.channels.NetworkChannel {
+    method public abstract void close() throws java.io.IOException;
+    method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface) throws java.io.IOException;
+    method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface, java.net.InetAddress) throws java.io.IOException;
+  }
+
   public abstract interface NetworkChannel implements java.lang.AutoCloseable java.nio.channels.Channel java.io.Closeable {
     method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
     method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
@@ -44623,6 +46062,7 @@
     method public java.lang.String getDisplayName(java.util.Locale);
     method public static java.util.Currency getInstance(java.lang.String);
     method public static java.util.Currency getInstance(java.util.Locale);
+    method public int getNumericCode();
     method public java.lang.String getSymbol();
     method public java.lang.String getSymbol(java.util.Locale);
   }
@@ -47705,8 +49145,10 @@
 
   public class ZipFile implements java.io.Closeable {
     ctor public ZipFile(java.io.File) throws java.io.IOException, java.util.zip.ZipException;
+    ctor public ZipFile(java.io.File, java.nio.charset.Charset) throws java.io.IOException, java.util.zip.ZipException;
     ctor public ZipFile(java.lang.String) throws java.io.IOException;
     ctor public ZipFile(java.io.File, int) throws java.io.IOException;
+    ctor public ZipFile(java.io.File, int, java.nio.charset.Charset) throws java.io.IOException;
     method public void close() throws java.io.IOException;
     method public java.util.Enumeration<? extends java.util.zip.ZipEntry> entries();
     method public java.lang.String getComment();
@@ -47760,6 +49202,7 @@
 
   public class ZipInputStream extends java.util.zip.InflaterInputStream {
     ctor public ZipInputStream(java.io.InputStream);
+    ctor public ZipInputStream(java.io.InputStream, java.nio.charset.Charset);
     method public void closeEntry() throws java.io.IOException;
     method protected java.util.zip.ZipEntry createZipEntry(java.lang.String);
     method public java.util.zip.ZipEntry getNextEntry() throws java.io.IOException;
@@ -47807,6 +49250,7 @@
 
   public class ZipOutputStream extends java.util.zip.DeflaterOutputStream {
     ctor public ZipOutputStream(java.io.OutputStream);
+    ctor public ZipOutputStream(java.io.OutputStream, java.nio.charset.Charset);
     method public void closeEntry() throws java.io.IOException;
     method public void putNextEntry(java.util.zip.ZipEntry) throws java.io.IOException;
     method public void setComment(java.lang.String);
@@ -49305,6 +50749,7 @@
     method public abstract boolean getEnableSessionCreation();
     method public abstract java.lang.String[] getEnabledCipherSuites();
     method public abstract java.lang.String[] getEnabledProtocols();
+    method public javax.net.ssl.SSLSession getHandshakeSession();
     method public abstract javax.net.ssl.SSLEngineResult.HandshakeStatus getHandshakeStatus();
     method public abstract boolean getNeedClientAuth();
     method public java.lang.String getPeerHost();
@@ -49378,10 +50823,12 @@
     ctor public SSLParameters(java.lang.String[]);
     ctor public SSLParameters(java.lang.String[], java.lang.String[]);
     method public java.lang.String[] getCipherSuites();
+    method public java.lang.String getEndpointIdentificationAlgorithm();
     method public boolean getNeedClientAuth();
     method public java.lang.String[] getProtocols();
     method public boolean getWantClientAuth();
     method public void setCipherSuites(java.lang.String[]);
+    method public void setEndpointIdentificationAlgorithm(java.lang.String);
     method public void setNeedClientAuth(boolean);
     method public void setProtocols(java.lang.String[]);
     method public void setWantClientAuth(boolean);
@@ -49482,6 +50929,7 @@
     method public abstract boolean getEnableSessionCreation();
     method public abstract java.lang.String[] getEnabledCipherSuites();
     method public abstract java.lang.String[] getEnabledProtocols();
+    method public javax.net.ssl.SSLSession getHandshakeSession();
     method public abstract boolean getNeedClientAuth();
     method public javax.net.ssl.SSLParameters getSSLParameters();
     method public abstract javax.net.ssl.SSLSession getSession();
@@ -49537,6 +50985,14 @@
     method public java.lang.String chooseEngineServerAlias(java.lang.String, java.security.Principal[], javax.net.ssl.SSLEngine);
   }
 
+  public abstract class X509ExtendedTrustManager implements javax.net.ssl.X509TrustManager {
+    ctor public X509ExtendedTrustManager();
+    method public abstract void checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String, java.net.Socket) throws java.security.cert.CertificateException;
+    method public abstract void checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException;
+    method public abstract void checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String, java.net.Socket) throws java.security.cert.CertificateException;
+    method public abstract void checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException;
+  }
+
   public abstract interface X509KeyManager implements javax.net.ssl.KeyManager {
     method public abstract java.lang.String chooseClientAlias(java.lang.String[], java.security.Principal[], java.net.Socket);
     method public abstract java.lang.String chooseServerAlias(java.lang.String, java.security.Principal[], java.net.Socket);
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 391c197..74ccbc2 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -145,7 +145,7 @@
     static const char kInstructionSet[] = "x86_64";
 #elif defined(__arm__)
     static const char kInstructionSet[] = "arm";
-#elif defined(__x86__)
+#elif defined(__i386__)
     static const char kInstructionSet[] = "x86";
 #elif defined (__mips__)
     static const char kInstructionSet[] = "mips";
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 1780e03..3dc024e 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -156,12 +156,12 @@
     return NO_ERROR;
 }
 
-status_t BootAnimation::initTexture(void* buffer, size_t len)
+status_t BootAnimation::initTexture(const Animation::Frame& frame)
 {
     //StopWatch watch("blah");
 
     SkBitmap bitmap;
-    SkMemoryStream  stream(buffer, len);
+    SkMemoryStream  stream(frame.map->getDataPtr(), frame.map->getDataLength());
     SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
     if (codec) {
         codec->setDitherImage(false);
@@ -171,6 +171,11 @@
         delete codec;
     }
 
+    // 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();
+
     // ensure we can call getPixels(). No need to call unlock, since the
     // bitmap will go out of scope when we return from this method.
     bitmap.lockPixels();
@@ -409,6 +414,7 @@
 
     String8 desString((char const*)descMap->getDataPtr(),
             descMap->getDataLength());
+    descMap->release();
     char const* s = desString.string();
 
     Animation animation;
@@ -533,9 +539,7 @@
                         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
                     }
-                    initTexture(
-                            frame.map->getDataPtr(),
-                            frame.map->getDataLength());
+                    initTexture(frame);
                 }
 
                 if (!clearReg.isEmpty()) {
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 22963c2..ba1c507 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -79,7 +79,7 @@
     };
 
     status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
-    status_t initTexture(void* buffer, size_t len);
+    status_t initTexture(const Animation::Frame& frame);
     bool android();
     bool movie();
 
diff --git a/cmds/svc/src/com/android/commands/svc/DataCommand.java b/cmds/svc/src/com/android/commands/svc/DataCommand.java
index 72cb86d..406e33b 100644
--- a/cmds/svc/src/com/android/commands/svc/DataCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/DataCommand.java
@@ -36,9 +36,7 @@
         return shortHelp() + "\n"
                 + "\n"
                 + "usage: svc data [enable|disable]\n"
-                + "         Turn mobile data on or off.\n\n"
-                + "       svc data prefer\n"
-                + "          Set mobile as the preferred data network\n";
+                + "         Turn mobile data on or off.\n\n";
     }
 
     public void run(String[] args) {
@@ -51,15 +49,6 @@
             } else if ("disable".equals(args[1])) {
                 flag = false;
                 validCommand = true;
-            } else if ("prefer".equals(args[1])) {
-                IConnectivityManager connMgr =
-                        IConnectivityManager.Stub.asInterface(ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
-                try {
-                    connMgr.setNetworkPreference(ConnectivityManager.TYPE_MOBILE);
-                } catch (RemoteException e) {
-                    System.err.println("Failed to set preferred network: " + e);
-                }
-                return;
             }
             if (validCommand) {
                 ITelephony phoneMgr
@@ -78,4 +67,4 @@
         }
         System.err.println(longHelp());
     }
-}
\ No newline at end of file
+}
diff --git a/cmds/svc/src/com/android/commands/svc/WifiCommand.java b/cmds/svc/src/com/android/commands/svc/WifiCommand.java
index d29e8b2..39f0e35 100644
--- a/cmds/svc/src/com/android/commands/svc/WifiCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/WifiCommand.java
@@ -36,9 +36,7 @@
         return shortHelp() + "\n"
                 + "\n"
                 + "usage: svc wifi [enable|disable]\n"
-                + "         Turn Wi-Fi on or off.\n\n"
-                + "       svc wifi prefer\n"
-                + "          Set Wi-Fi as the preferred data network\n";
+                + "         Turn Wi-Fi on or off.\n\n";
     }
 
     public void run(String[] args) {
@@ -51,15 +49,6 @@
             } else if ("disable".equals(args[1])) {
                 flag = false;
                 validCommand = true;
-            } else if ("prefer".equals(args[1])) {
-                IConnectivityManager connMgr =
-                        IConnectivityManager.Stub.asInterface(ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
-                try {
-                    connMgr.setNetworkPreference(ConnectivityManager.TYPE_WIFI);
-                } catch (RemoteException e) {
-                    System.err.println("Failed to set preferred network: " + e);
-                }
-                return;
             }
             if (validCommand) {
                 IWifiManager wifiMgr
@@ -75,4 +64,4 @@
         }
         System.err.println(longHelp());
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index 20236aa..933135d 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -21,6 +21,7 @@
 import android.content.res.XmlResourceParser;
 import android.content.res.Resources.NotFoundException;
 import android.util.AttributeSet;
+import android.util.StateSet;
 import android.util.TypedValue;
 import android.util.Xml;
 import android.view.animation.AnimationUtils;
@@ -87,9 +88,86 @@
         }
     }
 
+    public static StateListAnimator loadStateListAnimator(Context context, int id)
+            throws NotFoundException {
+        XmlResourceParser parser = null;
+        try {
+            parser = context.getResources().getAnimation(id);
+            return createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser));
+        } catch (XmlPullParserException ex) {
+            Resources.NotFoundException rnf =
+                    new Resources.NotFoundException(
+                            "Can't load state list animator resource ID #0x" +
+                                    Integer.toHexString(id)
+                    );
+            rnf.initCause(ex);
+            throw rnf;
+        } catch (IOException ex) {
+            Resources.NotFoundException rnf =
+                    new Resources.NotFoundException(
+                            "Can't load state list animator resource ID #0x" +
+                                    Integer.toHexString(id)
+                    );
+            rnf.initCause(ex);
+            throw rnf;
+        } finally {
+            if (parser != null) {
+                parser.close();
+            }
+        }
+    }
+
+    private static StateListAnimator createStateListAnimatorFromXml(Context context,
+            XmlPullParser parser, AttributeSet attributeSet)
+            throws IOException, XmlPullParserException {
+        int type;
+        StateListAnimator stateListAnimator = new StateListAnimator();
+
+        while (true) {
+            type = parser.next();
+            switch (type) {
+                case XmlPullParser.END_DOCUMENT:
+                case XmlPullParser.END_TAG:
+                    return stateListAnimator;
+
+                case XmlPullParser.START_TAG:
+                    // parse item
+                    Animator animator = null;
+                    if ("item".equals(parser.getName())) {
+                        int attributeCount = parser.getAttributeCount();
+                        int[] states = new int[attributeCount];
+                        int stateIndex = 0;
+                        for (int i = 0; i < attributeCount; i++) {
+                            int attrName = attributeSet.getAttributeNameResource(i);
+                            if (attrName == com.android.internal.R.attr.animation) {
+                                animator = loadAnimator(context,
+                                        attributeSet.getAttributeResourceValue(i, 0));
+                            } else {
+                                states[stateIndex++] =
+                                        attributeSet.getAttributeBooleanValue(i, false) ?
+                                                attrName : -attrName;
+                            }
+
+                        }
+                        if (animator == null) {
+                            animator = createAnimatorFromXml(context, parser);
+                        }
+
+                        if (animator == null) {
+                            throw new Resources.NotFoundException(
+                                    "animation state item must have a valid animation");
+                        }
+                        stateListAnimator
+                                .addState(StateSet.trimStateSet(states, stateIndex), animator);
+
+                    }
+                    break;
+            }
+        }
+    }
+
     private static Animator createAnimatorFromXml(Context c, XmlPullParser parser)
             throws XmlPullParserException, IOException {
-
         return createAnimatorFromXml(c, parser, Xml.asAttributeSet(parser), null, 0);
     }
 
diff --git a/core/java/android/animation/StateListAnimator.java b/core/java/android/animation/StateListAnimator.java
new file mode 100644
index 0000000..bc4843d
--- /dev/null
+++ b/core/java/android/animation/StateListAnimator.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.animation;
+
+import android.util.StateSet;
+import android.view.View;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+/**
+ * Lets you define a number of Animators that will run on the attached View depending on the View's
+ * drawable state.
+ * <p>
+ * It can be defined in an XML file with the <code>&lt;selector></code> element.
+ * Each State Animator is defined in a nested <code>&lt;item></code> element.
+ *
+ * @attr ref android.R.styleable#DrawableStates_state_focused
+ * @attr ref android.R.styleable#DrawableStates_state_window_focused
+ * @attr ref android.R.styleable#DrawableStates_state_enabled
+ * @attr ref android.R.styleable#DrawableStates_state_checkable
+ * @attr ref android.R.styleable#DrawableStates_state_checked
+ * @attr ref android.R.styleable#DrawableStates_state_selected
+ * @attr ref android.R.styleable#DrawableStates_state_activated
+ * @attr ref android.R.styleable#DrawableStates_state_active
+ * @attr ref android.R.styleable#DrawableStates_state_single
+ * @attr ref android.R.styleable#DrawableStates_state_first
+ * @attr ref android.R.styleable#DrawableStates_state_middle
+ * @attr ref android.R.styleable#DrawableStates_state_last
+ * @attr ref android.R.styleable#DrawableStates_state_pressed
+ * @attr ref android.R.styleable#StateListAnimatorItem_animation
+ */
+public class StateListAnimator {
+
+    private final ArrayList<Tuple> mTuples = new ArrayList<Tuple>();
+
+    private Tuple mLastMatch = null;
+
+    private Animator mRunningAnimator = null;
+
+    private WeakReference<View> mViewRef;
+
+    private AnimatorListenerAdapter mAnimatorListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            if (mRunningAnimator == animation) {
+                mRunningAnimator = null;
+            }
+        }
+    };
+
+    /**
+     * Associates the given animator with the provided drawable state specs so that it will be run
+     * when the View's drawable state matches the specs.
+     *
+     * @param specs The drawable state specs to match against
+     * @param animator The animator to run when the specs match
+     */
+    public void addState(int[] specs, Animator animator) {
+        Tuple tuple = new Tuple(specs, animator);
+        tuple.mAnimator.addListener(mAnimatorListener);
+        mTuples.add(tuple);
+    }
+
+    /**
+     * Returns the current {@link android.animation.Animator} which is started because of a state
+     * change.
+     *
+     * @return The currently running Animator or null if no Animator is running
+     * @hide
+     */
+    public Animator getRunningAnimator() {
+        return mRunningAnimator;
+    }
+
+    /**
+     * @hide
+     */
+    public View getTarget() {
+        return mViewRef == null ? null : mViewRef.get();
+    }
+
+    /**
+     * Called by View
+     * @hide
+     */
+    public void setTarget(View view) {
+        final View current = getTarget();
+        if (current == view) {
+            return;
+        }
+        if (current != null) {
+            clearTarget();
+        }
+        if (view != null) {
+            mViewRef = new WeakReference<View>(view);
+        }
+
+    }
+
+    private void clearTarget() {
+        final int size = mTuples.size();
+        for (int i = 0; i < size; i++) {
+            mTuples.get(i).mAnimator.setTarget(null);
+        }
+
+        mViewRef = null;
+        mLastMatch = null;
+        mRunningAnimator = null;
+    }
+
+    /**
+     * Called by View
+     * @hide
+     */
+    public void setState(int[] state) {
+        Tuple match = null;
+        final int count = mTuples.size();
+        for (int i = 0; i < count; i++) {
+            final Tuple tuple = mTuples.get(i);
+            if (StateSet.stateSetMatches(tuple.mSpecs, state)) {
+                match = tuple;
+                break;
+            }
+        }
+        if (match == mLastMatch) {
+            return;
+        }
+        if (mLastMatch != null) {
+            cancel(mLastMatch);
+        }
+        mLastMatch = match;
+        if (match != null) {
+            start(match);
+        }
+    }
+
+    private void start(Tuple match) {
+        match.mAnimator.setTarget(getTarget());
+        mRunningAnimator = match.mAnimator;
+        match.mAnimator.start();
+    }
+
+    private void cancel(Tuple lastMatch) {
+        lastMatch.mAnimator.cancel();
+        lastMatch.mAnimator.setTarget(null);
+    }
+
+    /**
+     * @hide
+     */
+    public ArrayList<Tuple> getTuples() {
+        return mTuples;
+    }
+
+    /**
+     * If there is an animation running for a recent state change, ends it.
+     * <p>
+     * This causes the animation to assign the end value(s) to the View.
+     */
+    public void jumpToCurrentState() {
+        if (mRunningAnimator != null) {
+            mRunningAnimator.end();
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public static class Tuple {
+
+        final int[] mSpecs;
+
+        final Animator mAnimator;
+
+        private Tuple(int[] specs, Animator animator) {
+            mSpecs = specs;
+            mAnimator = animator;
+        }
+
+        /**
+         * @hide
+         */
+        public int[] getSpecs() {
+            return mSpecs;
+        }
+
+        /**
+         * @hide
+         */
+        public Animator getAnimator() {
+            return mAnimator;
+        }
+    }
+}
diff --git a/core/java/android/animation/TypeEvaluator.java b/core/java/android/animation/TypeEvaluator.java
index 2640457..429c435 100644
--- a/core/java/android/animation/TypeEvaluator.java
+++ b/core/java/android/animation/TypeEvaluator.java
@@ -29,7 +29,7 @@
     /**
      * This function returns the result of linearly interpolating the start and end values, with
      * <code>fraction</code> representing the proportion between the start and end values. The
-     * calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
+     * calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>,
      * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
      * and <code>t</code> is <code>fraction</code>.
      *
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 04f62e3..3c3df01 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -932,6 +932,66 @@
      */
     public void setHomeActionContentDescription(int resId) { }
 
+    /**
+     * Enable hiding the action bar on content scroll.
+     *
+     * <p>If enabled, the action bar will scroll out of sight along with a
+     * {@link View#setNestedScrollingEnabled(boolean) nested scrolling child} view's content.
+     * The action bar must be in {@link Window#FEATURE_ACTION_BAR_OVERLAY overlay mode}
+     * to enable hiding on content scroll.</p>
+     *
+     * <p>When partially scrolled off screen the action bar is considered
+     * {@link #hide() hidden}. A call to {@link #show() show} will cause it to return to full view.
+     * </p>
+     * @param hideOnContentScroll true to enable hiding on content scroll.
+     */
+    public void setHideOnContentScrollEnabled(boolean hideOnContentScroll) {
+        if (hideOnContentScroll) {
+            throw new UnsupportedOperationException("Hide on content scroll is not supported in " +
+                    "this action bar configuration.");
+        }
+    }
+
+    /**
+     * Return whether the action bar is configured to scroll out of sight along with
+     * a {@link View#setNestedScrollingEnabled(boolean) nested scrolling child}.
+     *
+     * @return true if hide-on-content-scroll is enabled
+     * @see #setHideOnContentScrollEnabled(boolean)
+     */
+    public boolean isHideOnContentScrollEnabled() {
+        return false;
+    }
+
+    /**
+     * Return the current vertical offset of the action bar.
+     *
+     * <p>The action bar's current hide offset is the distance that the action bar is currently
+     * scrolled offscreen in pixels. The valid range is 0 (fully visible) to the action bar's
+     * current measured {@link #getHeight() height} (fully invisible).</p>
+     *
+     * @return The action bar's offset toward its fully hidden state in pixels
+     */
+    public int getHideOffset() {
+        return 0;
+    }
+
+    /**
+     * Set the current hide offset of the action bar.
+     *
+     * <p>The action bar's current hide offset is the distance that the action bar is currently
+     * scrolled offscreen in pixels. The valid range is 0 (fully visible) to the action bar's
+     * current measured {@link #getHeight() height} (fully invisible).</p>
+     *
+     * @param offset The action bar's offset toward its fully hidden state in pixels.
+     */
+    public void setHideOffset(int offset) {
+        if (offset != 0) {
+            throw new UnsupportedOperationException("Setting an explicit action bar hide offset " +
+                    "is not supported in this action bar configuration.");
+        }
+    }
+
     /** @hide */
     public void setDefaultDisplayHomeAsUpEnabled(boolean enabled) {
     }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 8981c88..4a30b05 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.annotation.NonNull;
+import android.os.PersistableBundle;
 import android.transition.Scene;
 import android.transition.TransitionManager;
 import android.util.ArrayMap;
@@ -655,7 +656,8 @@
 public class Activity extends ContextThemeWrapper
         implements LayoutInflater.Factory2,
         Window.Callback, KeyEvent.Callback,
-        OnCreateContextMenuListener, ComponentCallbacks2 {
+        OnCreateContextMenuListener, ComponentCallbacks2,
+        Window.OnWindowDismissedCallback {
     private static final String TAG = "Activity";
     private static final boolean DEBUG_LIFECYCLE = false;
 
@@ -920,6 +922,30 @@
     }
 
     /**
+     * Same as {@link #onCreate(android.os.Bundle)} but called for those activities created with
+     * the attribute {@link android.R.attr#persistable} set true.
+     *
+     * @param savedInstanceState if the activity is being re-initialized after
+     *     previously being shut down then this Bundle contains the data it most
+     *     recently supplied in {@link #onSaveInstanceState}.
+     *     <b><i>Note: Otherwise it is null.</i></b>
+     * @param persistentState if the activity is being re-initialized after
+     *     previously being shut down or powered off then this Bundle contains the data it most
+     *     recently supplied to outPersistentState in {@link #onSaveInstanceState}.
+     *     <b><i>Note: Otherwise it is null.</i></b>
+     *
+     * @see #onCreate(android.os.Bundle)
+     * @see #onStart
+     * @see #onSaveInstanceState
+     * @see #onRestoreInstanceState
+     * @see #onPostCreate
+     */
+    protected void onCreate(@Nullable Bundle savedInstanceState,
+            @Nullable PersistableBundle persistentState) {
+        onCreate(savedInstanceState);
+    }
+
+    /**
      * The hook for {@link ActivityThread} to restore the state of this activity.
      *
      * Calls {@link #onSaveInstanceState(android.os.Bundle)} and
@@ -933,6 +959,23 @@
     }
 
     /**
+     * The hook for {@link ActivityThread} to restore the state of this activity.
+     *
+     * Calls {@link #onSaveInstanceState(android.os.Bundle)} and
+     * {@link #restoreManagedDialogs(android.os.Bundle)}.
+     *
+     * @param savedInstanceState contains the saved state
+     * @param persistentState contains the persistable saved state
+     */
+    final void performRestoreInstanceState(Bundle savedInstanceState,
+            PersistableBundle persistentState) {
+        onRestoreInstanceState(savedInstanceState, persistentState);
+        if (savedInstanceState != null) {
+            restoreManagedDialogs(savedInstanceState);
+        }
+    }
+
+    /**
      * This method is called after {@link #onStart} when the activity is
      * being re-initialized from a previously saved state, given here in
      * <var>savedInstanceState</var>.  Most implementations will simply use {@link #onCreate}
@@ -960,7 +1003,34 @@
             }
         }
     }
-    
+
+    /**
+     * This is the same as {@link #onRestoreInstanceState(Bundle)} but is called for activities
+     * created with the attribute {@link android.R.attr#persistable}. The {@link
+     * android.os.PersistableBundle} passed came from the restored PersistableBundle first
+     * saved in {@link #onSaveInstanceState(Bundle, PersistableBundle)}.
+     *
+     * <p>This method is called between {@link #onStart} and
+     * {@link #onPostCreate}.
+     *
+     * <p>If this method is called {@link #onRestoreInstanceState(Bundle)} will not be called.
+     *
+     * @param savedInstanceState the data most recently supplied in {@link #onSaveInstanceState}.
+     * @param persistentState the data most recently supplied in {@link #onSaveInstanceState}.
+     *
+     * @see #onRestoreInstanceState(Bundle)
+     * @see #onCreate
+     * @see #onPostCreate
+     * @see #onResume
+     * @see #onSaveInstanceState
+     */
+    protected void onRestoreInstanceState(Bundle savedInstanceState,
+            PersistableBundle persistentState) {
+        if (savedInstanceState != null) {
+            onRestoreInstanceState(savedInstanceState);
+        }
+    }
+
     /**
      * Restore the state of any saved managed dialogs.
      *
@@ -1037,6 +1107,21 @@
     }
 
     /**
+     * This is the same as {@link #onPostCreate(Bundle)} but is called for activities
+     * created with the attribute {@link android.R.attr#persistable}.
+     *
+     * @param savedInstanceState The data most recently supplied in {@link #onSaveInstanceState}
+     * @param persistentState The data caming from the PersistableBundle first
+     * saved in {@link #onSaveInstanceState(Bundle, PersistableBundle)}.
+     *
+     * @see #onCreate
+     */
+    protected void onPostCreate(@Nullable Bundle savedInstanceState,
+            @Nullable PersistableBundle persistentState) {
+        onPostCreate(savedInstanceState);
+    }
+
+    /**
      * Called after {@link #onCreate} &mdash; or after {@link #onRestart} when  
      * the activity had been stopped, but is now again being displayed to the 
      * user.  It will be followed by {@link #onResume}.
@@ -1064,6 +1149,12 @@
         }
 
         getApplication().dispatchActivityStarted(this);
+
+        final ActivityOptions activityOptions = getActivityOptions();
+        if (activityOptions != null &&
+                activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
+            mEnterTransitionCoordinator = activityOptions.createEnterActivityTransition(this);
+        }
     }
 
     /**
@@ -1192,6 +1283,22 @@
     }
 
     /**
+     * The hook for {@link ActivityThread} to save the state of this activity.
+     *
+     * Calls {@link #onSaveInstanceState(android.os.Bundle)}
+     * and {@link #saveManagedDialogs(android.os.Bundle)}.
+     *
+     * @param outState The bundle to save the state to.
+     * @param outPersistentState The bundle to save persistent state to.
+     */
+    final void performSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
+        onSaveInstanceState(outState, outPersistentState);
+        saveManagedDialogs(outState);
+        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState +
+                ", " + outPersistentState);
+    }
+
+    /**
      * Called to retrieve per-instance state from an activity before being killed
      * so that the state can be restored in {@link #onCreate} or
      * {@link #onRestoreInstanceState} (the {@link Bundle} populated by this method
@@ -1246,6 +1353,25 @@
     }
 
     /**
+     * This is the same as {@link #onSaveInstanceState} but is called for activities
+     * created with the attribute {@link android.R.attr#persistable}. The {@link
+     * android.os.PersistableBundle} passed in will be saved and presented in
+     * {@link #onCreate(Bundle, PersistableBundle)} the first time that this activity
+     * is restarted following the next device reboot.
+     *
+     * @param outState Bundle in which to place your saved state.
+     * @param outPersistentState State which will be saved across reboots.
+     *
+     * @see #onSaveInstanceState(Bundle)
+     * @see #onCreate
+     * @see #onRestoreInstanceState(Bundle, PersistableBundle)
+     * @see #onPause
+     */
+    protected void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
+        onSaveInstanceState(outState);
+    }
+
+    /**
      * Save the state of any managed dialogs.
      *
      * @param outState place to store the saved state.
@@ -2519,7 +2645,9 @@
 
     /**
      * Called when the main window associated with the activity has been dismissed.
+     * @hide
      */
+    @Override
     public void onWindowDismissed() {
         finish();
     }
@@ -3493,6 +3621,18 @@
             }
             theme.applyStyle(resid, false);
         }
+
+        // Get the primary color and update the RecentsActivityValues for this activity
+        if (theme != null) {
+            TypedArray a = theme.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
+            int colorPrimary = a.getColor(com.android.internal.R.styleable.Theme_colorPrimary, 0);
+            a.recycle();
+            if (colorPrimary != 0) {
+                ActivityManager.RecentsActivityValues v = new ActivityManager.RecentsActivityValues();
+                v.colorPrimary = colorPrimary;
+                setRecentsActivityValues(v);
+            }
+        }
     }
 
     /**
@@ -4779,31 +4919,27 @@
     }
 
     /**
-     * Set a label and icon to be used in the Recents task display. When {@link
-     * ActivityManager#getRecentTasks} is called, the activities of each task are
-     * traversed in order from the topmost activity to the bottommost. As soon as one activity is
-     * found with either a non-null label or a non-null icon set by this call the traversal is
-     * ended. For each task those values will be returned in {@link
-     * ActivityManager.RecentTaskInfo#activityLabel} and {@link
-     * ActivityManager.RecentTaskInfo#activityIcon}.
+     * Sets information describing this Activity for presentation inside the Recents System UI. When
+     * {@link ActivityManager#getRecentTasks} is called, the activities of each task are
+     * traversed in order from the topmost activity to the bottommost. The traversal continues for
+     * each property until a suitable value is found. For each task those values will be returned in
+     * {@link android.app.ActivityManager.RecentsActivityValues}.
      *
      * @see ActivityManager#getRecentTasks
-     * @see ActivityManager.RecentTaskInfo
+     * @see android.app.ActivityManager.RecentsActivityValues
      *
-     * @param activityLabel The label to use in the RecentTaskInfo.
-     * @param activityIcon The Bitmap to use in the RecentTaskInfo.
+     * @param values The Recents values that describe this activity.
      */
-    public void setActivityLabelAndIcon(CharSequence activityLabel, Bitmap activityIcon) {
-        final Bitmap scaledIcon;
-        if (activityIcon != null) {
+    public void setRecentsActivityValues(ActivityManager.RecentsActivityValues values) {
+        ActivityManager.RecentsActivityValues activityValues =
+                new ActivityManager.RecentsActivityValues(values);
+        // Scale the icon down to something reasonable
+        if (values.icon != null) {
             final int size = ActivityManager.getLauncherLargeIconSizeInner(this);
-            scaledIcon = Bitmap.createScaledBitmap(activityIcon, size, size, true);
-        } else {
-            scaledIcon = null;
+            activityValues.icon = Bitmap.createScaledBitmap(values.icon, size, size, true);
         }
         try {
-            ActivityManagerNative.getDefault().setActivityLabelAndIcon(mToken, activityLabel,
-                    scaledIcon);
+            ActivityManagerNative.getDefault().setRecentsActivityValues(mToken, activityValues);
         } catch (RemoteException e) {
         }
     }
@@ -5141,19 +5277,29 @@
      *
      * @param callback the method to call when all visible Activities behind this one have been
      * drawn and it is safe to make this Activity translucent again.
+     * @param options activity options delivered to the activity below this one. The options
+     * are retrieved using {@link #getActivityOptions}.
      *
      * @see #convertFromTranslucent()
      * @see TranslucentConversionListener
      *
      * @hide
      */
-    public void convertToTranslucent(TranslucentConversionListener callback) {
+    void convertToTranslucent(TranslucentConversionListener callback, ActivityOptions options) {
+        boolean drawComplete;
         try {
             mTranslucentCallback = callback;
             mChangeCanvasToTranslucent =
-                    ActivityManagerNative.getDefault().convertToTranslucent(mToken);
+                    ActivityManagerNative.getDefault().convertToTranslucent(mToken, options);
+            drawComplete = true;
         } catch (RemoteException e) {
-            // pass
+            // Make callback return as though it timed out.
+            mChangeCanvasToTranslucent = false;
+            drawComplete = false;
+        }
+        if (!mChangeCanvasToTranslucent && mTranslucentCallback != null) {
+            // Window is already translucent.
+            mTranslucentCallback.onTranslucentConversionComplete(drawComplete);
         }
     }
 
@@ -5169,6 +5315,22 @@
     }
 
     /**
+     * Retrieve the ActivityOptions passed in from the launching activity or passed back
+     * from an activity launched by this activity in its call to {@link
+     * #convertToTranslucent(TranslucentConversionListener, ActivityOptions)}
+     *
+     * @return The ActivityOptions passed to {@link #convertToTranslucent}.
+     * @hide
+     */
+    ActivityOptions getActivityOptions() {
+        try {
+            return ActivityManagerNative.getDefault().getActivityOptions(mToken);
+        } catch (RemoteException e) {
+        }
+        return null;
+    }
+
+    /**
      * Adjust the current immersive mode setting.
      *
      * Note that changing this value will have no effect on the activity's
@@ -5402,36 +5564,19 @@
         mParent = parent;
     }
 
-    final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token,
-            Application application, Intent intent, ActivityInfo info, CharSequence title, 
-            Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances,
-            Configuration config) {
-        attach(context, aThread, instr, token, 0, application, intent, info, title, parent, id,
-            lastNonConfigurationInstances, config);
-    }
-    
     final void attach(Context context, ActivityThread aThread,
             Instrumentation instr, IBinder token, int ident,
             Application application, Intent intent, ActivityInfo info,
             CharSequence title, Activity parent, String id,
             NonConfigurationInstances lastNonConfigurationInstances,
-            Configuration config) {
-        attach(context, aThread, instr, token, ident, application, intent, info, title, parent, id,
-                lastNonConfigurationInstances, config, null, null);
-    }
-
-    final void attach(Context context, ActivityThread aThread,
-            Instrumentation instr, IBinder token, int ident,
-            Application application, Intent intent, ActivityInfo info,
-            CharSequence title, Activity parent, String id,
-            NonConfigurationInstances lastNonConfigurationInstances,
-            Configuration config, Bundle options, IVoiceInteractor voiceInteractor) {
+            Configuration config, IVoiceInteractor voiceInteractor) {
         attachBaseContext(context);
 
         mFragments.attachActivity(this, mContainer, null);
         
         mWindow = PolicyManager.makeNewWindow(this);
         mWindow.setCallback(this);
+        mWindow.setOnWindowDismissedCallback(this);
         mWindow.getLayoutInflater().setPrivateFactory(this);
         if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
             mWindow.setSoftInputMode(info.softInputMode);
@@ -5465,12 +5610,6 @@
         }
         mWindowManager = mWindow.getWindowManager();
         mCurrentConfig = config;
-        if (options != null) {
-            ActivityOptions activityOptions = new ActivityOptions(options);
-            if (activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
-                mEnterTransitionCoordinator = activityOptions.createEnterActivityTransition(this);
-            }
-        }
     }
 
     /** @hide */
@@ -5478,13 +5617,22 @@
         return mParent != null ? mParent.getActivityToken() : mToken;
     }
 
-    final void performCreate(Bundle icicle) {
-        onCreate(icicle);
+    final void performCreateCommon() {
         mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
                 com.android.internal.R.styleable.Window_windowNoDisplay, false);
         mFragments.dispatchActivityCreated();
     }
 
+    final void performCreate(Bundle icicle) {
+        onCreate(icicle);
+        performCreateCommon();
+    }
+
+    final void performCreate(Bundle icicle, PersistableBundle persistentState) {
+        onCreate(icicle, persistentState);
+        performCreateCommon();
+    }
+
     final void performStart() {
         mFragments.noteStateNotSaved();
         mCalled = false;
@@ -5680,7 +5828,16 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Put this Activity in a mode where the user is locked to the
+     * current task.
+     *
+     * This will prevent the user from launching other apps, going to settings,
+     * or reaching the home screen.
+     *
+     * Lock task mode will only start if the activity has been whitelisted by the
+     * Device Owner through DevicePolicyManager#setLockTaskComponents.
+     */
     public void startLockTask() {
         try {
             ActivityManagerNative.getDefault().startLockTaskMode(mToken);
@@ -5688,7 +5845,15 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Allow the user to switch away from the current task.
+     *
+     * Called to end the mode started by {@link Activity#startLockTask}. This
+     * can only be called by activities that have successfully called
+     * startLockTask previously.
+     *
+     * This will allow the user to exit this app and move onto other activities.
+     */
     public void stopLockTask() {
         try {
             ActivityManagerNative.getDefault().stopLockTaskMode();
@@ -5715,7 +5880,7 @@
          * occurred waiting for the Activity to complete drawing.
          *
          * @see Activity#convertFromTranslucent()
-         * @see Activity#convertToTranslucent(TranslucentConversionListener)
+         * @see Activity#convertToTranslucent(TranslucentConversionListener, ActivityOptions)
          */
         public void onTranslucentConversionComplete(boolean drawComplete);
     }
diff --git a/core/java/android/app/ActivityManager.aidl b/core/java/android/app/ActivityManager.aidl
new file mode 100644
index 0000000..92350da
--- /dev/null
+++ b/core/java/android/app/ActivityManager.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.app;
+
+parcelable ActivityManager.RecentTaskInfo;
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 018e949..1d05320 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -20,7 +20,6 @@
 import android.os.IBinder;
 import com.android.internal.app.IUsageStats;
 import com.android.internal.app.ProcessStats;
-import com.android.internal.os.PkgUsageStats;
 import com.android.internal.os.TransferPipe;
 import com.android.internal.util.FastPrintWriter;
 
@@ -53,6 +52,7 @@
 import java.io.FileDescriptor;
 import java.io.FileOutputStream;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -475,6 +475,111 @@
     }
 
     /**
+     * Information you can set and retrieve about the current activity within the recent task list.
+     */
+    public static class RecentsActivityValues implements Parcelable {
+        public CharSequence label;
+        public Bitmap icon;
+        public int colorPrimary;
+
+        public RecentsActivityValues(RecentsActivityValues values) {
+            copyFrom(values);
+        }
+
+        /**
+         * Creates the RecentsActivityValues to the specified values.
+         *
+         * @param label A label and description of the current state of this activity.
+         * @param icon An icon that represents the current state of this activity.
+         * @param color A color to override the theme's primary color.
+         */
+        public RecentsActivityValues(CharSequence label, Bitmap icon, int color) {
+            this.label = label;
+            this.icon = icon;
+            this.colorPrimary = color;
+        }
+
+        /**
+         * Creates the RecentsActivityValues to the specified values.
+         *
+         * @param label A label and description of the current state of this activity.
+         * @param icon An icon that represents the current state of this activity.
+         */
+        public RecentsActivityValues(CharSequence label, Bitmap icon) {
+            this(label, icon, 0);
+        }
+
+        /**
+         * Creates the RecentsActivityValues to the specified values.
+         *
+         * @param label A label and description of the current state of this activity.
+         */
+        public RecentsActivityValues(CharSequence label) {
+            this(label, null, 0);
+        }
+
+        public RecentsActivityValues() {
+            this(null, null, 0);
+        }
+
+        private RecentsActivityValues(Parcel source) {
+            readFromParcel(source);
+        }
+
+        /**
+         * Do a shallow copy of another set of activity values.
+         * @hide
+         */
+        public void copyFrom(RecentsActivityValues v) {
+            if (v != null) {
+                label = v.label;
+                icon = v.icon;
+                colorPrimary = v.colorPrimary;
+            }
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            TextUtils.writeToParcel(label, dest,
+                    Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+            if (icon == null) {
+                dest.writeInt(0);
+            } else {
+                dest.writeInt(1);
+                icon.writeToParcel(dest, 0);
+            }
+            dest.writeInt(colorPrimary);
+        }
+
+        public void readFromParcel(Parcel source) {
+            label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+            icon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
+            colorPrimary = source.readInt();
+        }
+
+        public static final Creator<RecentsActivityValues> CREATOR
+                = new Creator<RecentsActivityValues>() {
+            public RecentsActivityValues createFromParcel(Parcel source) {
+                return new RecentsActivityValues(source);
+            }
+            public RecentsActivityValues[] newArray(int size) {
+                return new RecentsActivityValues[size];
+            }
+        };
+
+        @Override
+        public String toString() {
+            return "RecentsActivityValues Label: " + label + " Icon: " + icon +
+                    " colorPrimary: " + colorPrimary;
+        }
+    }
+
+    /**
      * Information you can retrieve about tasks that the user has most recently
      * started or visited.
      */
@@ -523,16 +628,10 @@
         public int userId;
 
         /**
-         * The label of the highest activity in the task stack to have set a label using
-         * {@link Activity#setActivityLabelAndIcon(CharSequence, android.graphics.Bitmap)}.
+         * The recent activity values for the highest activity in the stack to have set the values.
+         * {@link Activity#setRecentsActivityValues(android.app.ActivityManager.RecentsActivityValues)}.
          */
-        public CharSequence activityLabel;
-
-        /**
-         * The Bitmap icon of the highest activity in the task stack to set a Bitmap using
-         * {@link Activity#setActivityLabelAndIcon(CharSequence, android.graphics.Bitmap)}.
-         */
-        public Bitmap activityIcon;
+        public RecentsActivityValues activityValues;
 
         public RecentTaskInfo() {
         }
@@ -555,13 +654,11 @@
             ComponentName.writeToParcel(origActivity, dest);
             TextUtils.writeToParcel(description, dest,
                     Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-            TextUtils.writeToParcel(activityLabel, dest,
-                    Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-            if (activityIcon == null) {
-                dest.writeInt(0);
-            } else {
+            if (activityValues != null) {
                 dest.writeInt(1);
-                activityIcon.writeToParcel(dest, 0);
+                activityValues.writeToParcel(dest, 0);
+            } else {
+                dest.writeInt(0);
             }
             dest.writeInt(stackId);
             dest.writeInt(userId);
@@ -573,8 +670,8 @@
             baseIntent = source.readInt() > 0 ? Intent.CREATOR.createFromParcel(source) : null;
             origActivity = ComponentName.readFromParcel(source);
             description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
-            activityLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
-            activityIcon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
+            activityValues = source.readInt() > 0 ?
+                    RecentsActivityValues.CREATOR.createFromParcel(source) : null;
             stackId = source.readInt();
             userId = source.readInt();
         }
@@ -783,41 +880,27 @@
             readFromParcel(source);
         }
     }
-    
+
     /**
-     * Return a list of the tasks that are currently running, with
-     * the most recent being first and older ones after in order.  Note that
-     * "running" does not mean any of the task's code is currently loaded or
-     * activity -- the task may have been frozen by the system, so that it
-     * can be restarted in its previous state when next brought to the
-     * foreground.
-     * 
-     * @param maxNum The maximum number of entries to return in the list.  The
-     * actual number returned may be smaller, depending on how many tasks the
-     * user has started.
+     * Get the list of tasks associated with the calling application.
      *
-     * @param flags Optional flags
-     * @param receiver Optional receiver for delayed thumbnails
-     *
-     * @return Returns a list of RunningTaskInfo records describing each of
-     * the running tasks.
-     * 
-     * Some thumbnails may not be available at the time of this call. The optional
-     * receiver may be used to receive those thumbnails.
-     *
-     * @throws SecurityException Throws SecurityException if the caller does
-     * not hold the {@link android.Manifest.permission#GET_TASKS} permission.
-     *
-     * @hide
+     * @return The list of tasks associated with the application making this call.
+     * @throws SecurityException
      */
-    public List<RunningTaskInfo> getRunningTasks(int maxNum, int flags, IThumbnailReceiver receiver)
-            throws SecurityException {
+    public List<ActivityManager.AppTask> getAppTasks() {
+        ArrayList<AppTask> tasks = new ArrayList<AppTask>();
+        List<IAppTask> appTasks;
         try {
-            return ActivityManagerNative.getDefault().getTasks(maxNum, flags, receiver);
+            appTasks = ActivityManagerNative.getDefault().getAppTasks();
         } catch (RemoteException e) {
             // System dead, we will be dead too soon!
             return null;
         }
+        int numAppTasks = appTasks.size();
+        for (int i = 0; i < numAppTasks; i++) {
+            tasks.add(new AppTask(appTasks.get(i)));
+        }
+        return tasks;
     }
 
     /**
@@ -849,7 +932,12 @@
      */
     public List<RunningTaskInfo> getRunningTasks(int maxNum)
             throws SecurityException {
-        return getRunningTasks(maxNum, 0, null);
+        try {
+            return ActivityManagerNative.getDefault().getTasks(maxNum, 0);
+        } catch (RemoteException e) {
+            // System dead, we will be dead too soon!
+            return null;
+        }
     }
 
     /**
@@ -1627,13 +1715,6 @@
         public int lastTrimLevel;
 
         /**
-         * Constant for {@link #importance}: this is a persistent process.
-         * Only used when reporting to process observers.
-         * @hide
-         */
-        public static final int IMPORTANCE_PERSISTENT = 50;
-
-        /**
          * Constant for {@link #importance}: this process is running the
          * foreground UI.
          */
@@ -1748,9 +1829,16 @@
          */
         public int importanceReasonImportance;
 
+        /**
+         * Current process state, as per PROCESS_STATE_* constants.
+         * @hide
+         */
+        public int processState;
+
         public RunningAppProcessInfo() {
             importance = IMPORTANCE_FOREGROUND;
             importanceReasonCode = REASON_UNKNOWN;
+            processState = PROCESS_STATE_IMPORTANT_FOREGROUND;
         }
         
         public RunningAppProcessInfo(String pProcessName, int pPid, String pArr[]) {
@@ -1776,6 +1864,7 @@
             dest.writeInt(importanceReasonPid);
             ComponentName.writeToParcel(importanceReasonComponent, dest);
             dest.writeInt(importanceReasonImportance);
+            dest.writeInt(processState);
         }
 
         public void readFromParcel(Parcel source) {
@@ -1791,6 +1880,7 @@
             importanceReasonPid = source.readInt();
             importanceReasonComponent = ComponentName.readFromParcel(source);
             importanceReasonImportance = source.readInt();
+            processState = source.readInt();
         }
 
         public static final Creator<RunningAppProcessInfo> CREATOR = 
@@ -2062,14 +2152,15 @@
                 return new HashMap<String, Integer>();
             }
 
-            PkgUsageStats[] allPkgUsageStats = usageStatsService.getAllPkgUsageStats();
+            UsageStats.PackageStats[] allPkgUsageStats = usageStatsService.getAllPkgUsageStats(
+                    ActivityThread.currentPackageName());
             if (allPkgUsageStats == null) {
                 return new HashMap<String, Integer>();
             }
 
             Map<String, Integer> launchCounts = new HashMap<String, Integer>();
-            for (PkgUsageStats pkgUsageStats : allPkgUsageStats) {
-                launchCounts.put(pkgUsageStats.packageName, pkgUsageStats.launchCount);
+            for (UsageStats.PackageStats pkgUsageStats : allPkgUsageStats) {
+                launchCounts.put(pkgUsageStats.getPackageName(), pkgUsageStats.getLaunchCount());
             }
 
             return launchCounts;
@@ -2183,17 +2274,17 @@
      *
      * @hide
      */
-    public PkgUsageStats[] getAllPackageUsageStats() {
+    public UsageStats.PackageStats[] getAllPackageUsageStats() {
         try {
             IUsageStats usageStatsService = IUsageStats.Stub.asInterface(
                     ServiceManager.getService("usagestats"));
             if (usageStatsService != null) {
-                return usageStatsService.getAllPkgUsageStats();
+                return usageStatsService.getAllPkgUsageStats(ActivityThread.currentPackageName());
             }
         } catch (RemoteException e) {
             Log.w(TAG, "Could not query usage stats", e);
         }
-        return new PkgUsageStats[0];
+        return new UsageStats.PackageStats[0];
     }
 
     /**
@@ -2314,4 +2405,42 @@
             return false;
         }
     }
+
+    /**
+     * The AppTask allows you to manage your own application's tasks.
+     * See {@link android.app.ActivityManager#getAppTasks()}
+     */
+    public static class AppTask {
+        private IAppTask mAppTaskImpl;
+
+        /** @hide */
+        public AppTask(IAppTask task) {
+            mAppTaskImpl = task;
+        }
+
+        /**
+         * Finishes all activities in this task and removes it from the recent tasks list.
+         */
+        public void finishAndRemoveTask() {
+            try {
+                mAppTaskImpl.finishAndRemoveTask();
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Invalid AppTask", e);
+            }
+        }
+
+        /**
+         * Get the RecentTaskInfo associated with this task.
+         *
+         * @return The RecentTaskInfo for this task, or null if the task no longer exists.
+         */
+        public RecentTaskInfo getTaskInfo() {
+            try {
+                return mAppTaskImpl.getTaskInfo();
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Invalid AppTask", e);
+                return null;
+            }
+        }
+    }
 }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index b1c37de..e704a1c 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -40,6 +40,7 @@
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
+import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StrictMode;
@@ -454,7 +455,8 @@
         case ACTIVITY_PAUSED_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
-            activityPaused(token);
+            PersistableBundle persistentState = data.readPersistableBundle();
+            activityPaused(token, persistentState);
             reply.writeNoException();
             return true;
         }
@@ -463,10 +465,9 @@
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
             Bundle map = data.readBundle();
-            Bitmap thumbnail = data.readInt() != 0
-                ? Bitmap.CREATOR.createFromParcel(data) : null;
+            PersistableBundle persistentState = data.readPersistableBundle();
             CharSequence description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data);
-            activityStopped(token, map, thumbnail, description);
+            activityStopped(token, map, persistentState, description);
             reply.writeNoException();
             return true;
         }
@@ -505,15 +506,25 @@
             return true;
         }
 
+        case GET_APP_TASKS_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            List<IAppTask> list = getAppTasks();
+            reply.writeNoException();
+            int N = list != null ? list.size() : -1;
+            reply.writeInt(N);
+            int i;
+            for (i=0; i<N; i++) {
+                IAppTask task = list.get(i);
+                reply.writeStrongBinder(task.asBinder());
+            }
+            return true;
+        }
+
         case GET_TASKS_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             int maxNum = data.readInt();
             int fl = data.readInt();
-            IBinder receiverBinder = data.readStrongBinder();
-            IThumbnailReceiver receiver = receiverBinder != null
-                ? IThumbnailReceiver.Stub.asInterface(receiverBinder)
-                : null;
-            List<ActivityManager.RunningTaskInfo> list = getTasks(maxNum, fl, receiver);
+            List<ActivityManager.RunningTaskInfo> list = getTasks(maxNum, fl);
             reply.writeNoException();
             int N = list != null ? list.size() : -1;
             reply.writeInt(N);
@@ -712,17 +723,6 @@
             return true;
         }
 
-        case REPORT_THUMBNAIL_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            Bitmap thumbnail = data.readInt() != 0
-                ? Bitmap.CREATOR.createFromParcel(data) : null;
-            CharSequence description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data);
-            reportThumbnail(token, thumbnail, description);
-            reply.writeNoException();
-            return true;
-        }
-
         case GET_CONTENT_PROVIDER_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder b = data.readStrongBinder();
@@ -1128,7 +1128,8 @@
             int pid = data.readInt();
             int uid = data.readInt();
             int mode = data.readInt();
-            int res = checkUriPermission(uri, pid, uid, mode);
+            int userId = data.readInt();
+            int res = checkUriPermission(uri, pid, uid, mode, userId);
             reply.writeNoException();
             reply.writeInt(res);
             return true;
@@ -1153,7 +1154,8 @@
             String targetPkg = data.readString();
             Uri uri = Uri.CREATOR.createFromParcel(data);
             int mode = data.readInt();
-            grantUriPermission(app, targetPkg, uri, mode);
+            int userId = data.readInt();
+            grantUriPermission(app, targetPkg, uri, mode, userId);
             reply.writeNoException();
             return true;
         }
@@ -1164,7 +1166,8 @@
             IApplicationThread app = ApplicationThreadNative.asInterface(b);
             Uri uri = Uri.CREATOR.createFromParcel(data);
             int mode = data.readInt();
-            revokeUriPermission(app, uri, mode);
+            int userId = data.readInt();
+            revokeUriPermission(app, uri, mode, userId);
             reply.writeNoException();
             return true;
         }
@@ -1173,7 +1176,8 @@
             data.enforceInterface(IActivityManager.descriptor);
             Uri uri = Uri.CREATOR.createFromParcel(data);
             int mode = data.readInt();
-            takePersistableUriPermission(uri, mode);
+            int userId = data.readInt();
+            takePersistableUriPermission(uri, mode, userId);
             reply.writeNoException();
             return true;
         }
@@ -1182,7 +1186,8 @@
             data.enforceInterface(IActivityManager.descriptor);
             Uri uri = Uri.CREATOR.createFromParcel(data);
             int mode = data.readInt();
-            releasePersistableUriPermission(uri, mode);
+            int userId = data.readInt();
+            releasePersistableUriPermission(uri, mode, userId);
             reply.writeNoException();
             return true;
         }
@@ -1556,12 +1561,28 @@
         case CONVERT_TO_TRANSLUCENT_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
-            boolean converted = convertToTranslucent(token);
+            final Bundle bundle;
+            if (data.readInt() == 0) {
+                bundle = null;
+            } else {
+                bundle = data.readBundle();
+            }
+            final ActivityOptions options = bundle == null ? null : new ActivityOptions(bundle);
+            boolean converted = convertToTranslucent(token, options);
             reply.writeNoException();
             reply.writeInt(converted ? 1 : 0);
             return true;
         }
 
+        case GET_ACTIVITY_OPTIONS_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder token = data.readStrongBinder();
+            final ActivityOptions options = getActivityOptions(token);
+            reply.writeNoException();
+            reply.writeBundle(options == null ? null : options.toBundle());
+            return true;
+        }
+
         case SET_IMMERSIVE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
@@ -1616,7 +1637,8 @@
             String targetPkg = data.readString();
             Uri uri = Uri.CREATOR.createFromParcel(data);
             int mode = data.readInt();
-            grantUriPermissionFromOwner(owner, fromUid, targetPkg, uri, mode);
+            int userId = data.readInt();
+            grantUriPermissionFromOwner(owner, fromUid, targetPkg, uri, mode, userId);
             reply.writeNoException();
             return true;
         }
@@ -1626,10 +1648,11 @@
             IBinder owner = data.readStrongBinder();
             Uri uri = null;
             if (data.readInt() != 0) {
-                Uri.CREATOR.createFromParcel(data);
+                uri = Uri.CREATOR.createFromParcel(data);
             }
             int mode = data.readInt();
-            revokeUriPermissionFromOwner(owner, uri, mode);
+            int userId = data.readInt();
+            revokeUriPermissionFromOwner(owner, uri, mode, userId);
             reply.writeNoException();
             return true;
         }
@@ -1640,7 +1663,8 @@
             String targetPkg = data.readString();
             Uri uri = Uri.CREATOR.createFromParcel(data);
             int modeFlags = data.readInt();
-            int res = checkGrantUriPermission(callingUid, targetPkg, uri, modeFlags);
+            int userId = data.readInt();
+            int res = checkGrantUriPermission(callingUid, targetPkg, uri, modeFlags, userId);
             reply.writeNoException();
             reply.writeInt(res);
             return true;
@@ -2134,13 +2158,12 @@
             return true;
         }
 
-        case SET_ACTIVITY_LABEL_ICON_TRANSACTION: {
+        case SET_RECENTS_ACTIVITY_VALUES_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
-            CharSequence activityLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data);
-            Bitmap activityIcon = data.readInt() > 0
-                    ? Bitmap.CREATOR.createFromParcel(data) : null;
-            setActivityLabelAndIcon(token, activityLabel, activityIcon);
+            ActivityManager.RecentsActivityValues values =
+                    ActivityManager.RecentsActivityValues.CREATOR.createFromParcel(data);
+            setRecentsActivityValues(token, values);
             reply.writeNoException();
             return true;
         }
@@ -2599,31 +2622,27 @@
         data.recycle();
         reply.recycle();
     }
-    public void activityPaused(IBinder token) throws RemoteException
+    public void activityPaused(IBinder token, PersistableBundle persistentState) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(token);
+        data.writePersistableBundle(persistentState);
         mRemote.transact(ACTIVITY_PAUSED_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
     }
     public void activityStopped(IBinder token, Bundle state,
-            Bitmap thumbnail, CharSequence description) throws RemoteException
+            PersistableBundle persistentState, CharSequence description) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(token);
         data.writeBundle(state);
-        if (thumbnail != null) {
-            data.writeInt(1);
-            thumbnail.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
+        data.writePersistableBundle(persistentState);
         TextUtils.writeToParcel(description, data, 0);
         mRemote.transact(ACTIVITY_STOPPED_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
         reply.readException();
@@ -2678,14 +2697,32 @@
         reply.recycle();
         return res;
     }
-    public List getTasks(int maxNum, int flags,
-            IThumbnailReceiver receiver) throws RemoteException {
+    public List<IAppTask> getAppTasks() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(GET_APP_TASKS_TRANSACTION, data, reply, 0);
+        reply.readException();
+        ArrayList<IAppTask> list = null;
+        int N = reply.readInt();
+        if (N >= 0) {
+            list = new ArrayList<IAppTask>();
+            while (N > 0) {
+                IAppTask task = IAppTask.Stub.asInterface(reply.readStrongBinder());
+                list.add(task);
+                N--;
+            }
+        }
+        data.recycle();
+        reply.recycle();
+        return list;
+    }
+    public List getTasks(int maxNum, int flags) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(maxNum);
         data.writeInt(flags);
-        data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);
         mRemote.transact(GET_TASKS_TRANSACTION, data, reply, 0);
         reply.readException();
         ArrayList list = null;
@@ -2695,7 +2732,7 @@
             while (N > 0) {
                 ActivityManager.RunningTaskInfo info =
                         ActivityManager.RunningTaskInfo.CREATOR
-                        .createFromParcel(reply);
+                                .createFromParcel(reply);
                 list.add(info);
                 N--;
             }
@@ -2964,25 +3001,6 @@
         reply.recycle();
         return res;
     }
-    public void reportThumbnail(IBinder token,
-                                Bitmap thumbnail, CharSequence description) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        if (thumbnail != null) {
-            data.writeInt(1);
-            thumbnail.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        TextUtils.writeToParcel(description, data, 0);
-        mRemote.transact(REPORT_THUMBNAIL_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
     public ContentProviderHolder getContentProvider(IApplicationThread caller,
             String name, int userId, boolean stable) throws RemoteException {
         Parcel data = Parcel.obtain();
@@ -3580,7 +3598,7 @@
         reply.recycle();
         return res;
     }
-    public int checkUriPermission(Uri uri, int pid, int uid, int mode) 
+    public int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId)
             throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -3589,6 +3607,7 @@
         data.writeInt(pid);
         data.writeInt(uid);
         data.writeInt(mode);
+        data.writeInt(userId);
         mRemote.transact(CHECK_URI_PERMISSION_TRANSACTION, data, reply, 0);
         reply.readException();
         int res = reply.readInt();
@@ -3597,7 +3616,7 @@
         return res;
     }
     public void grantUriPermission(IApplicationThread caller, String targetPkg,
-            Uri uri, int mode) throws RemoteException {
+            Uri uri, int mode, int userId) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -3605,19 +3624,21 @@
         data.writeString(targetPkg);
         uri.writeToParcel(data, 0);
         data.writeInt(mode);
+        data.writeInt(userId);
         mRemote.transact(GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
     }
     public void revokeUriPermission(IApplicationThread caller, Uri uri,
-            int mode) throws RemoteException {
+            int mode, int userId) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(caller.asBinder());
         uri.writeToParcel(data, 0);
         data.writeInt(mode);
+        data.writeInt(userId);
         mRemote.transact(REVOKE_URI_PERMISSION_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
@@ -3625,12 +3646,14 @@
     }
 
     @Override
-    public void takePersistableUriPermission(Uri uri, int mode) throws RemoteException {
+    public void takePersistableUriPermission(Uri uri, int mode, int userId)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         uri.writeToParcel(data, 0);
         data.writeInt(mode);
+        data.writeInt(userId);
         mRemote.transact(TAKE_PERSISTABLE_URI_PERMISSION_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
@@ -3638,12 +3661,14 @@
     }
 
     @Override
-    public void releasePersistableUriPermission(Uri uri, int mode) throws RemoteException {
+    public void releasePersistableUriPermission(Uri uri, int mode, int userId)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         uri.writeToParcel(data, 0);
         data.writeInt(mode);
+        data.writeInt(userId);
         mRemote.transact(RELEASE_PERSISTABLE_URI_PERMISSION_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
@@ -4099,12 +4124,18 @@
         return res;
     }
 
-    public boolean convertToTranslucent(IBinder token)
+    public boolean convertToTranslucent(IBinder token, ActivityOptions options)
             throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(token);
+        if (options == null) {
+            data.writeInt(0);
+        } else {
+            data.writeInt(1);
+            data.writeBundle(options.toBundle());
+        }
         mRemote.transact(CONVERT_TO_TRANSLUCENT_TRANSACTION, data, reply, 0);
         reply.readException();
         boolean res = reply.readInt() != 0;
@@ -4113,6 +4144,20 @@
         return res;
     }
 
+    public ActivityOptions getActivityOptions(IBinder token) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(token);
+        mRemote.transact(GET_ACTIVITY_OPTIONS_TRANSACTION, data, reply, 0);
+        reply.readException();
+        Bundle bundle = reply.readBundle();
+        ActivityOptions options = bundle == null ? null : new ActivityOptions(bundle);
+        data.recycle();
+        reply.recycle();
+        return options;
+    }
+
     public void setImmersive(IBinder token, boolean immersive)
             throws RemoteException {
         Parcel data = Parcel.obtain();
@@ -4197,7 +4242,7 @@
     }
 
     public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
-            Uri uri, int mode) throws RemoteException {
+            Uri uri, int mode, int userId) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -4206,6 +4251,7 @@
         data.writeString(targetPkg);
         uri.writeToParcel(data, 0);
         data.writeInt(mode);
+        data.writeInt(userId);
         mRemote.transact(GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
@@ -4213,7 +4259,7 @@
     }
 
     public void revokeUriPermissionFromOwner(IBinder owner, Uri uri,
-            int mode) throws RemoteException {
+            int mode, int userId) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -4225,6 +4271,7 @@
             data.writeInt(0);
         }
         data.writeInt(mode);
+        data.writeInt(userId);
         mRemote.transact(REVOKE_URI_PERMISSION_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
@@ -4232,7 +4279,7 @@
     }
 
     public int checkGrantUriPermission(int callingUid, String targetPkg,
-            Uri uri, int modeFlags) throws RemoteException {
+            Uri uri, int modeFlags, int userId) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -4240,6 +4287,7 @@
         data.writeString(targetPkg);
         uri.writeToParcel(data, 0);
         data.writeInt(modeFlags);
+        data.writeInt(userId);
         mRemote.transact(CHECK_GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0);
         reply.readException();
         int res = reply.readInt();
@@ -4919,21 +4967,14 @@
     }
 
     @Override
-    public void setActivityLabelAndIcon(IBinder token, CharSequence activityLabel,
-            Bitmap activityIcon) throws RemoteException
-    {
+    public void setRecentsActivityValues(IBinder token, ActivityManager.RecentsActivityValues values)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(token);
-        TextUtils.writeToParcel(activityLabel, data, 0);
-        if (activityIcon != null) {
-            data.writeInt(1);
-            activityIcon.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
-        mRemote.transact(SET_ACTIVITY_LABEL_ICON_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+        values.writeToParcel(data, 0);
+        mRemote.transact(SET_RECENTS_ACTIVITY_VALUES_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
         reply.readException();
         data.recycle();
         reply.recycle();
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index a49359f..692efd7 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -365,11 +365,15 @@
      * @param listener The listener to use to monitor activity transition events.
      * @return Returns a new ActivityOptions object that you can use to
      *         supply these options as the options Bundle when starting an activity.
+     *         Returns null if the Window does not have {@link Window#FEATURE_CONTENT_TRANSITIONS}.
      * @see android.transition.Transition#setEpicenterCallback(
      *          android.transition.Transition.EpicenterCallback)
      */
     public static ActivityOptions makeSceneTransitionAnimation(Window window,
             ActivityTransitionListener listener) {
+        if (!window.hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
+            return null;
+        }
         ActivityOptions opts = new ActivityOptions();
         opts.mAnimationType = ANIM_SCENE_TRANSITION;
         ExitTransitionCoordinator exit = new ExitTransitionCoordinator(window, listener);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 7dc21b4..71e4e82 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -46,7 +46,8 @@
 import android.hardware.display.DisplayManagerGlobal;
 import android.net.IConnectivityManager;
 import android.net.Proxy;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
+import android.net.Uri;
 import android.opengl.GLUtils;
 import android.os.AsyncTask;
 import android.os.Binder;
@@ -56,11 +57,11 @@
 import android.os.Environment;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.IRemoteCallback;
 import android.os.Looper;
 import android.os.Message;
 import android.os.MessageQueue;
 import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -69,8 +70,6 @@
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
-import android.transition.Scene;
-import android.transition.TransitionManager;
 import android.provider.Settings;
 import android.util.AndroidRuntimeException;
 import android.util.ArrayMap;
@@ -78,7 +77,6 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.LogPrinter;
-import android.util.Pair;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.util.SuperNotCalledException;
@@ -268,6 +266,7 @@
         Intent intent;
         IVoiceInteractor voiceInteractor;
         Bundle state;
+        PersistableBundle persistentState;
         Activity activity;
         Window window;
         Activity parent;
@@ -295,7 +294,6 @@
         boolean isForward;
         int pendingConfigChanges;
         boolean onlyLocalRequest;
-        Bundle activityOptions;
 
         View mPendingRemoveWindow;
         WindowManager mPendingRemoveWindowManager;
@@ -317,6 +315,10 @@
             return false;
         }
 
+        public boolean isPersistable() {
+            return (activityInfo.flags & ActivityInfo.FLAG_PERSISTABLE) != 0;
+        }
+
         public String toString() {
             ComponentName componentName = intent != null ? intent.getComponent() : null;
             return "ActivityRecord{"
@@ -590,8 +592,7 @@
         public final void scheduleResumeActivity(IBinder token, int processState,
                 boolean isForward, Bundle resumeArgs) {
             updateProcessState(processState, false);
-            sendMessage(H.RESUME_ACTIVITY, new Pair<IBinder, Bundle>(token, resumeArgs),
-                    isForward ? 1 : 0);
+            sendMessage(H.RESUME_ACTIVITY, token, isForward ? 1 : 0);
         }
 
         public final void scheduleSendResult(IBinder token, List<ResultInfo> results) {
@@ -605,11 +606,10 @@
         // activity itself back to the activity manager. (matters more with ipc)
         public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                 ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
-                IVoiceInteractor voiceInteractor,
-                int procState, Bundle state, List<ResultInfo> pendingResults,
+                IVoiceInteractor voiceInteractor, int procState, Bundle state,
+                PersistableBundle persistentState, List<ResultInfo> pendingResults,
                 List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
-                String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
-                Bundle resumeArgs) {
+                String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
 
             updateProcessState(procState, false);
 
@@ -622,6 +622,7 @@
             r.activityInfo = info;
             r.compatInfo = compatInfo;
             r.state = state;
+            r.persistentState = persistentState;
 
             r.pendingResults = pendingResults;
             r.pendingIntents = pendingNewIntents;
@@ -632,7 +633,6 @@
             r.profileFile = profileName;
             r.profileFd = profileFd;
             r.autoStopProfiler = autoStopProfiler;
-            r.activityOptions = resumeArgs;
 
             updatePendingConfiguration(curConfig);
 
@@ -821,10 +821,6 @@
             sendMessage(H.SUICIDE, null);
         }
 
-        public void requestThumbnail(IBinder token) {
-            sendMessage(H.REQUEST_THUMBNAIL, token);
-        }
-
         public void scheduleConfigurationChanged(Configuration config) {
             updatePendingConfiguration(config);
             sendMessage(H.CONFIGURATION_CHANGED, config);
@@ -839,7 +835,7 @@
             InetAddress.clearDnsCache();
         }
 
-        public void setHttpProxy(String host, String port, String exclList, String pacFileUrl) {
+        public void setHttpProxy(String host, String port, String exclList, Uri pacFileUrl) {
             Proxy.setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
         }
 
@@ -1168,7 +1164,7 @@
         public static final int CREATE_SERVICE          = 114;
         public static final int SERVICE_ARGS            = 115;
         public static final int STOP_SERVICE            = 116;
-        public static final int REQUEST_THUMBNAIL       = 117;
+
         public static final int CONFIGURATION_CHANGED   = 118;
         public static final int CLEAN_UP_CONTEXT        = 119;
         public static final int GC_WHEN_IDLE            = 120;
@@ -1218,7 +1214,6 @@
                     case CREATE_SERVICE: return "CREATE_SERVICE";
                     case SERVICE_ARGS: return "SERVICE_ARGS";
                     case STOP_SERVICE: return "STOP_SERVICE";
-                    case REQUEST_THUMBNAIL: return "REQUEST_THUMBNAIL";
                     case CONFIGURATION_CHANGED: return "CONFIGURATION_CHANGED";
                     case CLEAN_UP_CONTEXT: return "CLEAN_UP_CONTEXT";
                     case GC_WHEN_IDLE: return "GC_WHEN_IDLE";
@@ -1302,9 +1297,7 @@
                     break;
                 case RESUME_ACTIVITY:
                     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
-                    final Pair<IBinder, Bundle> resumeArgs = (Pair<IBinder, Bundle>) msg.obj;
-                    handleResumeActivity(resumeArgs.first, resumeArgs.second, true,
-                            msg.arg1 != 0, true);
+                    handleResumeActivity((IBinder) msg.obj, true, msg.arg1 != 0, true);
                     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                     break;
                 case SEND_RESULT:
@@ -1367,11 +1360,6 @@
                     maybeSnapshot();
                     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                     break;
-                case REQUEST_THUMBNAIL:
-                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "requestThumbnail");
-                    handleRequestThumbnail((IBinder)msg.obj);
-                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-                    break;
                 case CONFIGURATION_CHANGED:
                     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "configChanged");
                     mCurDefaultDisplayDpi = ((Configuration)msg.obj).densityDpi;
@@ -2089,7 +2077,7 @@
                     + ", comp=" + name
                     + ", token=" + token);
         }
-        return performLaunchActivity(r, null, null);
+        return performLaunchActivity(r, null);
     }
 
     public final Activity getActivity(IBinder token) {
@@ -2142,8 +2130,7 @@
         sendMessage(H.CLEAN_UP_CONTEXT, cci);
     }
 
-    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent,
-            Bundle options) {
+    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
         // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
 
         ActivityInfo aInfo = r.activityInfo;
@@ -2201,7 +2188,7 @@
                         + r.activityInfo.name + " with config " + config);
                 activity.attach(appContext, this, getInstrumentation(), r.token,
                         r.ident, app, r.intent, r.activityInfo, title, r.parent,
-                        r.embeddedID, r.lastNonConfigurationInstances, config, options,
+                        r.embeddedID, r.lastNonConfigurationInstances, config,
                         r.voiceInteractor);
 
                 if (customIntent != null) {
@@ -2215,7 +2202,11 @@
                 }
 
                 activity.mCalled = false;
-                mInstrumentation.callActivityOnCreate(activity, r.state);
+                if (r.isPersistable()) {
+                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
+                } else {
+                    mInstrumentation.callActivityOnCreate(activity, r.state);
+                }
                 if (!activity.mCalled) {
                     throw new SuperNotCalledException(
                         "Activity " + r.intent.getComponent().toShortString() +
@@ -2228,13 +2219,23 @@
                     r.stopped = false;
                 }
                 if (!r.activity.mFinished) {
-                    if (r.state != null) {
+                    if (r.isPersistable()) {
+                        if (r.state != null || r.persistentState != null) {
+                            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
+                                    r.persistentState);
+                        }
+                    } else if (r.state != null) {
                         mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                     }
                 }
                 if (!r.activity.mFinished) {
                     activity.mCalled = false;
-                    mInstrumentation.callActivityOnPostCreate(activity, r.state);
+                    if (r.isPersistable()) {
+                        mInstrumentation.callActivityOnPostCreate(activity, r.state,
+                                r.persistentState);
+                    } else {
+                        mInstrumentation.callActivityOnPostCreate(activity, r.state);
+                    }
                     if (!activity.mCalled) {
                         throw new SuperNotCalledException(
                             "Activity " + r.intent.getComponent().toShortString() +
@@ -2313,12 +2314,12 @@
         if (localLOGV) Slog.v(
             TAG, "Handling launch of " + r);
 
-        Activity a = performLaunchActivity(r, customIntent, r.activityOptions);
+        Activity a = performLaunchActivity(r, customIntent);
 
         if (a != null) {
             r.createdConfig = new Configuration(mConfiguration);
             Bundle oldState = r.state;
-            handleResumeActivity(r.token, r.activityOptions, false, r.isForward,
+            handleResumeActivity(r.token, false, r.isForward,
                     !r.activity.mFinished && !r.startsNotResumed);
 
             if (!r.activity.mFinished && r.startsNotResumed) {
@@ -2852,6 +2853,7 @@
                 r.paused = false;
                 r.stopped = false;
                 r.state = null;
+                r.persistentState = null;
             } catch (Exception e) {
                 if (!mInstrumentation.onException(r.activity, e)) {
                     throw new RuntimeException(
@@ -2877,7 +2879,7 @@
         r.mPendingRemoveWindowManager = null;
     }
 
-    final void handleResumeActivity(IBinder token, Bundle resumeArgs,
+    final void handleResumeActivity(IBinder token,
             boolean clearHide, boolean isForward, boolean reallyResume) {
         // If we are getting ready to gc after going to the background, well
         // we are back active so skip it.
@@ -3079,7 +3081,7 @@
 
             // Tell the activity manager we have paused.
             try {
-                ActivityManagerNative.getDefault().activityPaused(token);
+                ActivityManagerNative.getDefault().activityPaused(token, r.persistentState);
             } catch (RemoteException ex) {
             }
         }
@@ -3109,17 +3111,13 @@
                     + r.intent.getComponent().toShortString());
             Slog.e(TAG, e.getMessage(), e);
         }
-        Bundle state = null;
         if (finished) {
             r.activity.mFinished = true;
         }
         try {
             // Next have the activity save its current state and managed dialogs...
             if (!r.activity.mFinished && saveState) {
-                state = new Bundle();
-                state.setAllowFds(false);
-                mInstrumentation.callActivityOnSaveInstanceState(r.activity, state);
-                r.state = state;
+                callCallActivityOnSaveInstanceState(r);
             }
             // Now we are idle.
             r.activity.mCalled = false;
@@ -3155,7 +3153,7 @@
             listeners.get(i).onPaused(r.activity);
         }
 
-        return state;
+        return !r.activity.mFinished && saveState ? r.state : null;
     }
 
     final void performStopActivity(IBinder token, boolean saveState) {
@@ -3166,7 +3164,7 @@
     private static class StopInfo implements Runnable {
         ActivityClientRecord activity;
         Bundle state;
-        Bitmap thumbnail;
+        PersistableBundle persistentState;
         CharSequence description;
 
         @Override public void run() {
@@ -3174,7 +3172,7 @@
             try {
                 if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Reporting activity stopped: " + activity);
                 ActivityManagerNative.getDefault().activityStopped(
-                    activity.token, state, thumbnail, description);
+                    activity.token, state, persistentState, description);
             } catch (RemoteException ex) {
             }
         }
@@ -3213,7 +3211,6 @@
     private void performStopActivityInner(ActivityClientRecord r,
             StopInfo info, boolean keepShown, boolean saveState) {
         if (localLOGV) Slog.v(TAG, "Performing stop of " + r);
-        Bundle state = null;
         if (r != null) {
             if (!keepShown && r.stopped) {
                 if (r.activity.mFinished) {
@@ -3233,7 +3230,6 @@
                     // First create a thumbnail for the activity...
                     // For now, don't create the thumbnail here; we are
                     // doing that by doing a screen snapshot.
-                    info.thumbnail = null; //createThumbnailBitmap(r);
                     info.description = r.activity.onCreateDescription();
                 } catch (Exception e) {
                     if (!mInstrumentation.onException(r.activity, e)) {
@@ -3248,12 +3244,7 @@
             // Next have the activity save its current state and managed dialogs...
             if (!r.activity.mFinished && saveState) {
                 if (r.state == null) {
-                    state = new Bundle();
-                    state.setAllowFds(false);
-                    mInstrumentation.callActivityOnSaveInstanceState(r.activity, state);
-                    r.state = state;
-                } else {
-                    state = r.state;
+                    callCallActivityOnSaveInstanceState(r);
                 }
             }
 
@@ -3329,6 +3320,7 @@
         // manager to proceed and allow us to go fully into the background.
         info.activity = r;
         info.state = r.state;
+        info.persistentState = r.persistentState;
         mH.post(info);
     }
 
@@ -3785,9 +3777,7 @@
             performPauseActivity(r.token, false, r.isPreHoneycomb());
         }
         if (r.state == null && !r.stopped && !r.isPreHoneycomb()) {
-            r.state = new Bundle();
-            r.state.setAllowFds(false);
-            mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
+            callCallActivityOnSaveInstanceState(r);
         }
 
         handleDestroyActivity(r.token, false, configChanges, true);
@@ -3812,30 +3802,19 @@
             }
         }
         r.startsNotResumed = tmp.startsNotResumed;
-        r.activityOptions = null;
 
         handleLaunchActivity(r, currentIntent);
     }
 
-    private void handleRequestThumbnail(IBinder token) {
-        ActivityClientRecord r = mActivities.get(token);
-        Bitmap thumbnail = createThumbnailBitmap(r);
-        CharSequence description = null;
-        try {
-            description = r.activity.onCreateDescription();
-        } catch (Exception e) {
-            if (!mInstrumentation.onException(r.activity, e)) {
-                throw new RuntimeException(
-                        "Unable to create description of activity "
-                        + r.intent.getComponent().toShortString()
-                        + ": " + e.toString(), e);
-            }
-        }
-        //System.out.println("Reporting top thumbnail " + thumbnail);
-        try {
-            ActivityManagerNative.getDefault().reportThumbnail(
-                token, thumbnail, description);
-        } catch (RemoteException ex) {
+    private void callCallActivityOnSaveInstanceState(ActivityClientRecord r) {
+        r.state = new Bundle();
+        r.state.setAllowFds(false);
+        if (r.isPersistable()) {
+            r.persistentState = new PersistableBundle();
+            mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state,
+                    r.persistentState);
+        } else {
+            mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
         }
     }
 
@@ -4326,8 +4305,8 @@
             // crash if we can't get it.
             IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
             try {
-                ProxyProperties proxyProperties = service.getProxy();
-                Proxy.setHttpProxySystemProperty(proxyProperties);
+                ProxyInfo proxyInfo = service.getProxy();
+                Proxy.setHttpProxySystemProperty(proxyInfo);
             } catch (RemoteException e) {}
         }
 
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 3c1455b..ca64788 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Handler;
@@ -30,6 +31,7 @@
 import android.transition.TransitionSet;
 import android.util.ArrayMap;
 import android.util.Pair;
+import android.util.SparseArray;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroupOverlay;
@@ -138,6 +140,10 @@
     private static final String KEY_HEIGHT = "shared_element:height";
     private static final String KEY_NAME = "shared_element:name";
     private static final String KEY_BITMAP = "shared_element:bitmap";
+    private static final String KEY_SCALE_TYPE = "shared_element:scaleType";
+    private static final String KEY_IMAGE_MATRIX = "shared_element:imageMatrix";
+
+    private static final ImageView.ScaleType[] SCALE_TYPE_VALUES = ImageView.ScaleType.values();
 
     /**
      * Sent by the exiting coordinator (either EnterTransitionCoordinator
@@ -322,7 +328,8 @@
         final ArrayList<View> accepted = new ArrayList<View>();
         final ArrayList<View> rejected = new ArrayList<View>();
         createSharedElementImages(accepted, rejected, sharedElementNames, state);
-        setSharedElementState(state, accepted);
+        ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalImageViewState =
+                setSharedElementState(state, accepted);
         handleRejected(rejected);
 
         if (getViewsTransition() != null) {
@@ -331,6 +338,7 @@
         setViewVisibility(mSharedElements, View.VISIBLE);
         Transition transition = beginTransition(mEnteringViews, true, allowOverlappingTransitions(),
                 true);
+        setOriginalImageViewState(originalImageViewState);
 
         if (allowOverlappingTransitions()) {
             onStartEnterTransition(transition, mEnteringViews);
@@ -464,7 +472,7 @@
             if (getViewsTransition() != null) {
                 setViewVisibility(mEnteringViews, View.VISIBLE);
             }
-            getDecor().findSharedElements(map);
+            getDecor().findNamedViews(map);
             if (getViewsTransition() != null) {
                 setViewVisibility(mEnteringViews, View.INVISIBLE);
             }
@@ -568,15 +576,22 @@
         mEpicenterCallback.setEpicenter(epicenter);
     }
 
-    private void setSharedElementState(Bundle sharedElementState,
-            final ArrayList<View> acceptedOverlayViews) {
+    private ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> setSharedElementState(
+            Bundle sharedElementState, final ArrayList<View> acceptedOverlayViews) {
+        ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalImageState =
+                new ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>>();
         final int[] tempLoc = new int[2];
         if (sharedElementState != null) {
             for (int i = 0; i < mSharedElements.size(); i++) {
                 View sharedElement = mSharedElements.get(i);
+                String name = mTargetSharedNames.get(i);
+                Pair<ImageView.ScaleType, Matrix> originalState = getOldImageState(sharedElement,
+                        name, sharedElementState);
+                if (originalState != null) {
+                    originalImageState.put((ImageView) sharedElement, originalState);
+                }
                 View parent = (View) sharedElement.getParent();
                 parent.getLocationOnScreen(tempLoc);
-                String name = mTargetSharedNames.get(i);
                 setSharedElementState(sharedElement, name, sharedElementState, tempLoc);
                 sharedElement.requestLayout();
             }
@@ -596,6 +611,29 @@
                     }
                 }
         );
+        return originalImageState;
+    }
+
+    private static Pair<ImageView.ScaleType, Matrix> getOldImageState(View view, String name,
+            Bundle transitionArgs) {
+        if (!(view instanceof ImageView)) {
+            return null;
+        }
+        Bundle bundle = transitionArgs.getBundle(name);
+        int scaleTypeInt = bundle.getInt(KEY_SCALE_TYPE, -1);
+        if (scaleTypeInt < 0) {
+            return null;
+        }
+
+        ImageView imageView = (ImageView) view;
+        ImageView.ScaleType originalScaleType = imageView.getScaleType();
+
+        Matrix originalMatrix = null;
+        if (originalScaleType == ImageView.ScaleType.MATRIX) {
+            originalMatrix = new Matrix(imageView.getImageMatrix());
+        }
+
+        return Pair.create(originalScaleType, originalMatrix);
     }
 
     /**
@@ -614,6 +652,21 @@
             return;
         }
 
+        if (view instanceof ImageView) {
+            int scaleTypeInt = sharedElementBundle.getInt(KEY_SCALE_TYPE, -1);
+            if (scaleTypeInt >= 0) {
+                ImageView imageView = (ImageView) view;
+                ImageView.ScaleType scaleType = SCALE_TYPE_VALUES[scaleTypeInt];
+                imageView.setScaleType(scaleType);
+                if (scaleType == ImageView.ScaleType.MATRIX) {
+                    float[] matrixValues = sharedElementBundle.getFloatArray(KEY_IMAGE_MATRIX);
+                    Matrix matrix = new Matrix();
+                    matrix.setValues(matrixValues);
+                    imageView.setImageMatrix(matrix);
+                }
+            }
+        }
+
         float z = sharedElementBundle.getFloat(KEY_TRANSLATION_Z);
         view.setTranslationZ(z);
 
@@ -659,13 +712,24 @@
 
         sharedElementBundle.putFloat(KEY_TRANSLATION_Z, view.getTranslationZ());
 
-        sharedElementBundle.putString(KEY_NAME, view.getSharedElementName());
+        sharedElementBundle.putString(KEY_NAME, view.getViewName());
 
         Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
         Canvas canvas = new Canvas(bitmap);
         view.draw(canvas);
         sharedElementBundle.putParcelable(KEY_BITMAP, bitmap);
 
+        if (view instanceof ImageView) {
+            ImageView imageView = (ImageView) view;
+            int scaleTypeInt = scaleTypeToInt(imageView.getScaleType());
+            sharedElementBundle.putInt(KEY_SCALE_TYPE, scaleTypeInt);
+            if (imageView.getScaleType() == ImageView.ScaleType.MATRIX) {
+                float[] matrix = new float[9];
+                imageView.getImageMatrix().getValues(matrix);
+                sharedElementBundle.putFloatArray(KEY_IMAGE_MATRIX, matrix);
+            }
+        }
+
         transitionArgs.putBundle(name, sharedElementBundle);
     }
 
@@ -818,7 +882,7 @@
                 imageView.setId(com.android.internal.R.id.shared_element);
                 imageView.setScaleType(ImageView.ScaleType.CENTER);
                 imageView.setImageBitmap(bitmap);
-                imageView.setSharedElementName(name);
+                imageView.setViewName(name);
                 setSharedElementState(imageView, name, state, parentLoc);
                 if (mTargetSharedNames.contains(name)) {
                     accepted.add(imageView);
@@ -829,6 +893,25 @@
         }
     }
 
+    private static void setOriginalImageViewState(
+            ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalState) {
+        for (int i = 0; i < originalState.size(); i++) {
+            ImageView imageView = originalState.keyAt(i);
+            Pair<ImageView.ScaleType, Matrix> state = originalState.valueAt(i);
+            imageView.setScaleType(state.first);
+            imageView.setImageMatrix(state.second);
+        }
+    }
+
+    private static int scaleTypeToInt(ImageView.ScaleType scaleType) {
+        for (int i = 0; i < SCALE_TYPE_VALUES.length; i++) {
+            if (scaleType == SCALE_TYPE_VALUES[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
     private static class FixedEpicenterCallback extends Transition.EpicenterCallback {
         private Rect mEpicenter;
 
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index a810134..097c64e 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -33,6 +33,7 @@
 import android.view.Surface;
 import android.view.TextureView;
 import android.view.TextureView.SurfaceTextureListener;
+import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import dalvik.system.CloseGuard;
@@ -51,6 +52,7 @@
     private int mWidth;
     private int mHeight;
     private Surface mSurface;
+    private int mLastVisibility;
 
     // Only one IIntentSender or Intent may be queued at a time. Most recent one wins.
     IIntentSender mQueuedPendingIntent;
@@ -95,6 +97,8 @@
         mMetrics = new DisplayMetrics();
         wm.getDefaultDisplay().getMetrics(mMetrics);
 
+        mLastVisibility = getVisibility();
+
         if (DEBUG) Log.v(TAG, "ctor()");
     }
 
@@ -103,6 +107,26 @@
         mTextureView.layout(0, 0, r - l, b - t);
     }
 
+    @Override
+    protected void onVisibilityChanged(View changedView, int visibility) {
+        super.onVisibilityChanged(changedView, visibility);
+
+        if (mSurface != null) {
+            try {
+                if (visibility == View.GONE) {
+                    mActivityContainer.setSurface(null, mWidth, mHeight, mMetrics.densityDpi);
+                } else if (mLastVisibility == View.GONE) {
+                    // Don't change surface when going between View.VISIBLE and View.INVISIBLE.
+                    mActivityContainer.setSurface(mSurface, mWidth, mHeight, mMetrics.densityDpi);
+                }
+            } catch (RemoteException e) {
+                throw new RuntimeException(
+                        "ActivityView: Unable to set surface of ActivityContainer. " + e);
+            }
+        }
+        mLastVisibility = visibility;
+    }
+
     private boolean injectInputEvent(InputEvent event) {
         return mActivityContainer != null && mActivityContainer.injectEvent(event);
     }
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java
index ab148a9..4ce7835 100644
--- a/core/java/android/app/AlertDialog.java
+++ b/core/java/android/app/AlertDialog.java
@@ -92,6 +92,18 @@
      * the device's default alert theme with a light background.
      */
     public static final int THEME_DEVICE_DEFAULT_LIGHT = 5;
+
+    /**
+     * No layout hint.
+     * @hide
+     */
+    public static final int LAYOUT_HINT_NONE = 0;
+
+    /**
+     * Hint layout to the side.
+     * @hide
+     */
+    public static final int LAYOUT_HINT_SIDE = 1;
     
     protected AlertDialog(Context context) {
         this(context, resolveDialogTheme(context, 0), true);
@@ -208,6 +220,14 @@
     }
 
     /**
+     * Internal api to allow hinting for the best button panel layout.
+     * @hide
+     */
+    void setButtonPanelLayoutHint(int layoutHint) {
+        mAlert.setButtonPanelLayoutHint(layoutHint);
+    }
+
+    /**
      * Set a message to be sent when a button is pressed.
      * 
      * @param whichButton Which button to set the message for, can be one of
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index b616c1e..d813dab 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.Manifest;
 import android.os.Binder;
 import android.os.IBinder;
 import android.util.ArrayMap;
@@ -184,8 +185,10 @@
     public static final int OP_MONITOR_LOCATION = 41;
     /** @hide Continually monitoring location data with a relatively high power request. */
     public static final int OP_MONITOR_HIGH_POWER_LOCATION = 42;
+    /** @hide Retrieve current usage stats via {@link UsageStatsManager}. */
+    public static final int OP_GET_USAGE_STATS = 43;
     /** @hide */
-    public static final int _NUM_OP = 43;
+    public static final int _NUM_OP = 44;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION =
@@ -252,6 +255,7 @@
             OP_WAKE_LOCK,
             OP_COARSE_LOCATION,
             OP_COARSE_LOCATION,
+            OP_GET_USAGE_STATS,
     };
 
     /**
@@ -302,6 +306,7 @@
             null,
             OPSTR_MONITOR_LOCATION,
             OPSTR_MONITOR_HIGH_POWER_LOCATION,
+            null,
     };
 
     /**
@@ -352,6 +357,7 @@
             "WAKE_LOCK",
             "MONITOR_LOCATION",
             "MONITOR_HIGH_POWER_LOCATION",
+            "GET_USAGE_STATS"
     };
 
     /**
@@ -402,6 +408,7 @@
             android.Manifest.permission.WAKE_LOCK,
             null, // no permission for generic location monitoring
             null, // no permission for high power location monitoring
+            android.Manifest.permission.PACKAGE_USAGE_STATS,
     };
 
     /**
@@ -451,6 +458,7 @@
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_IGNORED, // OP_GET_USAGE_STATS
     };
 
     /**
@@ -504,6 +512,7 @@
             false,
             false,
             false,
+            false,
     };
 
     private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index ab62427..2f35160 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -35,6 +35,7 @@
 import android.content.pm.IPackageStatsObserver;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.PermissionGroupInfo;
@@ -1127,7 +1128,7 @@
     public void installPackage(Uri packageURI, PackageInstallObserver observer,
             int flags, String installerPackageName) {
         try {
-            mPM.installPackageEtc(packageURI, null, observer.mObserver,
+            mPM.installPackageEtc(packageURI, null, observer.getBinder(),
                     flags, installerPackageName);
         } catch (RemoteException e) {
             // Should never happen!
@@ -1140,7 +1141,7 @@
             Uri verificationURI, ManifestDigest manifestDigest,
             ContainerEncryptionParams encryptionParams) {
         try {
-            mPM.installPackageWithVerificationEtc(packageURI, null, observer.mObserver, flags,
+            mPM.installPackageWithVerificationEtc(packageURI, null, observer.getBinder(), flags,
                     installerPackageName, verificationURI, manifestDigest, encryptionParams);
         } catch (RemoteException e) {
             // Should never happen!
@@ -1153,7 +1154,7 @@
             VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
         try {
             mPM.installPackageWithVerificationAndEncryptionEtc(packageURI, null,
-                    observer.mObserver, flags, installerPackageName, verificationParams,
+                    observer.getBinder(), flags, installerPackageName, verificationParams,
                     encryptionParams);
         } catch (RemoteException e) {
             // Should never happen!
@@ -1440,6 +1441,41 @@
         return null;
     }
 
+    @Override
+    public PackageInstaller getPackageInstaller() {
+        try {
+            return new PackageInstaller(this, mPM.getPackageInstaller(), mContext.getUserId(),
+                    mContext.getPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void addForwardingIntentFilter(IntentFilter filter, boolean removable, int userIdOrig,
+            int userIdDest) {
+        try {
+            mPM.addForwardingIntentFilter(filter, removable, userIdOrig, userIdDest);
+        } catch (RemoteException e) {
+            // Should never happen!
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void clearForwardingIntentFilters(int userIdOrig) {
+        try {
+            mPM.clearForwardingIntentFilters(userIdOrig);
+        } catch (RemoteException e) {
+            // Should never happen!
+        }
+    }
+
     private final ContextImpl mContext;
     private final IPackageManager mPM;
 
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index fcc7f8e..ef4099f 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -25,10 +25,12 @@
 import android.content.pm.ServiceInfo;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Parcelable;
+import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -141,6 +143,7 @@
                     data.readStrongBinder());
             int procState = data.readInt();
             Bundle state = data.readBundle();
+            PersistableBundle persistentState = data.readPersistableBundle();
             List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR);
             List<Intent> pi = data.createTypedArrayList(Intent.CREATOR);
             boolean notResumed = data.readInt() != 0;
@@ -149,11 +152,10 @@
             ParcelFileDescriptor profileFd = data.readInt() != 0
                     ? ParcelFileDescriptor.CREATOR.createFromParcel(data) : null;
             boolean autoStopProfiler = data.readInt() != 0;
-            Bundle resumeArgs = data.readBundle();
             scheduleLaunchActivity(intent, b, ident, info, curConfig, compatInfo,
-                    voiceInteractor, procState, state,
-                    ri, pi, notResumed, isForward, profileName, profileFd, autoStopProfiler,
-                    resumeArgs);
+                    voiceInteractor, procState, state, persistentState,
+                    ri, pi, notResumed, isForward, profileName, profileFd,
+                    autoStopProfiler);
             return true;
         }
         
@@ -312,14 +314,6 @@
             return true;
         }
 
-        case REQUEST_THUMBNAIL_TRANSACTION:
-        {
-            data.enforceInterface(IApplicationThread.descriptor);
-            IBinder b = data.readStrongBinder();
-            requestThumbnail(b);
-            return true;
-        }
-
         case SCHEDULE_CONFIGURATION_CHANGED_TRANSACTION:
         {
             data.enforceInterface(IApplicationThread.descriptor);
@@ -345,7 +339,7 @@
             final String proxy = data.readString();
             final String port = data.readString();
             final String exclList = data.readString();
-            final String pacFileUrl = data.readString();
+            final Uri pacFileUrl = Uri.CREATOR.createFromParcel(data);
             setHttpProxy(proxy, port, exclList, pacFileUrl);
             return true;
         }
@@ -739,11 +733,10 @@
 
     public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
             ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
-            IVoiceInteractor voiceInteractor,
-            int procState, Bundle state, List<ResultInfo> pendingResults,
+            IVoiceInteractor voiceInteractor, int procState, Bundle state,
+            PersistableBundle persistentState, List<ResultInfo> pendingResults,
             List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
-            String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
-            Bundle resumeArgs)
+            String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler)
             throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -756,6 +749,7 @@
         data.writeStrongBinder(voiceInteractor != null ? voiceInteractor.asBinder() : null);
         data.writeInt(procState);
         data.writeBundle(state);
+        data.writePersistableBundle(persistentState);
         data.writeTypedList(pendingResults);
         data.writeTypedList(pendingNewIntents);
         data.writeInt(notResumed ? 1 : 0);
@@ -768,7 +762,6 @@
             data.writeInt(0);
         }
         data.writeInt(autoStopProfiler ? 1 : 0);
-        data.writeBundle(resumeArgs);
         mRemote.transact(SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
         data.recycle();
@@ -986,16 +979,6 @@
         data.recycle();
     }
 
-    public final void requestThumbnail(IBinder token)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        data.writeInterfaceToken(IApplicationThread.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(REQUEST_THUMBNAIL_TRANSACTION, data, null,
-                IBinder.FLAG_ONEWAY);
-        data.recycle();
-    }
-
     public final void scheduleConfigurationChanged(Configuration config)
             throws RemoteException {
         Parcel data = Parcel.obtain();
@@ -1023,13 +1006,13 @@
     }
 
     public void setHttpProxy(String proxy, String port, String exclList,
-            String pacFileUrl) throws RemoteException {
+            Uri pacFileUrl) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeString(proxy);
         data.writeString(port);
         data.writeString(exclList);
-        data.writeString(pacFileUrl);
+        pacFileUrl.writeToParcel(data, 0);
         mRemote.transact(SET_HTTP_PROXY_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
         data.recycle();
     }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index fe532bf..b4d8942 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import android.net.wifi.IWifiScanner;
+import android.net.wifi.WifiScanner;
 import android.os.Build;
 
 import com.android.internal.policy.PolicyManager;
@@ -24,6 +26,7 @@
 import android.bluetooth.BluetoothManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -106,6 +109,9 @@
 import android.os.storage.StorageManager;
 import android.print.IPrintManager;
 import android.print.PrintManager;
+import android.service.fingerprint.FingerprintManager;
+import android.service.fingerprint.FingerprintManagerReceiver;
+import android.service.fingerprint.FingerprintService;
 import android.telephony.TelephonyManager;
 import android.tv.ITvInputManager;
 import android.tv.TvInputManager;
@@ -451,6 +457,11 @@
                     return new KeyguardManager();
                 }});
 
+        registerService(FINGERPRINT_SERVICE, new ServiceFetcher() {
+            public Object createService(ContextImpl ctx) {
+                return new FingerprintManager(ctx);
+            }});
+
         registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
                 public Object createService(ContextImpl ctx) {
                     return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
@@ -581,6 +592,13 @@
                     return new WifiP2pManager(service);
                 }});
 
+        registerService(WIFI_SCANNING_SERVICE, new ServiceFetcher() {
+            public Object createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(WIFI_SCANNING_SERVICE);
+                IWifiScanner service = IWifiScanner.Stub.asInterface(b);
+                return new WifiScanner(ctx.getOuterContext(), service);
+            }});
+
         registerService(WINDOW_SERVICE, new ServiceFetcher() {
                 Display mDefaultDisplay;
                 public Object getService(ContextImpl ctx) {
@@ -661,6 +679,11 @@
                 return new NetworkScoreManager(ctx);
             }
         });
+
+        registerService(USAGE_STATS_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                return new UsageStatsManager(ctx.getOuterContext());
+        }});
     }
 
     static ContextImpl getImpl(Context context) {
@@ -1796,8 +1819,8 @@
     public void grantUriPermission(String toPackage, Uri uri, int modeFlags) {
          try {
             ActivityManagerNative.getDefault().grantUriPermission(
-                    mMainThread.getApplicationThread(), toPackage, uri,
-                    modeFlags);
+                    mMainThread.getApplicationThread(), toPackage,
+                    ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
         } catch (RemoteException e) {
         }
     }
@@ -1806,8 +1829,8 @@
     public void revokeUriPermission(Uri uri, int modeFlags) {
          try {
             ActivityManagerNative.getDefault().revokeUriPermission(
-                    mMainThread.getApplicationThread(), uri,
-                    modeFlags);
+                    mMainThread.getApplicationThread(),
+                    ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
         } catch (RemoteException e) {
         }
     }
@@ -1816,12 +1839,17 @@
     public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
         try {
             return ActivityManagerNative.getDefault().checkUriPermission(
-                    uri, pid, uid, modeFlags);
+                    ContentProvider.getUriWithoutUserId(uri), pid, uid, modeFlags,
+                    resolveUserId(uri));
         } catch (RemoteException e) {
             return PackageManager.PERMISSION_DENIED;
         }
     }
 
+    private int resolveUserId(Uri uri) {
+        return ContentProvider.getUserIdFromUri(uri, getUserId());
+    }
+
     @Override
     public int checkCallingUriPermission(Uri uri, int modeFlags) {
         int pid = Binder.getCallingPid();
@@ -2258,12 +2286,16 @@
 
         @Override
         protected IContentProvider acquireProvider(Context context, String auth) {
-            return mMainThread.acquireProvider(context, auth, mUser.getIdentifier(), true);
+            return mMainThread.acquireProvider(context,
+                    ContentProvider.getAuthorityWithoutUserId(auth),
+                    resolveUserIdFromAuthority(auth), true);
         }
 
         @Override
         protected IContentProvider acquireExistingProvider(Context context, String auth) {
-            return mMainThread.acquireExistingProvider(context, auth, mUser.getIdentifier(), true);
+            return mMainThread.acquireExistingProvider(context,
+                    ContentProvider.getAuthorityWithoutUserId(auth),
+                    resolveUserIdFromAuthority(auth), true);
         }
 
         @Override
@@ -2273,7 +2305,9 @@
 
         @Override
         protected IContentProvider acquireUnstableProvider(Context c, String auth) {
-            return mMainThread.acquireProvider(c, auth, mUser.getIdentifier(), false);
+            return mMainThread.acquireProvider(c,
+                    ContentProvider.getAuthorityWithoutUserId(auth),
+                    resolveUserIdFromAuthority(auth), false);
         }
 
         @Override
@@ -2290,5 +2324,10 @@
         public void appNotRespondingViaProvider(IContentProvider icp) {
             mMainThread.appNotRespondingViaProvider(icp.asBinder());
         }
+
+        /** @hide */
+        protected int resolveUserIdFromAuthority(String auth) {
+            return ContentProvider.getUserIdFromAuthority(auth, mUser.getIdentifier());
+        }
     }
 }
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index d168800..26c2c30 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -107,6 +107,7 @@
                 (LayoutInflater) themeContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         View view = inflater.inflate(R.layout.date_picker_dialog, null);
         setView(view);
+        setButtonPanelLayoutHint(LAYOUT_HINT_SIDE);
         mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
         mDatePicker.init(year, monthOfYear, dayOfMonth, this);
         updateTitle(year, monthOfYear, dayOfMonth);
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 07583fd..12d4513 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -79,7 +79,7 @@
  * </div>
  */
 public class Dialog implements DialogInterface, Window.Callback,
-        KeyEvent.Callback, OnCreateContextMenuListener {
+        KeyEvent.Callback, OnCreateContextMenuListener, Window.OnWindowDismissedCallback {
     private static final String TAG = "Dialog";
     private Activity mOwnerActivity;
     
@@ -165,6 +165,7 @@
         Window w = PolicyManager.makeNewWindow(mContext);
         mWindow = w;
         w.setCallback(this);
+        w.setOnWindowDismissedCallback(this);
         w.setWindowManager(mWindowManager, null, null);
         w.setGravity(Gravity.CENTER);
         mListenersHandler = new ListenersHandler(this);
@@ -708,6 +709,8 @@
     public void onDetachedFromWindow() {
     }
 
+    /** @hide */
+    @Override
     public void onWindowDismissed() {
         dismiss();
     }
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index c26e68a..d2d8ed1 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -23,8 +23,6 @@
 import android.os.Bundle;
 import android.os.ResultReceiver;
 import android.transition.Transition;
-import android.util.ArrayMap;
-import android.util.Pair;
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.view.Window;
@@ -123,7 +121,7 @@
                             mActivity.convertFromTranslucent();
                         }
                     }
-                });
+                }, null);
                 Drawable background = getDecor().getBackground();
                 if (background != null) {
                     window.setBackgroundDrawable(null);
@@ -219,6 +217,7 @@
 
     @Override
     protected void startExitTransition(ArrayList<String> sharedElements) {
+        mMakeOpaque = false;
         notifyPrepareRestore();
 
         if (getDecor().getBackground() == null) {
@@ -231,7 +230,7 @@
                 public void onTranslucentConversionComplete(boolean drawComplete) {
                     fadeOutBackground();
                 }
-            });
+            }, null);
         } else {
             fadeOutBackground();
         }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 6b94c4e..8753312 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -45,6 +45,7 @@
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
+import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.StrictMode;
 import android.service.voice.IVoiceInteractionSession;
@@ -104,15 +105,15 @@
     public void activityResumed(IBinder token) throws RemoteException;
     public void activityIdle(IBinder token, Configuration config,
             boolean stopProfiling) throws RemoteException;
-    public void activityPaused(IBinder token) throws RemoteException;
+    public void activityPaused(IBinder token, PersistableBundle persistentState) throws RemoteException;
     public void activityStopped(IBinder token, Bundle state,
-            Bitmap thumbnail, CharSequence description) throws RemoteException;
+            PersistableBundle persistentState, CharSequence description) throws RemoteException;
     public void activitySlept(IBinder token) throws RemoteException;
     public void activityDestroyed(IBinder token) throws RemoteException;
     public String getCallingPackage(IBinder token) throws RemoteException;
     public ComponentName getCallingActivity(IBinder token) throws RemoteException;
-    public List<RunningTaskInfo> getTasks(int maxNum, int flags,
-                         IThumbnailReceiver receiver) throws RemoteException;
+    public List<IAppTask> getAppTasks() throws RemoteException;
+    public List<RunningTaskInfo> getTasks(int maxNum, int flags) throws RemoteException;
     public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
             int flags, int userId) throws RemoteException;
     public ActivityManager.TaskThumbnails getTaskThumbnails(int taskId) throws RemoteException;
@@ -131,9 +132,6 @@
     public boolean isInHomeStack(int taskId) throws RemoteException;
     public void setFocusedStack(int stackId) throws RemoteException;
     public int getTaskForActivity(IBinder token, boolean onlyRoot) throws RemoteException;
-    /* oneway */
-    public void reportThumbnail(IBinder token,
-            Bitmap thumbnail, CharSequence description) throws RemoteException;
     public ContentProviderHolder getContentProvider(IApplicationThread caller,
             String name, int userId, boolean stable) throws RemoteException;
     public ContentProviderHolder getContentProviderExternal(String name, int userId, IBinder token)
@@ -213,14 +211,16 @@
     public int checkPermission(String permission, int pid, int uid)
             throws RemoteException;
 
-    public int checkUriPermission(Uri uri, int pid, int uid, int mode)
+    public int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId)
             throws RemoteException;
-    public void grantUriPermission(IApplicationThread caller, String targetPkg,
-            Uri uri, int mode) throws RemoteException;
-    public void revokeUriPermission(IApplicationThread caller, Uri uri,
-            int mode) throws RemoteException;
-    public void takePersistableUriPermission(Uri uri, int modeFlags) throws RemoteException;
-    public void releasePersistableUriPermission(Uri uri, int modeFlags) throws RemoteException;
+    public void grantUriPermission(IApplicationThread caller, String targetPkg, Uri uri,
+            int mode, int userId) throws RemoteException;
+    public void revokeUriPermission(IApplicationThread caller, Uri uri, int mode, int userId)
+            throws RemoteException;
+    public void takePersistableUriPermission(Uri uri, int modeFlags, int userId)
+            throws RemoteException;
+    public void releasePersistableUriPermission(Uri uri, int modeFlags, int userId)
+            throws RemoteException;
     public ParceledListSlice<UriPermission> getPersistedUriPermissions(
             String packageName, boolean incoming) throws RemoteException;
 
@@ -312,8 +312,9 @@
     public void finishHeavyWeightApp() throws RemoteException;
 
     public boolean convertFromTranslucent(IBinder token) throws RemoteException;
-    public boolean convertToTranslucent(IBinder token) throws RemoteException;
+    public boolean convertToTranslucent(IBinder token, ActivityOptions options) throws RemoteException;
     public void notifyActivityDrawn(IBinder token) throws RemoteException;
+    public ActivityOptions getActivityOptions(IBinder token) throws RemoteException;
 
     public void setImmersive(IBinder token, boolean immersive) throws RemoteException;
     public boolean isImmersive(IBinder token) throws RemoteException;
@@ -326,12 +327,12 @@
     
     public IBinder newUriPermissionOwner(String name) throws RemoteException;
     public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
-            Uri uri, int mode) throws RemoteException;
+            Uri uri, int mode, int userId) throws RemoteException;
     public void revokeUriPermissionFromOwner(IBinder owner, Uri uri,
-            int mode) throws RemoteException;
+            int mode, int userId) throws RemoteException;
 
-    public int checkGrantUriPermission(int callingUid, String targetPkg,
-            Uri uri, int modeFlags) throws RemoteException;
+    public int checkGrantUriPermission(int callingUid, String targetPkg, Uri uri,
+            int modeFlags, int userId) throws RemoteException;
 
     // Cause the specified process to dump the specified heap.
     public boolean dumpHeap(String process, int userId, boolean managed, String path,
@@ -439,8 +440,8 @@
     public boolean isInLockTaskMode() throws RemoteException;
 
     /** @hide */
-    public void setActivityLabelAndIcon(IBinder token, CharSequence activityLabel,
-            Bitmap activityBitmap) throws RemoteException;
+    public void setRecentsActivityValues(IBinder token, ActivityManager.RecentsActivityValues values)
+            throws RemoteException;
 
     /*
      * Private non-Binder interfaces
@@ -571,7 +572,7 @@
     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;
-    int REPORT_THUMBNAIL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+27;
+
     int GET_CONTENT_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+28;
     int PUBLISH_CONTENT_PROVIDERS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+29;
     int REF_CONTENT_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+30;
@@ -738,6 +739,8 @@
     int START_LOCK_TASK_BY_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+214;
     int STOP_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+215;
     int IS_IN_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+216;
-    int SET_ACTIVITY_LABEL_ICON_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
+    int SET_RECENTS_ACTIVITY_VALUES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
     int START_VOICE_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+218;
+    int GET_ACTIVITY_OPTIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+219;
+    int GET_APP_TASKS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+220;
 }
diff --git a/core/java/android/app/IAppTask.aidl b/core/java/android/app/IAppTask.aidl
new file mode 100644
index 0000000..268b4dd
--- /dev/null
+++ b/core/java/android/app/IAppTask.aidl
@@ -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 android.app;
+
+import android.app.ActivityManager;
+
+/** @hide */
+interface IAppTask {
+    void finishAndRemoveTask();
+    ActivityManager.RecentTaskInfo getTaskInfo();
+}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index f290e94..d0df7c3 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -25,9 +25,11 @@
 import android.content.pm.ServiceInfo;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.IBinder;
 import android.os.IInterface;
@@ -58,10 +60,9 @@
     void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
             ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
             IVoiceInteractor voiceInteractor, int procState, Bundle state,
-            List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed,
-            boolean isForward,
-            String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
-            Bundle resumeArgs)
+            PersistableBundle persistentState, List<ResultInfo> pendingResults,
+            List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
+            String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler)
             throws RemoteException;
     void scheduleRelaunchActivity(IBinder token, List<ResultInfo> pendingResults,
             List<Intent> pendingNewIntents, int configChanges,
@@ -101,12 +102,11 @@
             Bundle coreSettings) throws RemoteException;
     void scheduleExit() throws RemoteException;
     void scheduleSuicide() throws RemoteException;
-    void requestThumbnail(IBinder token) throws RemoteException;
     void scheduleConfigurationChanged(Configuration config) throws RemoteException;
     void updateTimeZone() throws RemoteException;
     void clearDnsCache() throws RemoteException;
     void setHttpProxy(String proxy, String port, String exclList,
-            String pacFileUrl) throws RemoteException;
+            Uri pacFileUrl) throws RemoteException;
     void processInBackground() throws RemoteException;
     void dumpService(FileDescriptor fd, IBinder servicetoken, String[] args)
             throws RemoteException;
@@ -159,7 +159,7 @@
     int SCHEDULE_STOP_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+11;
     int BIND_APPLICATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+12;
     int SCHEDULE_EXIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+13;
-    int REQUEST_THUMBNAIL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+14;
+
     int SCHEDULE_CONFIGURATION_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+15;
     int SCHEDULE_SERVICE_ARGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+16;
     int UPDATE_TIME_ZONE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+17;
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index ad4027d..b917263 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -58,6 +58,8 @@
     ZenModeConfig getZenModeConfig();
     boolean setZenModeConfig(in ZenModeConfig config);
     oneway void notifyConditions(String pkg, in IConditionProvider provider, in Condition[] conditions);
-    oneway void requestZenModeConditions(in IConditionListener callback, boolean requested);
+    oneway void requestZenModeConditions(in IConditionListener callback, int relevance);
     oneway void setZenModeCondition(in Uri conditionId);
+    oneway void setAutomaticZenModeConditions(in Uri[] conditionIds);
+    Condition[] getAutomaticZenModeConditions();
 }
\ No newline at end of file
diff --git a/core/java/android/app/IProcessObserver.aidl b/core/java/android/app/IProcessObserver.aidl
index e587912..ecf2c73 100644
--- a/core/java/android/app/IProcessObserver.aidl
+++ b/core/java/android/app/IProcessObserver.aidl
@@ -20,7 +20,7 @@
 oneway interface IProcessObserver {
 
     void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities);
-    void onImportanceChanged(int pid, int uid, int importance);
+    void onProcessStateChanged(int pid, int uid, int procState);
     void onProcessDied(int pid, int uid);
 
 }
diff --git a/core/java/android/app/IThumbnailReceiver.aidl b/core/java/android/app/IThumbnailReceiver.aidl
deleted file mode 100644
index 7943f2c..0000000
--- a/core/java/android/app/IThumbnailReceiver.aidl
+++ /dev/null
@@ -1,30 +0,0 @@
-/* //device/java/android/android/app/IThumbnailReceiver.aidl
-**
-** 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.
-*/
-package android.app;
-
-import android.graphics.Bitmap;
-
-/**
- * System private API for receiving updated thumbnails from a checkpoint.
- *
- * {@hide}
- */
-oneway interface IThumbnailReceiver {
-    void newThumbnail(int id, in Bitmap thumbnail, CharSequence description);
-    void finished();
-}
-
diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl
index 347de97..8ab9ac3 100644
--- a/core/java/android/app/IUiAutomationConnection.aidl
+++ b/core/java/android/app/IUiAutomationConnection.aidl
@@ -43,4 +43,5 @@
     WindowContentFrameStats getWindowContentFrameStats(int windowId);
     void clearWindowAnimationFrameStats();
     WindowAnimationFrameStats getWindowAnimationFrameStats();
+    void executeShellCommand(String command, in ParcelFileDescriptor fd);
 }
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index e58ccb8..b78b9c9 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -30,6 +30,7 @@
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.os.PerformanceCollector;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -1035,10 +1036,10 @@
             IllegalAccessException {
         Activity activity = (Activity)clazz.newInstance();
         ActivityThread aThread = null;
-        activity.attach(context, aThread, this, token, application, intent,
+        activity.attach(context, aThread, this, token, 0, application, intent,
                 info, title, parent, id,
                 (Activity.NonConfigurationInstances)lastNonConfigurationInstance,
-                new Configuration());
+                new Configuration(), null);
         return activity;
     }
 
@@ -1061,15 +1062,7 @@
         return (Activity)cl.loadClass(className).newInstance();
     }
 
-    /**
-     * Perform calling of an activity's {@link Activity#onCreate}
-     * method.  The default implementation simply calls through to that method.
-     * 
-     * @param activity The activity being created.
-     * @param icicle The previously frozen state (or null) to pass through to
-     *               onCreate().
-     */
-    public void callActivityOnCreate(Activity activity, Bundle icicle) {
+    private void prePerformCreate(Activity activity) {
         if (mWaitingActivities != null) {
             synchronized (mSync) {
                 final int N = mWaitingActivities.size();
@@ -1083,9 +1076,9 @@
                 }
             }
         }
-        
-        activity.performCreate(icicle);
-        
+    }
+
+    private void postPerformCreate(Activity activity) {
         if (mActivityMonitors != null) {
             synchronized (mSync) {
                 final int N = mActivityMonitors.size();
@@ -1096,6 +1089,33 @@
             }
         }
     }
+
+    /**
+     * Perform calling of an activity's {@link Activity#onCreate}
+     * method.  The default implementation simply calls through to that method.
+     *
+     * @param activity The activity being created.
+     * @param icicle The previously frozen state (or null) to pass through to onCreate().
+     */
+    public void callActivityOnCreate(Activity activity, Bundle icicle) {
+        prePerformCreate(activity);
+        activity.performCreate(icicle);
+        postPerformCreate(activity);
+    }
+
+    /**
+     * Perform calling of an activity's {@link Activity#onCreate}
+     * method.  The default implementation simply calls through to that method.
+     *  @param activity The activity being created.
+     * @param icicle The previously frozen state (or null) to pass through to
+     * @param persistentState The previously persisted state (or null)
+     */
+    public void callActivityOnCreate(Activity activity, Bundle icicle,
+            PersistableBundle persistentState) {
+        prePerformCreate(activity);
+        activity.performCreate(icicle, persistentState);
+        postPerformCreate(activity);
+    }
     
     public void callActivityOnDestroy(Activity activity) {
       // TODO: the following block causes intermittent hangs when using startActivity
@@ -1130,7 +1150,7 @@
     /**
      * Perform calling of an activity's {@link Activity#onRestoreInstanceState}
      * method.  The default implementation simply calls through to that method.
-     * 
+     *
      * @param activity The activity being restored.
      * @param savedInstanceState The previously saved state being restored.
      */
@@ -1139,9 +1159,22 @@
     }
 
     /**
+     * Perform calling of an activity's {@link Activity#onRestoreInstanceState}
+     * method.  The default implementation simply calls through to that method.
+     *
+     * @param activity The activity being restored.
+     * @param savedInstanceState The previously saved state being restored.
+     * @param persistentState The previously persisted state (or null)
+     */
+    public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState,
+            PersistableBundle persistentState) {
+        activity.performRestoreInstanceState(savedInstanceState, persistentState);
+    }
+
+    /**
      * Perform calling of an activity's {@link Activity#onPostCreate} method.
      * The default implementation simply calls through to that method.
-     * 
+     *
      * @param activity The activity being created.
      * @param icicle The previously frozen state (or null) to pass through to
      *               onPostCreate().
@@ -1151,6 +1184,19 @@
     }
 
     /**
+     * Perform calling of an activity's {@link Activity#onPostCreate} method.
+     * The default implementation simply calls through to that method.
+     *
+     * @param activity The activity being created.
+     * @param icicle The previously frozen state (or null) to pass through to
+     *               onPostCreate().
+     */
+    public void callActivityOnPostCreate(Activity activity, Bundle icicle,
+            PersistableBundle persistentState) {
+        activity.onPostCreate(icicle, persistentState);
+    }
+
+    /**
      * Perform calling of an activity's {@link Activity#onNewIntent}
      * method.  The default implementation simply calls through to that method.
      * 
@@ -1215,7 +1261,7 @@
     /**
      * Perform calling of an activity's {@link Activity#onSaveInstanceState}
      * method.  The default implementation simply calls through to that method.
-     * 
+     *
      * @param activity The activity being saved.
      * @param outState The bundle to pass to the call.
      */
@@ -1224,6 +1270,18 @@
     }
 
     /**
+     * Perform calling of an activity's {@link Activity#onSaveInstanceState}
+     * method.  The default implementation simply calls through to that method.
+     *  @param activity The activity being saved.
+     * @param outState The bundle to pass to the call.
+     * @param outPersistentState The persistent bundle to pass to the call.
+     */
+    public void callActivityOnSaveInstanceState(Activity activity, Bundle outState,
+            PersistableBundle outPersistentState) {
+        activity.performSaveInstanceState(outState, outPersistentState);
+    }
+
+    /**
      * Perform calling of an activity's {@link Activity#onPause} method.  The
      * default implementation simply calls through to that method.
      * 
@@ -1428,7 +1486,7 @@
     }
 
     /**
-     * Like {@link #execStartActivity},
+     * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)},
      * but accepts an array of activities to be started.  Note that active
      * {@link ActivityMonitor} objects only match against the first activity in
      * the array.
@@ -1442,7 +1500,7 @@
     }
 
     /**
-     * Like {@link #execStartActivity},
+     * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)},
      * but accepts an array of activities to be started.  Note that active
      * {@link ActivityMonitor} objects only match against the first activity in
      * the array.
@@ -1545,7 +1603,8 @@
     }
 
     /**
-     * Like {@link #execStartActivity}, but for starting as a particular user.
+     * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)},
+     * but for starting as a particular user.
      *
      * @param who The Context from which the activity is being started.
      * @param contextThread The main thread of the Context from which the activity
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index aab6ed8..db91742a 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -44,8 +44,8 @@
      * you to disable / reenable the keyguard.
      */
     public class KeyguardLock {
-        private IBinder mToken = new Binder();
-        private String mTag;
+        private final IBinder mToken = new Binder();
+        private final String mTag;
 
         KeyguardLock(String tag) {
             mTag = tag;
diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java
index 96c7246..9ec7f41 100644
--- a/core/java/android/app/LauncherActivity.java
+++ b/core/java/android/app/LauncherActivity.java
@@ -340,9 +340,11 @@
         super.onCreate(icicle);
         
         mPackageManager = getPackageManager();
-    
-        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
-        setProgressBarIndeterminateVisibility(true);
+
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+            setProgressBarIndeterminateVisibility(true);
+        }
         onSetContentView();
 
         mIconResizer = new IconResizer();
@@ -357,7 +359,9 @@
         updateAlertTitle();
         updateButtonText();
 
-        setProgressBarIndeterminateVisibility(false);
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            setProgressBarIndeterminateVisibility(false);
+        }
     }
 
     private void updateAlertTitle() {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 25a1493..76a6a8e 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -17,7 +17,7 @@
 package android.app;
 
 import com.android.internal.R;
-import com.android.internal.util.LegacyNotificationUtil;
+import com.android.internal.util.NotificationColorUtil;
 
 import android.annotation.IntDef;
 import android.content.Context;
@@ -28,6 +28,7 @@
 import android.media.AudioManager;
 import android.net.Uri;
 import android.os.BadParcelableException;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -420,6 +421,21 @@
     @Priority
     public int priority;
 
+    /**
+     * Accent color (an ARGB integer like the constants in {@link android.graphics.Color})
+     * to be applied by the standard Style templates when presenting this notification.
+     *
+     * The current template design constructs a colorful header image by overlaying the
+     * {@link #icon} image (stenciled in white) atop a field of this color. Alpha components are
+     * ignored.
+     */
+    public int color = COLOR_DEFAULT;
+
+    /**
+     * Special value of {@link #color} telling the system not to decorate this notification with
+     * any special color but instead use default colors when presenting this notification.
+     */
+    public static final int COLOR_DEFAULT = 0; // AKA Color.TRANSPARENT
 
     /**
      * Sphere of visibility of this notification, which affects how and when the SystemUI reveals 
@@ -643,8 +659,8 @@
 
     /**
      * @hide
-     * Extra added by NotificationManagerService to indicate whether a NotificationScorer
-     * modified the Notifications's score.
+     * Extra added by NotificationManagerService to indicate whether
+     * the Notifications's score has been modified.
      */
     public static final String EXTRA_SCORE_MODIFIED = "android.scoreModified";
 
@@ -877,6 +893,8 @@
         if (parcel.readInt() != 0) {
             publicVersion = Notification.CREATOR.createFromParcel(parcel);
         }
+
+        color = parcel.readInt();
     }
 
     @Override
@@ -968,6 +986,8 @@
             this.publicVersion.cloneInto(that.publicVersion, heavy);
         }
 
+        that.color = this.color;
+
         if (!heavy) {
             that.lightenPayload(); // will clean out extras
         }
@@ -1110,6 +1130,8 @@
         } else {
             parcel.writeInt(0);
         }
+
+        parcel.writeInt(color);
     }
 
     /**
@@ -1218,6 +1240,7 @@
         sb.append(Integer.toHexString(this.defaults));
         sb.append(" flags=0x");
         sb.append(Integer.toHexString(this.flags));
+        sb.append(String.format(" color=0x%08x", this.color));
         sb.append(" category="); sb.append(this.category);
         if (actions != null) {
             sb.append(" ");
@@ -1309,9 +1332,10 @@
         private boolean mShowWhen = true;
         private int mVisibility = VISIBILITY_PRIVATE;
         private Notification mPublicVersion = null;
-        private boolean mQuantumTheme;
-        private final LegacyNotificationUtil mLegacyNotificationUtil;
+        private final NotificationColorUtil mColorUtil;
         private ArrayList<String> mPeople;
+        private boolean mPreQuantum;
+        private int mColor = COLOR_DEFAULT;
 
         /**
          * Constructs a new Builder with the defaults:
@@ -1341,12 +1365,8 @@
             mPriority = PRIORITY_DEFAULT;
             mPeople = new ArrayList<String>();
 
-            // TODO: Decide on targetSdk from calling app whether to use quantum theme.
-            mQuantumTheme = true;
-
-            // TODO: Decide on targetSdk from calling app whether to instantiate the processor at
-            // all.
-            mLegacyNotificationUtil = LegacyNotificationUtil.getInstance();
+            mPreQuantum = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.L;
+            mColorUtil = NotificationColorUtil.getInstance();
         }
 
         /**
@@ -1853,29 +1873,38 @@
             }
         }
 
+        /**
+         * Sets {@link Notification#color}.
+         *
+         * @param argb The accent color to use
+         *
+         * @return The same Builder.
+         */
+        public Builder setColor(int argb) {
+            mColor = argb;
+            return this;
+        }
+
         private RemoteViews applyStandardTemplate(int resId, boolean fitIn1U) {
             RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId);
             boolean showLine3 = false;
             boolean showLine2 = false;
             int smallIconImageViewId = R.id.icon;
-            if (!mQuantumTheme && mPriority < PRIORITY_LOW) {
-                contentView.setInt(R.id.icon,
-                        "setBackgroundResource", R.drawable.notification_template_icon_low_bg);
-                contentView.setInt(R.id.status_bar_latest_event_content,
-                        "setBackgroundResource", R.drawable.notification_bg_low);
+            if (mPriority < PRIORITY_LOW) {
+                // TODO: Low priority presentation
             }
             if (mLargeIcon != null) {
                 contentView.setImageViewBitmap(R.id.icon, mLargeIcon);
-                processLegacyLargeIcon(mLargeIcon, contentView);
+                processLargeIcon(mLargeIcon, contentView);
                 smallIconImageViewId = R.id.right_icon;
             }
             if (mSmallIcon != 0) {
                 contentView.setImageViewResource(smallIconImageViewId, mSmallIcon);
                 contentView.setViewVisibility(smallIconImageViewId, View.VISIBLE);
                 if (mLargeIcon != null) {
-                    processLegacySmallIcon(mSmallIcon, smallIconImageViewId, contentView);
+                    processSmallRightIcon(mSmallIcon, smallIconImageViewId, contentView);
                 } else {
-                    processLegacyLargeIcon(mSmallIcon, contentView);
+                    processSmallIconAsLarge(mSmallIcon, contentView);
                 }
 
             } else {
@@ -2035,12 +2064,12 @@
          *         doesn't create quantum notifications by itself) app.
          */
         private boolean isLegacy() {
-            return mLegacyNotificationUtil != null;
+            return mColorUtil != null;
         }
 
         private void processLegacyAction(Action action, RemoteViews button) {
             if (isLegacy()) {
-                if (mLegacyNotificationUtil.isGrayscale(mContext, action.icon)) {
+                if (mColorUtil.isGrayscale(mContext, action.icon)) {
                     button.setTextViewCompoundDrawablesRelativeColorFilter(R.id.action0, 0,
                             mContext.getResources().getColor(
                                     R.color.notification_action_legacy_color_filter),
@@ -2051,47 +2080,70 @@
 
         private CharSequence processLegacyText(CharSequence charSequence) {
             if (isLegacy()) {
-                return mLegacyNotificationUtil.invertCharSequenceColors(charSequence);
+                return mColorUtil.invertCharSequenceColors(charSequence);
             } else {
                 return charSequence;
             }
         }
 
-        private void processLegacyLargeIcon(int largeIconId, RemoteViews contentView) {
-            if (isLegacy()) {
-                processLegacyLargeIcon(
-                        mLegacyNotificationUtil.isGrayscale(mContext, largeIconId),
-                        contentView);
+        /**
+         * Apply any necessary background to smallIcons being used in the largeIcon spot.
+         */
+        private void processSmallIconAsLarge(int largeIconId, RemoteViews contentView) {
+            if (!isLegacy() || mColorUtil.isGrayscale(mContext, largeIconId)) {
+                applyLargeIconBackground(contentView);
             }
         }
 
-        private void processLegacyLargeIcon(Bitmap largeIcon, RemoteViews contentView) {
-            if (isLegacy()) {
-                processLegacyLargeIcon(
-                        mLegacyNotificationUtil.isGrayscale(largeIcon),
-                        contentView);
+        /**
+         * Apply any necessary background to a largeIcon if it's a fake smallIcon (that is,
+         * if it's grayscale).
+         */
+        // TODO: also check bounds, transparency, that sort of thing.
+        private void processLargeIcon(Bitmap largeIcon, RemoteViews contentView) {
+            if (!isLegacy() || mColorUtil.isGrayscale(largeIcon)) {
+                applyLargeIconBackground(contentView);
             }
         }
 
-        private void processLegacyLargeIcon(boolean isGrayscale, RemoteViews contentView) {
-            if (isLegacy() && isGrayscale) {
-                contentView.setInt(R.id.icon, "setBackgroundResource",
-                        R.drawable.notification_icon_legacy_bg_inset);
-            }
+        /**
+         * Add a colored circle behind the largeIcon slot.
+         */
+        private void applyLargeIconBackground(RemoteViews contentView) {
+            contentView.setInt(R.id.icon, "setBackgroundResource",
+                    R.drawable.notification_icon_legacy_bg_inset);
+
+            contentView.setDrawableParameters(
+                    R.id.icon,
+                    true,
+                    -1,
+                    mColor,
+                    PorterDuff.Mode.SRC_ATOP,
+                    -1);
         }
 
-        private void processLegacySmallIcon(int smallIconDrawableId, int smallIconImageViewId,
+        /**
+         * Recolor small icons when used in the R.id.right_icon slot.
+         */
+        private void processSmallRightIcon(int smallIconDrawableId, int smallIconImageViewId,
                 RemoteViews contentView) {
-            if (isLegacy()) {
-                if (mLegacyNotificationUtil.isGrayscale(mContext, smallIconDrawableId)) {
-                    contentView.setDrawableParameters(smallIconImageViewId, false, -1,
-                            mContext.getResources().getColor(
-                                    R.color.notification_action_legacy_color_filter),
-                            PorterDuff.Mode.MULTIPLY, -1);
-                }
+            if (!isLegacy() || mColorUtil.isGrayscale(mContext, smallIconDrawableId)) {
+                contentView.setDrawableParameters(smallIconImageViewId, false, -1,
+                        mContext.getResources().getColor(
+                                R.color.notification_action_legacy_color_filter),
+                        PorterDuff.Mode.MULTIPLY, -1);
             }
         }
 
+        private int resolveColor() {
+            if (mColor == COLOR_DEFAULT) {
+                mColor = mContext.getResources().getColor(R.color.notification_icon_bg_color);
+            } else {
+                mColor |= 0xFF000000; // no alpha for custom colors
+            }
+            return mColor;
+        }
+
         /**
          * Apply the unstyled operations and return a new {@link Notification} object.
          * @hide
@@ -2102,6 +2154,9 @@
             n.icon = mSmallIcon;
             n.iconLevel = mSmallIconLevel;
             n.number = mNumber;
+
+            n.color = resolveColor();
+
             n.contentView = makeContentView();
             n.contentIntent = mContentIntent;
             n.deleteIntent = mDeleteIntent;
@@ -2207,45 +2262,31 @@
 
 
         private int getBaseLayoutResource() {
-            return mQuantumTheme
-                    ? R.layout.notification_template_quantum_base
-                    : R.layout.notification_template_base;
+            return R.layout.notification_template_quantum_base;
         }
 
         private int getBigBaseLayoutResource() {
-            return mQuantumTheme
-                    ? R.layout.notification_template_quantum_big_base
-                    : R.layout.notification_template_big_base;
+            return R.layout.notification_template_quantum_big_base;
         }
 
         private int getBigPictureLayoutResource() {
-            return mQuantumTheme
-                    ? R.layout.notification_template_quantum_big_picture
-                    : R.layout.notification_template_big_picture;
+            return R.layout.notification_template_quantum_big_picture;
         }
 
         private int getBigTextLayoutResource() {
-            return mQuantumTheme
-                    ? R.layout.notification_template_quantum_big_text
-                    : R.layout.notification_template_big_text;
+            return R.layout.notification_template_quantum_big_text;
         }
 
         private int getInboxLayoutResource() {
-            return mQuantumTheme
-                    ? R.layout.notification_template_quantum_inbox
-                    : R.layout.notification_template_inbox;
+            return R.layout.notification_template_quantum_inbox;
         }
 
         private int getActionLayoutResource() {
-            return mQuantumTheme
-                    ? R.layout.notification_quantum_action
-                    : R.layout.notification_action;
+            return R.layout.notification_quantum_action;
         }
 
         private int getActionTombstoneLayoutResource() {
-            return mQuantumTheme
-                    ? R.layout.notification_quantum_action_tombstone
-                    : R.layout.notification_action_tombstone;
+            return R.layout.notification_quantum_action_tombstone;
         }
     }
 
diff --git a/core/java/android/app/PackageInstallObserver.java b/core/java/android/app/PackageInstallObserver.java
index dacffb4..941efbd 100644
--- a/core/java/android/app/PackageInstallObserver.java
+++ b/core/java/android/app/PackageInstallObserver.java
@@ -18,32 +18,36 @@
 
 import android.content.pm.IPackageInstallObserver2;
 import android.os.Bundle;
-import android.os.RemoteException;
 
-/**
- * @hide
- *
- * New-style observer for package installers to use.
- */
+/** {@hide} */
 public class PackageInstallObserver {
-    IPackageInstallObserver2.Stub mObserver = new IPackageInstallObserver2.Stub() {
+    private final IPackageInstallObserver2.Stub mBinder = new IPackageInstallObserver2.Stub() {
         @Override
-        public void packageInstalled(String pkgName, Bundle extras, int result)
-                throws RemoteException {
-            PackageInstallObserver.this.packageInstalled(pkgName, extras, result);
+        public void packageInstalled(String basePackageName, Bundle extras, int returnCode) {
+            PackageInstallObserver.this.packageInstalled(basePackageName, extras, returnCode);
         }
     };
 
+    /** {@hide} */
+    public IPackageInstallObserver2.Stub getBinder() {
+        return mBinder;
+    }
+
     /**
-     * This method will be called to report the result of the package installation attempt.
+     * This method will be called to report the result of the package
+     * installation attempt.
      *
-     * @param pkgName Name of the package whose installation was attempted
-     * @param extras If non-null, this Bundle contains extras providing additional information
-     *        about an install failure.  See {@link android.content.pm.PackageManager} for
-     *        documentation about which extras apply to various failures; in particular the
-     *        strings named EXTRA_FAILURE_*.
-     * @param result The numeric success or failure code indicating the basic outcome
+     * @param basePackageName Name of the package whose installation was
+     *            attempted
+     * @param extras If non-null, this Bundle contains extras providing
+     *            additional information about an install failure. See
+     *            {@link android.content.pm.PackageManager} for documentation
+     *            about which extras apply to various failures; in particular
+     *            the strings named EXTRA_FAILURE_*.
+     * @param returnCode The numeric success or failure code indicating the
+     *            basic outcome
+     * @hide
      */
-    public void packageInstalled(String pkgName, Bundle extras, int result) {
+    public void packageInstalled(String basePackageName, Bundle extras, int returnCode) {
     }
 }
diff --git a/core/java/android/app/PackageUninstallObserver.java b/core/java/android/app/PackageUninstallObserver.java
new file mode 100644
index 0000000..0a960a7
--- /dev/null
+++ b/core/java/android/app/PackageUninstallObserver.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.app;
+
+import android.content.pm.IPackageDeleteObserver;
+
+/** {@hide} */
+public class PackageUninstallObserver {
+    private final IPackageDeleteObserver.Stub mBinder = new IPackageDeleteObserver.Stub() {
+        @Override
+        public void packageDeleted(String basePackageName, int returnCode) {
+            PackageUninstallObserver.this.onUninstallFinished(basePackageName, returnCode);
+        }
+    };
+
+    /** {@hide} */
+    public IPackageDeleteObserver.Stub getBinder() {
+        return mBinder;
+    }
+
+    public void onUninstallFinished(String basePackageName, int returnCode) {
+    }
+}
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 5cf61a8..ce5306f 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -60,6 +60,7 @@
             | DISABLE_SEARCH;
 
     public static final int NAVIGATION_HINT_BACK_ALT      = 1 << 0;
+    public static final int NAVIGATION_HINT_IME_SHOWN     = 1 << 1;
 
     public static final int WINDOW_STATUS_BAR = 1;
     public static final int WINDOW_NAVIGATION_BAR = 2;
diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
index a85c61f..8cf8c25 100644
--- a/core/java/android/app/TimePickerDialog.java
+++ b/core/java/android/app/TimePickerDialog.java
@@ -110,6 +110,7 @@
                 (LayoutInflater) themeContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         View view = inflater.inflate(R.layout.time_picker_dialog, null);
         setView(view);
+        setButtonPanelLayoutHint(LAYOUT_HINT_SIDE);
         mTimePicker = (TimePicker) view.findViewById(R.id.timePicker);
 
         // Initialize state
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 9405325..64e3484 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -26,6 +26,7 @@
 import android.graphics.Point;
 import android.hardware.display.DisplayManagerGlobal;
 import android.os.Looper;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.Log;
@@ -40,7 +41,9 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityWindowInfo;
 import android.view.accessibility.IAccessibilityInteractionConnection;
+import libcore.io.IoUtils;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeoutException;
@@ -840,6 +843,44 @@
         return null;
     }
 
+    /**
+     * Executes a shell command. This method returs a file descriptor that points
+     * to the standard output stream. The command execution is similar to running
+     * "adb shell <command>" from a host connected to the device.
+     * <p>
+     * <strong>Note:</strong> It is your responsibility to close the retunred file
+     * descriptor once you are done reading.
+     * </p>
+     *
+     * @param command The command to execute.
+     * @return A file descriptor to the standard output stream.
+     */
+    public ParcelFileDescriptor executeShellCommand(String command) {
+        synchronized (mLock) {
+            throwIfNotConnectedLocked();
+        }
+
+        ParcelFileDescriptor source = null;
+        ParcelFileDescriptor sink = null;
+
+        try {
+            ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
+            source = pipe[0];
+            sink = pipe[1];
+
+            // Calling out without a lock held.
+            mUiAutomationConnection.executeShellCommand(command, sink);
+        } catch (IOException ioe) {
+            Log.e(LOG_TAG, "Error executing shell command!", ioe);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error executing shell command!", re);
+        } finally {
+            IoUtils.closeQuietly(sink);
+        }
+
+        return source;
+    }
+
     private static float getDegreesForRotation(int value) {
         switch (value) {
             case Surface.ROTATION_90: {
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index fa40286..81bcb39 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -23,6 +23,7 @@
 import android.hardware.input.InputManager;
 import android.os.Binder;
 import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -33,6 +34,12 @@
 import android.view.WindowContentFrameStats;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.IAccessibilityManager;
+import libcore.io.IoUtils;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 
 /**
  * This is a remote object that is passed from the shell to an instrumentation
@@ -50,8 +57,8 @@
     private final IWindowManager mWindowManager = IWindowManager.Stub.asInterface(
             ServiceManager.getService(Service.WINDOW_SERVICE));
 
-    private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager.Stub.asInterface(
-            ServiceManager.getService(Service.ACCESSIBILITY_SERVICE));
+    private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager.Stub
+            .asInterface(ServiceManager.getService(Service.ACCESSIBILITY_SERVICE));
 
     private final Object mLock = new Object();
 
@@ -220,6 +227,41 @@
     }
 
     @Override
+    public void executeShellCommand(String command, ParcelFileDescriptor sink)
+            throws RemoteException {
+        synchronized (mLock) {
+            throwIfCalledByNotTrustedUidLocked();
+            throwIfShutdownLocked();
+            throwIfNotConnectedLocked();
+        }
+
+        InputStream in = null;
+        OutputStream out = null;
+
+        try {
+            java.lang.Process process = Runtime.getRuntime().exec(command);
+
+            in = process.getInputStream();
+            out = new FileOutputStream(sink.getFileDescriptor());
+
+            final byte[] buffer = new byte[8192];
+            while (true) {
+                final int readByteCount = in.read(buffer);
+                if (readByteCount < 0) {
+                    break;
+                }
+                out.write(buffer, 0, readByteCount);
+            }
+        } catch (IOException ioe) {
+            throw new RuntimeException("Error running shell command", ioe);
+        } finally {
+            IoUtils.closeQuietly(in);
+            IoUtils.closeQuietly(out);
+            IoUtils.closeQuietly(sink);
+        }
+    }
+
+    @Override
     public void shutdown() {
         synchronized (mLock) {
             if (isConnectedLocked()) {
diff --git a/core/java/android/app/UsageStats.aidl b/core/java/android/app/UsageStats.aidl
new file mode 100644
index 0000000..7dee70a
--- /dev/null
+++ b/core/java/android/app/UsageStats.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 UsageStats;
+parcelable UsageStats.PackageStats;
diff --git a/core/java/android/app/UsageStats.java b/core/java/android/app/UsageStats.java
new file mode 100644
index 0000000..0aeba59
--- /dev/null
+++ b/core/java/android/app/UsageStats.java
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.content.res.Configuration;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.util.ArrayMap;
+
+import java.util.Map;
+
+/**
+ * Snapshot of current usage stats data.
+ * @hide
+ */
+public class UsageStats implements Parcelable {
+    /** @hide */
+    public final ArrayMap<String, PackageStats> mPackages = new ArrayMap<String, PackageStats>();
+    /** @hide */
+    public final ArrayMap<Configuration, ConfigurationStats> mConfigurations
+            = new ArrayMap<Configuration, ConfigurationStats>();
+
+    public static class PackageStats implements Parcelable {
+        private final String mPackageName;
+        private int mLaunchCount;
+        private long mUsageTime;
+        private long mResumedTime;
+
+        /** @hide */
+        public final ArrayMap<String, Long> componentResumeTimes;
+
+        public static final Parcelable.Creator<PackageStats> CREATOR
+                = new Parcelable.Creator<PackageStats>() {
+            public PackageStats createFromParcel(Parcel in) {
+                return new PackageStats(in);
+            }
+
+            public PackageStats[] newArray(int size) {
+                return new PackageStats[size];
+            }
+        };
+
+        public String toString() {
+            return "PackageStats{"
+            + Integer.toHexString(System.identityHashCode(this))
+            + " " + mPackageName + "}";
+        }
+
+        /** @hide */
+        public PackageStats(String pkgName) {
+            mPackageName = pkgName;
+            componentResumeTimes = new ArrayMap<String, Long>();
+        }
+
+        /** @hide */
+        public PackageStats(String pkgName, int count, long time, Map<String, Long> lastResumeTimes) {
+            mPackageName = pkgName;
+            mLaunchCount = count;
+            mUsageTime = time;
+            componentResumeTimes = new ArrayMap<String, Long>();
+            componentResumeTimes.putAll(lastResumeTimes);
+        }
+
+        /** @hide */
+        public PackageStats(Parcel source) {
+            mPackageName = source.readString();
+            mLaunchCount = source.readInt();
+            mUsageTime = source.readLong();
+            final int N = source.readInt();
+            componentResumeTimes = new ArrayMap<String, Long>(N);
+            for (int i = 0; i < N; i++) {
+                String component = source.readString();
+                long lastResumeTime = source.readLong();
+                componentResumeTimes.put(component, lastResumeTime);
+            }
+        }
+
+        /** @hide */
+        public PackageStats(PackageStats pStats) {
+            mPackageName = pStats.mPackageName;
+            mLaunchCount = pStats.mLaunchCount;
+            mUsageTime = pStats.mUsageTime;
+            componentResumeTimes = new ArrayMap<String, Long>(pStats.componentResumeTimes);
+        }
+
+        /** @hide */
+        public void resume(boolean launched) {
+            if (launched) {
+                mLaunchCount++;
+            }
+            mResumedTime = SystemClock.elapsedRealtime();
+        }
+
+        /** @hide */
+        public void pause() {
+            if (mResumedTime > 0) {
+                mUsageTime += SystemClock.elapsedRealtime() - mResumedTime;
+            }
+            mResumedTime = 0;
+        }
+
+        public final String getPackageName() {
+            return mPackageName;
+        }
+
+        public final long getUsageTime(long elapsedRealtime) {
+            return mUsageTime + (mResumedTime > 0 ? (elapsedRealtime- mResumedTime) : 0);
+        }
+
+        public final int getLaunchCount() {
+            return mLaunchCount;
+        }
+
+        /** @hide */
+        public boolean clearUsageTimes() {
+            mLaunchCount = 0;
+            mUsageTime = 0;
+            return mResumedTime <= 0 && componentResumeTimes.isEmpty();
+        }
+
+        public final int describeContents() {
+            return 0;
+        }
+
+        public final void writeToParcel(Parcel dest, int parcelableFlags) {
+            writeToParcel(dest, parcelableFlags, 0);
+        }
+
+        final void writeToParcel(Parcel dest, int parcelableFlags, long elapsedRealtime) {
+            dest.writeString(mPackageName);
+            dest.writeInt(mLaunchCount);
+            dest.writeLong(elapsedRealtime > 0 ? getUsageTime(elapsedRealtime) : mUsageTime);
+            dest.writeInt(componentResumeTimes.size());
+            for (Map.Entry<String, Long> ent : componentResumeTimes.entrySet()) {
+                dest.writeString(ent.getKey());
+                dest.writeLong(ent.getValue());
+            }
+        }
+
+        /** @hide */
+        public void writeExtendedToParcel(Parcel dest, int parcelableFlags) {
+        }
+    }
+
+    public static class ConfigurationStats implements Parcelable {
+        private final Configuration mConfiguration;
+        private long mLastUsedTime;
+        private int mUsageCount;
+        private long mUsageTime;
+        private long mStartedTime;
+
+        public static final Parcelable.Creator<ConfigurationStats> CREATOR
+                = new Parcelable.Creator<ConfigurationStats>() {
+            public ConfigurationStats createFromParcel(Parcel in) {
+                return new ConfigurationStats(in);
+            }
+
+            public ConfigurationStats[] newArray(int size) {
+                return new ConfigurationStats[size];
+            }
+        };
+
+        public String toString() {
+            return "ConfigurationStats{"
+            + Integer.toHexString(System.identityHashCode(this))
+            + " " + mConfiguration + "}";
+        }
+
+        /** @hide */
+        public ConfigurationStats(Configuration config) {
+            mConfiguration = config;
+        }
+
+        /** @hide */
+        public ConfigurationStats(Parcel source) {
+            mConfiguration = Configuration.CREATOR.createFromParcel(source);
+            mLastUsedTime = source.readLong();
+            mUsageCount = source.readInt();
+            mUsageTime = source.readLong();
+        }
+
+        /** @hide */
+        public ConfigurationStats(ConfigurationStats pStats) {
+            mConfiguration = pStats.mConfiguration;
+            mLastUsedTime = pStats.mLastUsedTime;
+            mUsageCount = pStats.mUsageCount;
+            mUsageTime = pStats.mUsageTime;
+        }
+
+        public final Configuration getConfiguration() {
+            return mConfiguration;
+        }
+
+        public final long getLastUsedTime() {
+            return mLastUsedTime;
+        }
+
+        public final long getUsageTime(long elapsedRealtime) {
+            return mUsageTime + (mStartedTime > 0 ? (elapsedRealtime- mStartedTime) : 0);
+        }
+
+        public final int getUsageCount() {
+            return mUsageCount;
+        }
+
+        /** @hide */
+        public void start() {
+            mLastUsedTime = System.currentTimeMillis();
+            mUsageCount++;
+            mStartedTime = SystemClock.elapsedRealtime();
+        }
+
+        /** @hide */
+        public void stop() {
+            if (mStartedTime > 0) {
+                mUsageTime += SystemClock.elapsedRealtime() - mStartedTime;
+            }
+            mStartedTime = 0;
+        }
+
+        /** @hide */
+        public boolean clearUsageTimes() {
+            mUsageCount = 0;
+            mUsageTime = 0;
+            return mLastUsedTime == 0 && mStartedTime <= 0;
+        }
+
+        public final int describeContents() {
+            return 0;
+        }
+
+        public final void writeToParcel(Parcel dest, int parcelableFlags) {
+            writeToParcel(dest, parcelableFlags, 0);
+        }
+
+        final void writeToParcel(Parcel dest, int parcelableFlags, long elapsedRealtime) {
+            mConfiguration.writeToParcel(dest, parcelableFlags);
+            dest.writeLong(mLastUsedTime);
+            dest.writeInt(mUsageCount);
+            dest.writeLong(elapsedRealtime > 0 ? getUsageTime(elapsedRealtime) : mUsageTime);
+        }
+
+        /** @hide */
+        public void writeExtendedToParcel(Parcel dest, int parcelableFlags) {
+        }
+    }
+
+    /** @hide */
+    public UsageStats() {
+    }
+
+    /** @hide */
+    public UsageStats(Parcel source, boolean extended) {
+        int N = source.readInt();
+        for (int i=0; i<N; i++) {
+            PackageStats pkg = extended ? onNewPackageStats(source) : new PackageStats(source);
+            mPackages.put(pkg.getPackageName(), pkg);
+        }
+        N = source.readInt();
+        for (int i=0; i<N; i++) {
+            ConfigurationStats config = extended ? onNewConfigurationStats(source)
+                    : new ConfigurationStats(source);
+            mConfigurations.put(config.getConfiguration(), config);
+        }
+    }
+
+    public int getPackageStatsCount() {
+        return mPackages.size();
+    }
+
+    public PackageStats getPackageStatsAt(int index) {
+        return mPackages.valueAt(index);
+    }
+
+    public PackageStats getPackageStats(String pkgName) {
+        return mPackages.get(pkgName);
+    }
+
+    /** @hide */
+    public PackageStats getOrCreatePackageStats(String pkgName) {
+        PackageStats ps = mPackages.get(pkgName);
+        if (ps == null) {
+            ps = onNewPackageStats(pkgName);
+            mPackages.put(pkgName, ps);
+        }
+        return ps;
+    }
+
+    public int getConfigurationStatsCount() {
+        return mConfigurations.size();
+    }
+
+    public ConfigurationStats getConfigurationStatsAt(int index) {
+        return mConfigurations.valueAt(index);
+    }
+
+    public ConfigurationStats getConfigurationStats(Configuration config) {
+        return mConfigurations.get(config);
+    }
+
+    /** @hide */
+    public ConfigurationStats getOrCreateConfigurationStats(Configuration config) {
+        ConfigurationStats cs = mConfigurations.get(config);
+        if (cs == null) {
+            cs = onNewConfigurationStats(config);
+            mConfigurations.put(config, cs);
+        }
+        return cs;
+    }
+
+    /** @hide */
+    public void clearUsageTimes() {
+        for (int i=mPackages.size()-1; i>=0; i--) {
+            if (mPackages.valueAt(i).clearUsageTimes()) {
+                mPackages.removeAt(i);
+            }
+        }
+        for (int i=mConfigurations.size()-1; i>=0; i--) {
+            if (mConfigurations.valueAt(i).clearUsageTimes()) {
+                mConfigurations.removeAt(i);
+            }
+        }
+    }
+
+    /** @hide */
+    public PackageStats onNewPackageStats(String pkgName) {
+        return new PackageStats(pkgName);
+    }
+
+    /** @hide */
+    public PackageStats onNewPackageStats(Parcel source) {
+        return new PackageStats(source);
+    }
+
+    /** @hide */
+    public ConfigurationStats onNewConfigurationStats(Configuration config) {
+        return new ConfigurationStats(config);
+    }
+
+    /** @hide */
+    public ConfigurationStats onNewConfigurationStats(Parcel source) {
+        return new ConfigurationStats(source);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel dest, int parcelableFlags) {
+        writeToParcelInner(dest, parcelableFlags, false);
+    }
+
+    /** @hide */
+    public void writeExtendedToParcel(Parcel dest, int parcelableFlags) {
+        writeToParcelInner(dest, parcelableFlags, true);
+    }
+
+    private void writeToParcelInner(Parcel dest, int parcelableFlags, boolean extended) {
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
+
+        int N = mPackages.size();
+        dest.writeInt(N);
+        for (int i=0; i<N; i++) {
+            PackageStats ps = mPackages.valueAt(i);
+            ps.writeToParcel(dest, parcelableFlags, elapsedRealtime);
+            if (extended) {
+                ps.writeExtendedToParcel(dest, parcelableFlags);
+            }
+        }
+        N = mConfigurations.size();
+        dest.writeInt(N);
+        for (int i=0; i<N; i++) {
+            ConfigurationStats cs = mConfigurations.valueAt(i);
+            cs.writeToParcel(dest, parcelableFlags, elapsedRealtime);
+            if (extended) {
+                cs.writeExtendedToParcel(dest, parcelableFlags);
+            }
+        }
+    }
+
+    public static final Parcelable.Creator<UsageStats> CREATOR
+            = new Parcelable.Creator<UsageStats>() {
+        public UsageStats createFromParcel(Parcel in) {
+            return new UsageStats(in, false);
+        }
+
+        public UsageStats[] newArray(int size) {
+            return new UsageStats[size];
+        }
+    };
+}
diff --git a/core/java/android/app/UsageStatsManager.java b/core/java/android/app/UsageStatsManager.java
new file mode 100644
index 0000000..fbf9c3b
--- /dev/null
+++ b/core/java/android/app/UsageStatsManager.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.content.Context;
+import android.os.ParcelableParcel;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import com.android.internal.app.IUsageStats;
+
+/**
+ * Access to usage stats data.
+ * @hide
+ */
+public class UsageStatsManager {
+    final Context mContext;
+    final IUsageStats mService;
+
+    /** @hide */
+    public UsageStatsManager(Context context) {
+        mContext = context;
+        mService = IUsageStats.Stub.asInterface(ServiceManager.getService(
+                Context.USAGE_STATS_SERVICE));
+    }
+
+    public UsageStats getCurrentStats() {
+        try {
+            ParcelableParcel in = mService.getCurrentStats(mContext.getOpPackageName());
+            if (in != null) {
+                return new UsageStats(in.getParcel(), false);
+            }
+        } catch (RemoteException e) {
+            // About to die.
+        }
+        return new UsageStats();
+    }
+}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 5f8ebbe..58d707c 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -651,6 +651,10 @@
      *         not "image/*"
      */
     public Intent getCropAndSetWallpaperIntent(Uri imageUri) {
+        if (imageUri == null) {
+            throw new IllegalArgumentException("Image URI must not be null");
+        }
+
         if (!ContentResolver.SCHEME_CONTENT.equals(imageUri.getScheme())) {
             throw new IllegalArgumentException("Image URI must be of the "
                     + ContentResolver.SCHEME_CONTENT + " scheme type");
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 68ab611..8884446 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -16,12 +16,11 @@
 
 package android.app.admin;
 
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
@@ -38,6 +37,8 @@
 
 import com.android.org.conscrypt.TrustedCertificateStore;
 
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.net.InetSocketAddress;
@@ -172,6 +173,16 @@
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_SET_NEW_PASSWORD
             = "android.app.action.SET_NEW_PASSWORD";
+    /**
+     * Flag for {@link #addForwardingIntentFilter}: the intents will forwarded to the primary user.
+     */
+    public static int FLAG_TO_PRIMARY_USER = 0x0001;
+
+    /**
+     * Flag for {@link #addForwardingIntentFilter}: the intents will be forwarded to the managed
+     * profile.
+     */
+    public static int FLAG_TO_MANAGED_PROFILE = 0x0002;
 
     /**
      * Return true if the given administrator component is currently
@@ -348,8 +359,8 @@
     }
 
     /**
-     * Retrieve the current minimum password quality for all admins
-     * or a particular one.
+     * Retrieve the current minimum password quality for all admins of this user
+     * and its profiles or a particular one.
      * @param admin The name of the admin component to check, or null to aggregate
      * all admins.
      */
@@ -401,8 +412,8 @@
     }
 
     /**
-     * Retrieve the current minimum password length for all admins
-     * or a particular one.
+     * Retrieve the current minimum password length for all admins of this
+     * user and its profiles or a particular one.
      * @param admin The name of the admin component to check, or null to aggregate
      * all admins.
      */
@@ -456,8 +467,9 @@
 
     /**
      * Retrieve the current number of upper case letters required in the
-     * password for all admins or a particular one. This is the same value as
-     * set by {#link {@link #setPasswordMinimumUpperCase(ComponentName, int)}
+     * password for all admins of this user and its profiles or a particular one.
+     * This is the same value as set by
+     * {#link {@link #setPasswordMinimumUpperCase(ComponentName, int)}
      * and only applies when the password quality is
      * {@link #PASSWORD_QUALITY_COMPLEX}.
      *
@@ -516,8 +528,9 @@
 
     /**
      * Retrieve the current number of lower case letters required in the
-     * password for all admins or a particular one. This is the same value as
-     * set by {#link {@link #setPasswordMinimumLowerCase(ComponentName, int)}
+     * password for all admins of this user and its profiles or a particular one.
+     * This is the same value as set by
+     * {#link {@link #setPasswordMinimumLowerCase(ComponentName, int)}
      * and only applies when the password quality is
      * {@link #PASSWORD_QUALITY_COMPLEX}.
      *
@@ -633,8 +646,9 @@
 
     /**
      * Retrieve the current number of numerical digits required in the password
-     * for all admins or a particular one. This is the same value as
-     * set by {#link {@link #setPasswordMinimumNumeric(ComponentName, int)}
+     * for all admins of this user and its profiles or a particular one.
+     * This is the same value as set by
+     * {#link {@link #setPasswordMinimumNumeric(ComponentName, int)}
      * and only applies when the password quality is
      * {@link #PASSWORD_QUALITY_COMPLEX}.
      *
@@ -749,8 +763,9 @@
 
     /**
      * Retrieve the current number of non-letter characters required in the
-     * password for all admins or a particular one. This is the same value as
-     * set by {#link {@link #setPasswordMinimumNonLetter(ComponentName, int)}
+     * password for all admins of this user and its profiles or a particular one.
+     * This is the same value as set by
+     * {#link {@link #setPasswordMinimumNonLetter(ComponentName, int)}
      * and only applies when the password quality is
      * {@link #PASSWORD_QUALITY_COMPLEX}.
      *
@@ -857,9 +872,10 @@
 
     /**
      * Get the current password expiration time for the given admin or an aggregate of
-     * all admins if admin is null. If the password is expired, this will return the time since
-     * the password expired as a negative number.  If admin is null, then a composite of all
-     * expiration timeouts is returned - which will be the minimum of all timeouts.
+     * all admins of this user and its profiles if admin is null. If the password is
+     * expired, this will return the time since the password expired as a negative number.
+     * If admin is null, then a composite of all expiration timeouts is returned
+     * - which will be the minimum of all timeouts.
      *
      * @param admin The name of the admin component to check, or null to aggregate all admins.
      * @return The password expiration time, in ms.
@@ -876,8 +892,8 @@
     }
 
     /**
-     * Retrieve the current password history length for all admins
-     * or a particular one.
+     * Retrieve the current password history length for all admins of this
+     * user and its profiles or a particular one.
      * @param admin The name of the admin component to check, or null to aggregate
      * all admins.
      * @return The length of the password history
@@ -912,14 +928,13 @@
     /**
      * Determine whether the current password the user has set is sufficient
      * to meet the policy requirements (quality, minimum length) that have been
-     * requested.
+     * requested by the admins of this user and its profiles.
      *
      * <p>The calling device admin must have requested
      * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
      * this method; if it has not, a security exception will be thrown.
      *
-     * @return Returns true if the password meets the current requirements,
-     * else false.
+     * @return Returns true if the password meets the current requirements, else false.
      */
     public boolean isActivePasswordSufficient() {
         if (mService != null) {
@@ -982,7 +997,7 @@
 
     /**
      * Retrieve the current maximum number of login attempts that are allowed
-     * before the device wipes itself, for all admins
+     * before the device wipes itself, for all admins of this user and its profiles
      * or a particular one.
      * @param admin The name of the admin component to check, or null to aggregate
      * all admins.
@@ -1026,6 +1041,8 @@
      * {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD} to be able to call
      * this method; if it has not, a security exception will be thrown.
      *
+     * Can not be called from a managed profile.
+     *
      * @param password The new password for the user.
      * @param flags May be 0 or {@link #RESET_PASSWORD_REQUIRE_ENTRY}.
      * @return Returns true if the password was applied, or false if it is
@@ -1066,8 +1083,8 @@
     }
 
     /**
-     * Retrieve the current maximum time to unlock for all admins
-     * or a particular one.
+     * Retrieve the current maximum time to unlock for all admins of this user
+     * and its profiles or a particular one.
      * @param admin The name of the admin component to check, or null to aggregate
      * all admins.
      */
@@ -1778,7 +1795,7 @@
      * Sets the enabled state of the profile. A profile should be enabled only once it is ready to
      * be used. Only the profile owner can call this.
      *
-     * @see #isPRofileOwnerApp
+     * @see #isProfileOwnerApp
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      */
@@ -1834,27 +1851,6 @@
 
     /**
      * @hide
-     * @param userId the userId of a managed profile profile.
-     *
-     * @return whether or not the managed profile is enabled.
-     * @throws IllegalArgumentException if the userId is invalid.
-     */
-    public boolean isProfileEnabled(int userId) throws IllegalArgumentException {
-        if (mService != null) {
-            try {
-                return mService.isProfileEnabled(userId);
-            } catch (RemoteException re) {
-                Log.w(TAG, "Failed to get status for owner profile.");
-                throw new IllegalArgumentException(
-                        "Failed to get status for owner profile.", re);
-            }
-        }
-        return true;
-    }
-
-
-    /**
-     * @hide
      * @return the human readable name of the organisation associated with this DPM or null if
      *         one is not set.
      * @throws IllegalArgumentException if the userId is invalid.
@@ -1953,6 +1949,39 @@
     }
 
     /**
+     * Called by a profile owner to forward intents sent from the managed profile to the owner, or
+     * from the owner to the managed profile.
+     * If an intent matches this intent filter, then activities belonging to the other user can
+     * respond to this intent.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param filter if an intent matches this IntentFilter, then it can be forwarded.
+     */
+    public void addForwardingIntentFilter(ComponentName admin, IntentFilter filter, int flags) {
+        if (mService != null) {
+            try {
+                mService.addForwardingIntentFilter(admin, filter, flags);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+
+    /**
+     * Called by a profile owner to remove the forwarding intent filters from the current user
+     * and from the owner.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     */
+    public void clearForwardingIntentFilters(ComponentName admin) {
+        if (mService != null) {
+            try {
+                mService.clearForwardingIntentFilters(admin);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+
+    /**
      * Called by a profile or device owner to get the application restrictions for a given target
      * application running in the managed profile.
      *
@@ -2019,4 +2048,137 @@
             }
         }
     }
+
+    /**
+     * Called by profile or device owner to re-enable a system app that was disabled by default
+     * when the managed profile was created. This should only be called from a profile or device
+     * owner running within a managed profile.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param packageName The package to be re-enabled in the current profile.
+     */
+    public void enableSystemApp(ComponentName admin, String packageName) {
+        if (mService != null) {
+            try {
+                mService.enableSystemApp(admin, packageName);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to install package: " + packageName);
+            }
+        }
+    }
+
+    /**
+     * Called by profile or device owner to re-enable system apps by intent that were disabled
+     * by default when the managed profile was created. This should only be called from a profile
+     * or device owner running within a managed profile.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param intent An intent matching the app(s) to be installed. All apps that resolve for this
+     *               intent will be re-enabled in the current profile.
+     * @return int The number of activities that matched the intent and were installed.
+     */
+    public int enableSystemApp(ComponentName admin, Intent intent) {
+        if (mService != null) {
+            try {
+                return mService.enableSystemAppWithIntent(admin, intent);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to install packages matching filter: " + intent);
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * Called by a profile owner to disable account management for a specific type of account.
+     *
+     * <p>The calling device admin must be a profile owner. If it is not, a
+     * security exception will be thrown.
+     *
+     * <p>When account management is disabled for an account type, adding or removing an account
+     * of that type will not be possible.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param accountType For which account management is disabled or enabled.
+     * @param disabled The boolean indicating that account management will be disabled (true) or
+     * enabled (false).
+     */
+    public void setAccountManagementDisabled(ComponentName admin, String accountType,
+            boolean disabled) {
+        if (mService != null) {
+            try {
+                mService.setAccountManagementDisabled(admin, accountType, disabled);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+
+    /**
+     * Gets the array of accounts for which account management is disabled by the profile owner.
+     *
+     * <p> Account management can be disabled/enabled by calling
+     * {@link #setAccountManagementDisabled}.
+     *
+     * @return a list of account types for which account management has been disabled.
+     *
+     * @see #setAccountManagementDisabled
+     */
+    public String[] getAccountTypesWithManagementDisabled() {
+        if (mService != null) {
+            try {
+                return mService.getAccountTypesWithManagementDisabled();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Sets which components may enter lock task mode.
+     *
+     * This function can only be called by the device owner or the profile owner.
+     * @param components The list of components allowed to enter lock task mode
+     */
+    public void setLockTaskComponents(ComponentName[] components) throws SecurityException {
+        if (mService != null) {
+            try {
+                mService.setLockTaskComponents(components);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+
+    /**
+     * This function returns the list of components allowed to start the lock task mode.
+     * @hide
+     */
+    public ComponentName[] getLockTaskComponents() {
+        if (mService != null) {
+            try {
+                return mService.getLockTaskComponents();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * This function lets the caller know whether the given component is allowed to start the
+     * lock task mode.
+     * @param component The component to check
+     */
+    public boolean isLockTaskPermitted(ComponentName component) {
+        if (mService != null) {
+            try {
+                return mService.isLockTaskPermitted(component);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return false;
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 72b3c20..03ced0f 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -18,6 +18,7 @@
 package android.app.admin;
 
 import android.content.ComponentName;
+import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Bundle;
 import android.os.RemoteCallback;
@@ -109,7 +110,6 @@
     String getProfileOwner(int userHandle);
     String getProfileOwnerName(int userHandle);
     void setProfileEnabled(in ComponentName who);
-    boolean isProfileEnabled(int userHandle);
 
     boolean installCaCert(in byte[] certBuffer);
     void uninstallCaCert(in byte[] certBuffer);
@@ -121,4 +121,16 @@
     Bundle getApplicationRestrictions(in ComponentName who, in String packageName);
 
     void setUserRestriction(in ComponentName who, in String key, boolean enable);
+    void addForwardingIntentFilter(in ComponentName admin, in IntentFilter filter, int flags);
+    void clearForwardingIntentFilters(in ComponentName admin);
+
+    void enableSystemApp(in ComponentName admin, in String packageName);
+    int enableSystemAppWithIntent(in ComponentName admin, in Intent intent);
+
+    void setAccountManagementDisabled(in ComponentName who, in String accountType, in boolean disabled);
+    String[] getAccountTypesWithManagementDisabled();
+
+    void setLockTaskComponents(in ComponentName[] components);
+    ComponentName[] getLockTaskComponents();
+    boolean isLockTaskPermitted(in ComponentName component);
 }
diff --git a/core/java/android/app/task/ITaskCallback.aidl b/core/java/android/app/task/ITaskCallback.aidl
new file mode 100644
index 0000000..ffa57d1
--- /dev/null
+++ b/core/java/android/app/task/ITaskCallback.aidl
@@ -0,0 +1,53 @@
+/**
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.task;
+
+import android.app.task.ITaskService;
+import android.app.task.TaskParams;
+
+/**
+ * The server side of the TaskManager IPC protocols.  The app-side implementation
+ * invokes on this interface to indicate completion of the (asynchronous) instructions
+ * issued by the server.
+ *
+ * In all cases, the 'who' parameter is the caller's service binder, used to track
+ * which Task Service instance is reporting.
+ *
+ * {@hide}
+ */
+interface ITaskCallback {
+    /**
+     * Immediate callback to the system after sending a start signal, used to quickly detect ANR.
+     *
+     * @param taskId Unique integer used to identify this task.
+     */
+    void acknowledgeStartMessage(int taskId);
+    /**
+     * Immediate callback to the system after sending a stop signal, used to quickly detect ANR.
+     *
+     * @param taskId Unique integer used to identify this task.
+     */
+    void acknowledgeStopMessage(int taskId);
+    /*
+     * Tell the task manager that the client is done with its execution, so that it can go on to
+     * the next one and stop attributing wakelock time to us etc.
+     *
+     * @param taskId Unique integer used to identify this task.
+     * @param reschedule Whether or not to reschedule this task.
+     */
+    void taskFinished(int taskId, boolean reschedule);
+}
diff --git a/core/java/android/app/task/ITaskService.aidl b/core/java/android/app/task/ITaskService.aidl
new file mode 100644
index 0000000..87b0191
--- /dev/null
+++ b/core/java/android/app/task/ITaskService.aidl
@@ -0,0 +1,35 @@
+/**
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.task;
+
+import android.app.task.ITaskCallback;
+import android.app.task.TaskParams;
+
+import android.os.Bundle;
+
+/**
+ * Interface that the framework uses to communicate with application code that implements a
+ * TaskService.  End user code does not implement this interface directly; instead, the app's
+ * service implementation will extend android.app.task.TaskService.
+ * {@hide}
+ */
+oneway interface ITaskService {
+    /** Begin execution of application's task. */
+    void startTask(in TaskParams taskParams);
+    /** Stop execution of application's task. */
+    void stopTask(in TaskParams taskParams);
+}
diff --git a/core/java/android/app/task/TaskParams.aidl b/core/java/android/app/task/TaskParams.aidl
new file mode 100644
index 0000000..9b25855
--- /dev/null
+++ b/core/java/android/app/task/TaskParams.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.task;
+
+parcelable TaskParams;
\ No newline at end of file
diff --git a/core/java/android/app/task/TaskParams.java b/core/java/android/app/task/TaskParams.java
new file mode 100644
index 0000000..0351082
--- /dev/null
+++ b/core/java/android/app/task/TaskParams.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.app.task;
+
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Contains the parameters used to configure/identify your task. You do not create this object
+ * yourself, instead it is handed in to your application by the System.
+ */
+public class TaskParams implements Parcelable {
+
+    private final int taskId;
+    private final Bundle extras;
+    private final IBinder callback;
+
+    /** @hide */
+    public TaskParams(int taskId, Bundle extras, IBinder callback) {
+        this.taskId = taskId;
+        this.extras = extras;
+        this.callback = callback;
+    }
+
+    /**
+     * @return The unique id of this task, specified at creation time.
+     */
+    public int getTaskId() {
+        return taskId;
+    }
+
+    /**
+     * @return The extras you passed in when constructing this task with
+     * {@link android.content.Task.Builder#setExtras(android.os.Bundle)}. This will
+     * never be null. If you did not set any extras this will be an empty bundle.
+     */
+    public Bundle getExtras() {
+        return extras;
+    }
+
+    /** @hide */
+    public ITaskCallback getCallback() {
+        return ITaskCallback.Stub.asInterface(callback);
+    }
+
+    private TaskParams(Parcel in) {
+        taskId = in.readInt();
+        extras = in.readBundle();
+        callback = in.readStrongBinder();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(taskId);
+        dest.writeBundle(extras);
+        dest.writeStrongBinder(callback);
+    }
+
+    public static final Creator<TaskParams> CREATOR = new Creator<TaskParams>() {
+        @Override
+        public TaskParams createFromParcel(Parcel in) {
+            return new TaskParams(in);
+        }
+
+        @Override
+        public TaskParams[] newArray(int size) {
+            return new TaskParams[size];
+        }
+    };
+}
diff --git a/core/java/android/app/task/TaskService.java b/core/java/android/app/task/TaskService.java
new file mode 100644
index 0000000..81333be
--- /dev/null
+++ b/core/java/android/app/task/TaskService.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.app.task;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * <p>Entry point for the callback from the {@link android.content.TaskManager}.</p>
+ * <p>This is the base class that handles asynchronous requests that were previously scheduled. You
+ * are responsible for overriding {@link TaskService#onStartTask(TaskParams)}, which is where
+ * you will implement your task logic.</p>
+ * <p>This service executes each incoming task on a {@link android.os.Handler} running on your
+ * application's main thread. This means that you <b>must</b> offload your execution logic to
+ * another thread/handler/{@link android.os.AsyncTask} of your choosing. Not doing so will result
+ * in blocking any future callbacks from the TaskManager - specifically
+ * {@link #onStopTask(android.app.task.TaskParams)}, which is meant to inform you that the
+ * scheduling requirements are no longer being met.</p>
+ */
+public abstract class TaskService extends Service {
+    private static final String TAG = "TaskService";
+
+    /**
+     * Task services must be protected with this permission:
+     *
+     * <pre class="prettyprint">
+     *     <service android:name="MyTaskService"
+     *              android:permission="android.permission.BIND_TASK_SERVICE" >
+     *         ...
+     *     </service>
+     * </pre>
+     *
+     * <p>If a task service is declared in the manifest but not protected with this
+     * permission, that service will be ignored by the OS.
+     */
+    public static final String PERMISSION_BIND =
+            "android.permission.BIND_TASK_SERVICE";
+
+    /**
+     * Identifier for a message that will result in a call to
+     * {@link #onStartTask(android.app.task.TaskParams)}.
+     */
+    private final int MSG_EXECUTE_TASK = 0;
+    /**
+     * Message that will result in a call to {@link #onStopTask(android.app.task.TaskParams)}.
+     */
+    private final int MSG_STOP_TASK = 1;
+    /**
+     * Message that the client has completed execution of this task.
+     */
+    private final int MSG_TASK_FINISHED = 2;
+
+    /** Lock object for {@link #mHandler}. */
+    private final Object mHandlerLock = new Object();
+
+    /**
+     * Handler we post tasks to. Responsible for calling into the client logic, and handling the
+     * callback to the system.
+     */
+    @GuardedBy("mHandlerLock")
+    TaskHandler mHandler;
+
+    /** Binder for this service. */
+    ITaskService mBinder = new ITaskService.Stub() {
+        @Override
+        public void startTask(TaskParams taskParams) {
+            ensureHandler();
+            Message m = Message.obtain(mHandler, MSG_EXECUTE_TASK, taskParams);
+            m.sendToTarget();
+        }
+        @Override
+        public void stopTask(TaskParams taskParams) {
+            ensureHandler();
+            Message m = Message.obtain(mHandler, MSG_STOP_TASK, taskParams);
+            m.sendToTarget();
+        }
+    };
+
+    /** @hide */
+    void ensureHandler() {
+        synchronized (mHandlerLock) {
+            if (mHandler == null) {
+                mHandler = new TaskHandler(getMainLooper());
+            }
+        }
+    }
+
+    /**
+     * Runs on application's main thread - callbacks are meant to offboard work to some other
+     * (app-specified) mechanism.
+     * @hide
+     */
+    class TaskHandler extends Handler {
+        TaskHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            final TaskParams params = (TaskParams) msg.obj;
+            switch (msg.what) {
+                case MSG_EXECUTE_TASK:
+                    try {
+                        TaskService.this.onStartTask(params);
+                    } catch (Exception e) {
+                        Log.e(TAG, "Error while executing task: " + params.getTaskId());
+                        throw new RuntimeException(e);
+                    } finally {
+                        maybeAckMessageReceived(params, MSG_EXECUTE_TASK);
+                    }
+                    break;
+                case MSG_STOP_TASK:
+                    try {
+                        TaskService.this.onStopTask(params);
+                    } catch (Exception e) {
+                        Log.e(TAG, "Application unable to handle onStopTask.", e);
+                        throw new RuntimeException(e);
+                    } finally {
+                        maybeAckMessageReceived(params, MSG_STOP_TASK);
+                    }
+                    break;
+                case MSG_TASK_FINISHED:
+                    final boolean needsReschedule = (msg.arg2 == 1);
+                    ITaskCallback callback = params.getCallback();
+                    if (callback != null) {
+                        try {
+                            callback.taskFinished(params.getTaskId(), needsReschedule);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Error reporting task finish to system: binder has gone" +
+                                    "away.");
+                        }
+                    } else {
+                        Log.e(TAG, "finishTask() called for a nonexistent task id.");
+                    }
+                    break;
+                default:
+                    Log.e(TAG, "Unrecognised message received.");
+                    break;
+            }
+        }
+
+        /**
+         * Messages come in on the application's main thread, so rather than run the risk of
+         * waiting for an app that may be doing something foolhardy, we ack to the system after
+         * processing a message. This allows us to throw up an ANR dialogue as quickly as possible.
+         * @param params id of the task we're acking.
+         * @param state Information about what message we're acking.
+         */
+        private void maybeAckMessageReceived(TaskParams params, int state) {
+            final ITaskCallback callback = params.getCallback();
+            final int taskId = params.getTaskId();
+            if (callback != null) {
+                try {
+                    if (state == MSG_EXECUTE_TASK) {
+                        callback.acknowledgeStartMessage(taskId);
+                    } else if (state == MSG_STOP_TASK) {
+                        callback.acknowledgeStopMessage(taskId);
+                    }
+                } catch(RemoteException e) {
+                    Log.e(TAG, "System unreachable for starting task.");
+                }
+            } else {
+                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                    Log.d(TAG, state + ": Attempting to ack a task that has already been" +
+                            "processed.");
+                }
+            }
+        }
+    }
+
+    /** @hide */
+    public final IBinder onBind(Intent intent) {
+        return mBinder.asBinder();
+    }
+
+    /**
+     * Override this method with the callback logic for your task. Any such logic needs to be
+     * performed on a separate thread, as this function is executed on your application's main
+     * thread.
+     *
+     * @param params Parameters specifying info about this task, including the extras bundle you
+     *               optionally provided at task-creation time.
+     */
+    public abstract void onStartTask(TaskParams params);
+
+    /**
+     * This method is called if your task should be stopped even before you've called
+     * {@link #taskFinished(TaskParams, boolean)}.
+     *
+     * <p>This will happen if the requirements specified at schedule time are no longer met. For
+     * example you may have requested WiFi with
+     * {@link android.content.Task.Builder#setRequiredNetworkCapabilities(int)}, yet while your
+     * task was executing the user toggled WiFi. Another example is if you had specified
+     * {@link android.content.Task.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
+     * idle maintenance window. You are solely responsible for the behaviour of your application
+     * upon receipt of this message; your app will likely start to misbehave if you ignore it. One
+     * repercussion is that the system will cease to hold a wakelock for you.</p>
+     *
+     * <p>After you've done your clean-up you are still expected to call
+     * {@link #taskFinished(TaskParams, boolean)} this will inform the TaskManager that all is well, and
+     * allow you to reschedule your task as it is probably uncompleted. Until you call
+     * taskFinished() you will not receive any newly scheduled tasks with the given task id as the
+     * TaskManager will consider the task to be in an error state.</p>
+     *
+     * @param params Parameters specifying info about this task.
+     * @return True to indicate to the TaskManager whether you'd like to reschedule this task based
+     * on the criteria provided at task creation-time. False to drop the task. Regardless of the
+     * value returned, your task must stop executing.
+     */
+    public abstract boolean onStopTask(TaskParams params);
+
+    /**
+     * Callback to inform the TaskManager you have completed execution. This can be called from any
+     * thread, as it will ultimately be run on your application's main thread. When the system
+     * receives this message it will release the wakelock being held.
+     * <p>
+     *     You can specify post-execution behaviour to the scheduler here with <code>needsReschedule
+     *     </code>. This will apply a back-off timer to your task based on the default, or what was
+     *     set with {@link android.content.Task.Builder#setBackoffCriteria(long, int)}. The
+     *     original requirements are always honoured even for a backed-off task.
+     *     Note that a task running in idle mode will not be backed-off. Instead what will happen
+     *     is the task will be re-added to the queue and re-executed within a future idle
+     *     maintenance window.
+     * </p>
+     *
+     * @param params Parameters specifying system-provided info about this task, this was given to
+     *               your application in {@link #onStartTask(TaskParams)}.
+     * @param needsReschedule True if this task is complete, false if you want the TaskManager to
+     *                        reschedule you.
+     */
+    public final void taskFinished(TaskParams params, boolean needsReschedule) {
+        ensureHandler();
+        Message m = Message.obtain(mHandler, MSG_TASK_FINISHED, params);
+        m.arg2 = needsReschedule ? 1 : 0;
+        m.sendToTarget();
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index dd3a871..d3e9089 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -181,7 +181,8 @@
      * A bundle extra that hints to the AppWidgetProvider the category of host that owns this
      * this widget. Can have the value {@link
      * AppWidgetProviderInfo#WIDGET_CATEGORY_HOME_SCREEN} or {@link
-     * AppWidgetProviderInfo#WIDGET_CATEGORY_KEYGUARD}.
+     * AppWidgetProviderInfo#WIDGET_CATEGORY_KEYGUARD} or {@link
+     * AppWidgetProviderInfo#WIDGET_CATEGORY_RECENTS}.
      */
     public static final String OPTION_APPWIDGET_HOST_CATEGORY = "appWidgetCategory";
 
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index 4b33799..8b9c7f0 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -54,6 +54,11 @@
     public static final int WIDGET_CATEGORY_KEYGUARD = 2;
 
     /**
+     * Indicates that the widget can be displayed within recents.
+     */
+    public static final int WIDGET_CATEGORY_RECENTS = 4;
+
+    /**
      * Identity of this AppWidget component.  This component should be a {@link
      * android.content.BroadcastReceiver}, and it will be sent the AppWidget intents
      * {@link android.appwidget as described in the AppWidget package documentation}.
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index a396a05..7f8d0ab 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -512,6 +512,25 @@
      */
     public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
 
+     /**
+      * No preferrence of physical transport for GATT connections to remote dual-mode devices
+      * @hide
+      */
+    public static final int TRANSPORT_AUTO = 0;
+
+    /**
+     * Prefer BR/EDR transport for GATT connections to remote dual-mode devices
+     * @hide
+     */
+   public static final int TRANSPORT_BREDR = 1;
+
+    /**
+     * Prefer LE transport for GATT connections to remote dual-mode devices
+     * @hide
+     */
+   public static final int TRANSPORT_LE = 2;
+
+
     /**
      * Lazy initialization. Guaranteed final after first object constructed, or
      * getService() called.
@@ -1216,6 +1235,27 @@
      */
     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
                                      BluetoothGattCallback callback) {
+        return (connectGatt(context, autoConnect,callback, TRANSPORT_AUTO));
+    }
+
+    /**
+     * Connect to GATT Server hosted by this device. Caller acts as GATT client.
+     * The callback is used to deliver results to Caller, such as connection status as well
+     * as any further GATT client operations.
+     * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
+     * GATT client operations.
+     * @param callback GATT callback handler that will receive asynchronous callbacks.
+     * @param autoConnect Whether to directly connect to the remote device (false)
+     *                    or to automatically connect as soon as the remote
+     *                    device becomes available (true).
+     * @param transport preferred transport for GATT connections to remote dual-mode devices
+     *             {@link BluetoothDevice#TRANSPORT_AUTO} or
+     *             {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE}
+     * @throws IllegalArgumentException if callback is null
+     * @hide
+     */
+    public BluetoothGatt connectGatt(Context context, boolean autoConnect,
+                                     BluetoothGattCallback callback, int transport) {
         // TODO(Bluetooth) check whether platform support BLE
         //     Do the check here or in GattServer?
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -1226,10 +1266,11 @@
                 // BLE is not supported
                 return null;
             }
-            BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this);
+            BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this, transport);
             gatt.connect(autoConnect, callback);
             return gatt;
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return null;
     }
+
 }
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index ff3af7c..601d9ee 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -51,6 +51,7 @@
     private int mConnState;
     private final Object mStateLock = new Object();
     private Boolean mDeviceBusy = false;
+    private int mTransport;
 
     private static final int CONN_STATE_IDLE = 0;
     private static final int CONN_STATE_CONNECTING = 1;
@@ -135,7 +136,7 @@
                 }
                 try {
                     mService.clientConnect(mClientIf, mDevice.getAddress(),
-                                           !mAutoConnect); // autoConnect is inverse of "isDirect"
+                                           !mAutoConnect, mTransport); // autoConnect is inverse of "isDirect"
                 } catch (RemoteException e) {
                     Log.e(TAG,"",e);
                 }
@@ -600,10 +601,12 @@
             }
         };
 
-    /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device) {
+    /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device,
+                                int transport) {
         mContext = context;
         mService = iGatt;
         mDevice = device;
+        mTransport = transport;
         mServices = new ArrayList<BluetoothGattService>();
 
         mConnState = CONN_STATE_IDLE;
@@ -759,7 +762,7 @@
     public boolean connect() {
         try {
             mService.clientConnect(mClientIf, mDevice.getAddress(),
-                                   false); // autoConnect is inverse of "isDirect"
+                                   false, mTransport); // autoConnect is inverse of "isDirect"
             return true;
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index 0c00c06..34e8605 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -50,6 +50,7 @@
 
     private Object mServerIfLock = new Object();
     private int mServerIf;
+    private int mTransport;
     private List<BluetoothGattService> mServices;
 
     private static final int CALLBACK_REG_TIMEOUT = 10000;
@@ -269,12 +270,13 @@
     /**
      * Create a BluetoothGattServer proxy object.
      */
-    /*package*/ BluetoothGattServer(Context context, IBluetoothGatt iGatt) {
+    /*package*/ BluetoothGattServer(Context context, IBluetoothGatt iGatt, int transport) {
         mContext = context;
         mService = iGatt;
         mAdapter = BluetoothAdapter.getDefaultAdapter();
         mCallback = null;
         mServerIf = 0;
+        mTransport = transport;
         mServices = new ArrayList<BluetoothGattService>();
     }
 
@@ -401,7 +403,7 @@
 
         try {
             mService.serverConnect(mServerIf, device.getAddress(),
-                               autoConnect ? false : true); // autoConnect is inverse of "isDirect"
+                               autoConnect ? false : true,mTransport); // autoConnect is inverse of "isDirect"
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             return false;
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index 172f3bc..b1618cf3 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -194,6 +194,26 @@
      */
     public BluetoothGattServer openGattServer(Context context,
                                               BluetoothGattServerCallback callback) {
+
+        return (openGattServer (context, callback, BluetoothDevice.TRANSPORT_AUTO));
+    }
+
+    /**
+     * Open a GATT Server
+     * The callback is used to deliver results to Caller, such as connection status as well
+     * as the results of any other GATT server operations.
+     * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer
+     * to conduct GATT server operations.
+     * @param context App context
+     * @param callback GATT server callback handler that will receive asynchronous callbacks.
+     * @param transport preferred transport for GATT connections to remote dual-mode devices
+     *             {@link BluetoothDevice#TRANSPORT_AUTO} or
+     *             {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE}
+     * @return BluetoothGattServer instance
+     * @hide
+     */
+    public BluetoothGattServer openGattServer(Context context,
+                                              BluetoothGattServerCallback callback,int transport) {
         if (context == null || callback == null) {
             throw new IllegalArgumentException("null parameter: " + context + " " + callback);
         }
@@ -208,7 +228,7 @@
                 Log.e(TAG, "Fail to get GATT Server connection");
                 return null;
             }
-            BluetoothGattServer mGattServer = new BluetoothGattServer(context, iGatt);
+            BluetoothGattServer mGattServer = new BluetoothGattServer(context, iGatt,transport);
             Boolean regStatus = mGattServer.registerCallback(callback);
             return regStatus? mGattServer : null;
         } catch (RemoteException e) {
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index f532f7c..00fd7ce 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -325,6 +325,7 @@
             }
         } catch (RemoteException e) {
             Log.e(TAG, Log.getStackTraceString(new Throwable()));
+            throw new IOException("unable to send RPC: " + e.getMessage());
         }
     }
 
diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
index 6dd551e..f0c8299 100644
--- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
+++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
@@ -20,7 +20,7 @@
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.DhcpResults;
-import android.net.LinkCapabilities;
+import android.net.NetworkCapabilities;
 import android.net.LinkProperties;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
@@ -53,6 +53,9 @@
     private static final boolean DBG = true;
     private static final boolean VDBG = true;
 
+    // Event sent to the mBtdtHandler when DHCP fails so we can tear down the network.
+    private static final int EVENT_NETWORK_FAILED = 1;
+
     private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
     private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
     private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
@@ -72,7 +75,7 @@
     private BluetoothTetheringDataTracker() {
         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_BLUETOOTH, 0, NETWORKTYPE, "");
         mLinkProperties = new LinkProperties();
-        mLinkCapabilities = new LinkCapabilities();
+        mNetworkCapabilities = new NetworkCapabilities();
 
         mNetworkInfo.setIsAvailable(false);
         setTeardownRequested(false);
@@ -239,16 +242,6 @@
         }
     }
 
-   /**
-     * A capability is an Integer/String pair, the capabilities
-     * are defined in the class LinkSocket#Key.
-     *
-     * @return a copy of this connections capabilities, may be empty but never null.
-     */
-    public LinkCapabilities getLinkCapabilities() {
-        return new LinkCapabilities(mLinkCapabilities);
-    }
-
     /**
      * Fetch default gateway address for the network
      */
@@ -315,6 +308,7 @@
                     }
                     if (!success) {
                         Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
+                        mBtdtHandler.obtainMessage(EVENT_NETWORK_FAILED).sendToTarget();
                         return;
                     }
                     mLinkProperties = dhcpResults.linkProperties;
@@ -407,6 +401,10 @@
                     if (VDBG) Log.d(TAG, "got EVENT_NETWORK_DISCONNECTED, " + linkProperties);
                     mBtdt.stopReverseTether();
                     break;
+                case EVENT_NETWORK_FAILED:
+                    if (VDBG) Log.d(TAG, "got EVENT_NETWORK_FAILED");
+                    mBtdt.teardown();
+                    break;
             }
         }
     }
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 4b28516..ab53fb0 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -18,6 +18,8 @@
 
 import android.os.ParcelUuid;
 
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.UUID;
@@ -76,6 +78,12 @@
     public static final ParcelUuid BASE_UUID =
             ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
 
+    /** Length of bytes for 16 bit UUID */
+    public static final int UUID_BYTES_16_BIT = 2;
+    /** Length of bytes for 32 bit UUID */
+    public static final int UUID_BYTES_32_BIT = 4;
+    /** Length of bytes for 128 bit UUID */
+    public static final int UUID_BYTES_128_BIT = 16;
 
     public static final ParcelUuid[] RESERVED_UUIDS = {
         AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
@@ -216,15 +224,60 @@
     }
 
     /**
+     * Parse UUID from bytes. The {@code uuidBytes} can represent a 16-bit, 32-bit or 128-bit UUID,
+     * but the returned UUID is always in 128-bit format.
+     * Note UUID is little endian in Bluetooth.
+     *
+     * @param uuidBytes Byte representation of uuid.
+     * @return {@link ParcelUuid} parsed from bytes.
+     * @throws IllegalArgumentException If the {@code uuidBytes} cannot be parsed.
+     */
+    public static ParcelUuid parseUuidFrom(byte[] uuidBytes) {
+        if (uuidBytes == null) {
+            throw new IllegalArgumentException("uuidBytes cannot be null");
+        }
+        int length = uuidBytes.length;
+        if (length != UUID_BYTES_16_BIT && length != UUID_BYTES_32_BIT &&
+                length != UUID_BYTES_128_BIT) {
+            throw new IllegalArgumentException("uuidBytes length invalid - " + length);
+        }
+
+        // Construct a 128 bit UUID.
+        if (length == UUID_BYTES_128_BIT) {
+            ByteBuffer buf = ByteBuffer.wrap(uuidBytes).order(ByteOrder.LITTLE_ENDIAN);
+            long msb = buf.getLong(8);
+            long lsb = buf.getLong(0);
+            return new ParcelUuid(new UUID(msb, lsb));
+        }
+
+        // For 16 bit and 32 bit UUID we need to convert them to 128 bit value.
+        // 128_bit_value = uuid * 2^96 + BASE_UUID
+        long shortUuid;
+        if (length == UUID_BYTES_16_BIT) {
+            shortUuid = uuidBytes[0] & 0xFF;
+            shortUuid += (uuidBytes[1] & 0xFF) << 8;
+        } else {
+            shortUuid = uuidBytes[0] & 0xFF ;
+            shortUuid += (uuidBytes[1] & 0xFF) << 8;
+            shortUuid += (uuidBytes[2] & 0xFF) << 16;
+            shortUuid += (uuidBytes[3] & 0xFF) << 24;
+        }
+        long msb = BASE_UUID.getUuid().getMostSignificantBits() + (shortUuid << 32);
+        long lsb = BASE_UUID.getUuid().getLeastSignificantBits();
+        return new ParcelUuid(new UUID(msb, lsb));
+    }
+
+    /**
      * Check whether the given parcelUuid can be converted to 16 bit bluetooth uuid.
+     *
      * @param parcelUuid
      * @return true if the parcelUuid can be converted to 16 bit uuid, false otherwise.
      */
     public static boolean isShortUuid(ParcelUuid parcelUuid) {
-      UUID uuid = parcelUuid.getUuid();
-      if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
-        return false;
-      }
-      return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L);
+        UUID uuid = parcelUuid.getUuid();
+        if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
+            return false;
+        }
+        return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L);
     }
 }
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index c6b5c3d..49b156d 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -35,7 +35,7 @@
 
     void registerClient(in ParcelUuid appId, in IBluetoothGattCallback callback);
     void unregisterClient(in int clientIf);
-    void clientConnect(in int clientIf, in String address, in boolean isDirect);
+    void clientConnect(in int clientIf, in String address, in boolean isDirect, in int transport);
     void clientDisconnect(in int clientIf, in String address);
     void startAdvertising(in int appIf);
     void stopAdvertising();
@@ -77,7 +77,7 @@
 
     void registerServer(in ParcelUuid appId, in IBluetoothGattServerCallback callback);
     void unregisterServer(in int serverIf);
-    void serverConnect(in int servertIf, in String address, in boolean isDirect);
+    void serverConnect(in int servertIf, in String address, in boolean isDirect, in int transport);
     void serverDisconnect(in int serverIf, in String address);
     void beginServiceDeclaration(in int serverIf, in int srvcType,
                             in int srvcInstanceId, in int minHandles,
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 50c4fed..b44abf9 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -16,6 +16,7 @@
 
 package android.content;
 
+import static android.content.ContentProvider.maybeAddUserId;
 import android.content.res.AssetFileDescriptor;
 import android.graphics.Bitmap;
 import android.net.Uri;
@@ -186,7 +187,7 @@
         final CharSequence mText;
         final String mHtmlText;
         final Intent mIntent;
-        final Uri mUri;
+        Uri mUri;
 
         /**
          * Create an Item consisting of a single block of (possibly styled) text.
@@ -809,6 +810,24 @@
         }
     }
 
+    /**
+     * Prepare this {@link ClipData} to leave an app process.
+     *
+     * @hide
+     */
+    public void prepareToLeaveUser(int userId) {
+        final int size = mItems.size();
+        for (int i = 0; i < size; i++) {
+            final Item item = mItems.get(i);
+            if (item.mIntent != null) {
+                item.mIntent.prepareToLeaveUser(userId);
+            }
+            if (item.mUri != null) {
+                item.mUri = maybeAddUserId(item.mUri, userId);
+            }
+        }
+    }
+
     @Override
     public String toString() {
         StringBuilder b = new StringBuilder(128);
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 02c850b..be9782f 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -36,6 +36,7 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.util.Log;
+import android.text.TextUtils;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -195,6 +196,7 @@
                 return rejectQuery(uri, projection, selection, selectionArgs, sortOrder,
                         CancellationSignal.fromTransport(cancellationSignal));
             }
+            uri = getUriWithoutUserId(uri);
             final String original = setCallingPackage(callingPkg);
             try {
                 return ContentProvider.this.query(
@@ -207,6 +209,7 @@
 
         @Override
         public String getType(Uri uri) {
+            uri = getUriWithoutUserId(uri);
             return ContentProvider.this.getType(uri);
         }
 
@@ -215,9 +218,11 @@
             if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
                 return rejectInsert(uri, initialValues);
             }
+            int userId = getUserIdFromUri(uri);
+            uri = getUriWithoutUserId(uri);
             final String original = setCallingPackage(callingPkg);
             try {
-                return ContentProvider.this.insert(uri, initialValues);
+                return maybeAddUserId(ContentProvider.this.insert(uri, initialValues), userId);
             } finally {
                 setCallingPackage(original);
             }
@@ -228,6 +233,7 @@
             if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
+            uri = getUriWithoutUserId(uri);
             final String original = setCallingPackage(callingPkg);
             try {
                 return ContentProvider.this.bulkInsert(uri, initialValues);
@@ -240,24 +246,39 @@
         public ContentProviderResult[] applyBatch(String callingPkg,
                 ArrayList<ContentProviderOperation> operations)
                 throws OperationApplicationException {
-            for (ContentProviderOperation operation : operations) {
+            int numOperations = operations.size();
+            final int[] userIds = new int[numOperations];
+            for (int i = 0; i < numOperations; i++) {
+                ContentProviderOperation operation = operations.get(i);
+                userIds[i] = getUserIdFromUri(operation.getUri());
                 if (operation.isReadOperation()) {
                     if (enforceReadPermission(callingPkg, operation.getUri())
                             != AppOpsManager.MODE_ALLOWED) {
                         throw new OperationApplicationException("App op not allowed", 0);
                     }
                 }
-
                 if (operation.isWriteOperation()) {
                     if (enforceWritePermission(callingPkg, operation.getUri())
                             != AppOpsManager.MODE_ALLOWED) {
                         throw new OperationApplicationException("App op not allowed", 0);
                     }
                 }
+                if (userIds[i] != UserHandle.USER_CURRENT) {
+                    // Removing the user id from the uri.
+                    operation = new ContentProviderOperation(operation, true);
+                }
+                operations.set(i, operation);
             }
             final String original = setCallingPackage(callingPkg);
             try {
-                return ContentProvider.this.applyBatch(operations);
+                ContentProviderResult[] results = ContentProvider.this.applyBatch(operations);
+                for (int i = 0; i < results.length ; i++) {
+                    if (userIds[i] != UserHandle.USER_CURRENT) {
+                        // Adding the userId to the uri.
+                        results[i] = new ContentProviderResult(results[i], userIds[i]);
+                    }
+                }
+                return results;
             } finally {
                 setCallingPackage(original);
             }
@@ -268,6 +289,7 @@
             if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
+            uri = getUriWithoutUserId(uri);
             final String original = setCallingPackage(callingPkg);
             try {
                 return ContentProvider.this.delete(uri, selection, selectionArgs);
@@ -282,6 +304,7 @@
             if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
+            uri = getUriWithoutUserId(uri);
             final String original = setCallingPackage(callingPkg);
             try {
                 return ContentProvider.this.update(uri, values, selection, selectionArgs);
@@ -295,6 +318,7 @@
                 String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
                 throws FileNotFoundException {
             enforceFilePermission(callingPkg, uri, mode);
+            uri = getUriWithoutUserId(uri);
             final String original = setCallingPackage(callingPkg);
             try {
                 return ContentProvider.this.openFile(
@@ -309,6 +333,7 @@
                 String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
                 throws FileNotFoundException {
             enforceFilePermission(callingPkg, uri, mode);
+            uri = getUriWithoutUserId(uri);
             final String original = setCallingPackage(callingPkg);
             try {
                 return ContentProvider.this.openAssetFile(
@@ -330,6 +355,7 @@
 
         @Override
         public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
+            uri = getUriWithoutUserId(uri);
             return ContentProvider.this.getStreamTypes(uri, mimeTypeFilter);
         }
 
@@ -337,6 +363,7 @@
         public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
                 Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
             enforceFilePermission(callingPkg, uri, "r");
+            uri = getUriWithoutUserId(uri);
             final String original = setCallingPackage(callingPkg);
             try {
                 return ContentProvider.this.openTypedAssetFile(
@@ -356,9 +383,11 @@
             if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
                 return null;
             }
+            int userId = getUserIdFromUri(uri);
+            uri = getUriWithoutUserId(uri);
             final String original = setCallingPackage(callingPkg);
             try {
-                return ContentProvider.this.canonicalize(uri);
+                return maybeAddUserId(ContentProvider.this.canonicalize(uri), userId);
             } finally {
                 setCallingPackage(original);
             }
@@ -369,9 +398,11 @@
             if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
                 return null;
             }
+            int userId = getUserIdFromUri(uri);
+            uri = getUriWithoutUserId(uri);
             final String original = setCallingPackage(callingPkg);
             try {
-                return ContentProvider.this.uncanonicalize(uri);
+                return maybeAddUserId(ContentProvider.this.uncanonicalize(uri), userId);
             } finally {
                 setCallingPackage(original);
             }
@@ -1680,4 +1711,75 @@
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         writer.println("nothing to dump");
     }
+
+    /** @hide */
+    public static int getUserIdFromAuthority(String auth, int defaultUserId) {
+        if (auth == null) return defaultUserId;
+        int end = auth.indexOf('@');
+        if (end == -1) return defaultUserId;
+        String userIdString = auth.substring(0, end);
+        try {
+            return Integer.parseInt(userIdString);
+        } catch (NumberFormatException e) {
+            Log.w(TAG, "Error parsing userId.", e);
+            return UserHandle.USER_NULL;
+        }
+    }
+
+    /** @hide */
+    public static int getUserIdFromAuthority(String auth) {
+        return getUserIdFromAuthority(auth, UserHandle.USER_CURRENT);
+    }
+
+    /** @hide */
+    public static int getUserIdFromUri(Uri uri, int defaultUserId) {
+        if (uri == null) return defaultUserId;
+        return getUserIdFromAuthority(uri.getAuthority(), defaultUserId);
+    }
+
+    /** @hide */
+    public static int getUserIdFromUri(Uri uri) {
+        return getUserIdFromUri(uri, UserHandle.USER_CURRENT);
+    }
+
+    /**
+     * Removes userId part from authority string. Expects format:
+     * userId@some.authority
+     * If there is no userId in the authority, it symply returns the argument
+     * @hide
+     */
+    public static String getAuthorityWithoutUserId(String auth) {
+        if (auth == null) return null;
+        int end = auth.indexOf('@');
+        return auth.substring(end+1);
+    }
+
+    /** @hide */
+    public static Uri getUriWithoutUserId(Uri uri) {
+        if (uri == null) return null;
+        Uri.Builder builder = uri.buildUpon();
+        builder.authority(getAuthorityWithoutUserId(uri.getAuthority()));
+        return builder.build();
+    }
+
+    /** @hide */
+    public static boolean uriHasUserId(Uri uri) {
+        if (uri == null) return false;
+        return !TextUtils.isEmpty(uri.getUserInfo());
+    }
+
+    /** @hide */
+    public static Uri maybeAddUserId(Uri uri, int userId) {
+        if (uri == null) return null;
+        if (userId != UserHandle.USER_CURRENT
+                && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
+            if (!uriHasUserId(uri)) {
+                //We don't add the user Id if there's already one
+                Uri.Builder builder = uri.buildUpon();
+                builder.encodedAuthority("" + userId + "@" + uri.getEncodedAuthority());
+                return builder.build();
+            }
+        }
+        return uri;
+    }
 }
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index 12e9bab..136e54d 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -16,6 +16,7 @@
 
 package android.content;
 
+import android.content.ContentProvider;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Parcel;
@@ -87,6 +88,31 @@
         mYieldAllowed = source.readInt() != 0;
     }
 
+    /** @hide */
+    public ContentProviderOperation(ContentProviderOperation cpo, boolean removeUserIdFromUri) {
+        mType = cpo.mType;
+        if (removeUserIdFromUri) {
+            mUri = ContentProvider.getUriWithoutUserId(cpo.mUri);
+        } else {
+            mUri = cpo.mUri;
+        }
+        mValues = cpo.mValues;
+        mSelection = cpo.mSelection;
+        mSelectionArgs = cpo.mSelectionArgs;
+        mExpectedCount = cpo.mExpectedCount;
+        mSelectionArgsBackReferences = cpo.mSelectionArgsBackReferences;
+        mValuesBackReferences = cpo.mValuesBackReferences;
+        mYieldAllowed = cpo.mYieldAllowed;
+    }
+
+    /** @hide */
+    public ContentProviderOperation getWithoutUserIdInUri() {
+        if (ContentProvider.uriHasUserId(mUri)) {
+            return new ContentProviderOperation(this, true);
+        }
+        return this;
+    }
+
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mType);
         Uri.writeToParcel(dest, mUri);
@@ -387,7 +413,6 @@
         }
     };
 
-
     /**
      * Used to add parameters to a {@link ContentProviderOperation}. The {@link Builder} is
      * first created by calling {@link ContentProviderOperation#newInsert(android.net.Uri)},
diff --git a/core/java/android/content/ContentProviderResult.java b/core/java/android/content/ContentProviderResult.java
index 5d188ef..ec3d002 100644
--- a/core/java/android/content/ContentProviderResult.java
+++ b/core/java/android/content/ContentProviderResult.java
@@ -16,7 +16,9 @@
 
 package android.content;
 
+import android.content.ContentProvider;
 import android.net.Uri;
+import android.os.UserHandle;
 import android.os.Parcelable;
 import android.os.Parcel;
 
@@ -50,6 +52,12 @@
         }
     }
 
+    /** @hide */
+    public ContentProviderResult(ContentProviderResult cpr, int userId) {
+        uri = ContentProvider.maybeAddUserId(cpr.uri, userId);
+        count = cpr.count;
+    }
+
     public void writeToParcel(Parcel dest, int flags) {
         if (uri == null) {
             dest.writeInt(1);
@@ -81,4 +89,4 @@
         }
         return "ContentProviderResult(count=" + count + ")";
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 5b41394..7642e13 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1643,7 +1643,8 @@
      */
     public void takePersistableUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags) {
         try {
-            ActivityManagerNative.getDefault().takePersistableUriPermission(uri, modeFlags);
+            ActivityManagerNative.getDefault().takePersistableUriPermission(
+                    ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
         } catch (RemoteException e) {
         }
     }
@@ -1658,7 +1659,8 @@
      */
     public void releasePersistableUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags) {
         try {
-            ActivityManagerNative.getDefault().releasePersistableUriPermission(uri, modeFlags);
+            ActivityManagerNative.getDefault().releasePersistableUriPermission(
+                    ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
         } catch (RemoteException e) {
         }
     }
@@ -2462,4 +2464,9 @@
     private final Context mContext;
     final String mPackageName;
     private static final String TAG = "ContentResolver";
+
+    /** @hide */
+    public int resolveUserId(Uri uri) {
+        return ContentProvider.getUserIdFromUri(uri, mContext.getUserId());
+    }
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index de223a3..a059e48 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1982,6 +1982,7 @@
             WIFI_SERVICE,
             WIFI_HOTSPOT_SERVICE,
             WIFI_P2P_SERVICE,
+            WIFI_SCANNING_SERVICE,
             NSD_SERVICE,
             AUDIO_SERVICE,
             MEDIA_ROUTER_SERVICE,
@@ -2054,6 +2055,9 @@
      *  <dt> {@link #WIFI_SERVICE} ("wifi")
      *  <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of
      * Wi-Fi connectivity.
+     *  <dt> {@link #WIFI_P2P_SERVICE} ("wifip2p")
+     *  <dd> A {@link android.net.wifi.p2p.WifiP2pManager WifiP2pManager} for management of
+     * Wi-Fi Direct connectivity.
      * <dt> {@link #INPUT_METHOD_SERVICE} ("input_method")
      * <dd> An {@link android.view.inputmethod.InputMethodManager InputMethodManager}
      * for management of input methods.
@@ -2357,6 +2361,16 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
+     * android.net.wifi.WifiScanner} for scanning the wifi universe
+     *
+     * @see #getSystemService
+     * @see android.net.wifi.WifiScanner
+     * @hide
+     */
+    public static final String WIFI_SCANNING_SERVICE = "wifiscanner";
+
+    /**
+     * Use with {@link #getSystemService} to retrieve a {@link
      * android.net.nsd.NsdManager} for handling management of network service
      * discovery
      *
@@ -2377,6 +2391,16 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a
+     * {@link android.service.fingerprint.FingerprintManager} for handling management
+     * of fingerprints.
+     *
+     * @see #getSystemService
+     * @see android.app.FingerprintManager
+     */
+    public static final String FINGERPRINT_SERVICE = "fingerprint";
+
+    /**
+     * Use with {@link #getSystemService} to retrieve a
      * {@link android.media.MediaRouter} for controlling and managing
      * routing of media.
      *
@@ -2659,6 +2683,16 @@
     public static final String NETWORK_SCORE_SERVICE = "network_score";
 
     /**
+     * Use with {@link #getSystemService} to retrieve a {@link
+     * android.app.UsageStatsManager} for interacting with the status bar.
+     *
+     * @see #getSystemService
+     * @see android.app.UsageStatsManager
+     * @hide
+     */
+    public static final String USAGE_STATS_SERVICE = "usagestats";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index ae5437b..076f657 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -26,6 +26,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.pm.ActivityInfo;
+import static android.content.ContentProvider.maybeAddUserId;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
@@ -3736,7 +3737,8 @@
      *
      * <p>When set, the activity specified by this Intent will launch into a
      * separate task rooted at that activity. The activity launched must be
-     * defined with {@link android.R.attr#launchMode} "standard" or "singleTop".
+     * defined with {@link android.R.attr#launchMode} <code>standard</code>
+     * or <code>singleTop</code>.
      *
      * <p>If FLAG_ACTIVITY_NEW_DOCUMENT is used without
      * {@link #FLAG_ACTIVITY_MULTIPLE_TASK} then the activity manager will
@@ -3751,6 +3753,8 @@
      * always create a new task. Thus the same document may be made to appear
      * more than one time in Recents.
      *
+     * <p>This is equivalent to the attribute {@link android.R.attr#documentLaunchMode}.
+     *
      * @see #FLAG_ACTIVITY_MULTIPLE_TASK
      */
     public static final int FLAG_ACTIVITY_NEW_DOCUMENT =
@@ -3815,6 +3819,15 @@
      */
     public static final int FLAG_ACTIVITY_TASK_ON_HOME = 0X00004000;
     /**
+     * If set and the new activity is the root of a new task, then the task
+     * will remain in the list of recently launched tasks only until all of
+     * the activities in it are finished.
+     *
+     * <p>This is equivalent to the attribute
+     * {@link android.R.styleable#AndroidManifestActivity_autoRemoveFromRecents}.
+     */
+    public static final int FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS = 0x00002000;
+    /**
      * If set, when sending a broadcast only registered receivers will be
      * called -- no BroadcastReceiver components will be launched.
      */
@@ -4019,7 +4032,7 @@
 
     /**
      * Create an intent for a specific component with a specified action and data.
-     * This is equivalent using {@link #Intent(String, android.net.Uri)} to
+     * This is equivalent to using {@link #Intent(String, android.net.Uri)} to
      * construct the Intent and then calling {@link #setClass} to set its
      * class.
      *
@@ -7421,6 +7434,41 @@
     }
 
     /**
+     * Prepare this {@link Intent} to be sent to another user
+     *
+     * @hide
+     */
+    public void prepareToLeaveUser(int userId) {
+        Uri data = getData();
+        if (data != null) {
+            mData = maybeAddUserId(data, userId);
+        }
+        if (mSelector != null) {
+            mSelector.prepareToLeaveUser(userId);
+        }
+        if (mClipData != null) {
+            mClipData.prepareToLeaveUser(userId);
+        }
+        String action = getAction();
+        if (ACTION_SEND.equals(action)) {
+            final Uri stream = getParcelableExtra(EXTRA_STREAM);
+            if (stream != null) {
+                putExtra(EXTRA_STREAM, maybeAddUserId(stream, userId));
+            }
+        }
+        if (ACTION_SEND_MULTIPLE.equals(action)) {
+            final ArrayList<Uri> streams = getParcelableArrayListExtra(EXTRA_STREAM);
+            if (streams != null) {
+                ArrayList<Uri> newStreams = new ArrayList<Uri>();
+                for (int i = 0; i < streams.size(); i++) {
+                    newStreams.add(maybeAddUserId(streams.get(i), userId));
+                }
+                putParcelableArrayListExtra(EXTRA_STREAM, newStreams);
+            }
+        }
+    }
+
+    /**
      * Migrate any {@link #EXTRA_STREAM} in {@link #ACTION_SEND} and
      * {@link #ACTION_SEND_MULTIPLE} to {@link ClipData}. Also inspects nested
      * intents in {@link #ACTION_CHOOSER}.
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index d4f7f06..6b4404d 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -82,7 +82,7 @@
         
         /**
          * Set a set of String values in the preferences editor, to be written
-         * back once {@link #commit} is called.
+         * back once {@link #commit} or {@link #apply} is called.
          * 
          * @param key The name of the preference to modify.
          * @param values The set of new values for the preference.  Passing {@code null}
diff --git a/core/java/android/content/SyncRequest.java b/core/java/android/content/SyncRequest.java
index a9a62a7..9ba45ca 100644
--- a/core/java/android/content/SyncRequest.java
+++ b/core/java/android/content/SyncRequest.java
@@ -473,7 +473,7 @@
          *   SyncRequest.Builder builder =
          *     new SyncRequest.Builder()
          *       .setSyncAdapter(dummyAccount, dummyProvider)
-         *       .syncOnce(5 * MINUTES_IN_SECS);
+         *       .syncOnce();
          *
          *   for (String syncData : syncItems) {
          *     Bundle extras = new Bundle();
diff --git a/core/java/android/content/Task.java b/core/java/android/content/Task.java
new file mode 100644
index 0000000..407880f
--- /dev/null
+++ b/core/java/android/content/Task.java
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+
+import android.app.task.TaskService;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Container of data passed to the {@link android.content.TaskManager} fully encapsulating the
+ * parameters required to schedule work against the calling application. These are constructed
+ * using the {@link Task.Builder}.
+ */
+public class Task implements Parcelable {
+
+    public interface NetworkType {
+        public final int ANY = 0;
+        public final int UNMETERED = 1;
+    }
+
+    /**
+     * Linear: retry_time(failure_time, t) = failure_time + initial_retry_delay * t, t >= 1
+     * Expon: retry_time(failure_time, t) = failure_time + initial_retry_delay ^ t, t >= 1
+     */
+    public interface BackoffPolicy {
+        public final int LINEAR = 0;
+        public final int EXPONENTIAL = 1;
+    }
+
+    private final int taskId;
+    // TODO: Change this to use PersistableBundle when that lands in master.
+    private final Bundle extras;
+    private final ComponentName service;
+    private final boolean requireCharging;
+    private final boolean requireDeviceIdle;
+    private final int networkCapabilities;
+    private final long minLatencyMillis;
+    private final long maxExecutionDelayMillis;
+    private final boolean isPeriodic;
+    private final long intervalMillis;
+    private final long initialBackoffMillis;
+    private final int backoffPolicy;
+
+    /**
+     * Unique task id associated with this class. This is assigned to your task by the scheduler.
+     */
+    public int getTaskId() {
+        return taskId;
+    }
+
+    /**
+     * Bundle of extras which are returned to your application at execution time.
+     */
+    public Bundle getExtras() {
+        return extras;
+    }
+
+    /**
+     * Name of the service endpoint that will be called back into by the TaskManager.
+     */
+    public ComponentName getService() {
+        return service;
+    }
+
+    /**
+     * Whether this task needs the device to be plugged in.
+     */
+    public boolean isRequireCharging() {
+        return requireCharging;
+    }
+
+    /**
+     * Whether this task needs the device to be in an Idle maintenance window.
+     */
+    public boolean isRequireDeviceIdle() {
+        return requireDeviceIdle;
+    }
+
+    /**
+     * See {@link android.content.Task.NetworkType} for a description of this value.
+     */
+    public int getNetworkCapabilities() {
+        return networkCapabilities;
+    }
+
+    /**
+     * Set for a task that does not recur periodically, to specify a delay after which the task
+     * will be eligible for execution. This value is not set if the task recurs periodically.
+     */
+    public long getMinLatencyMillis() {
+        return minLatencyMillis;
+    }
+
+    /**
+     * See {@link Builder#setOverrideDeadline(long)}. This value is not set if the task recurs
+     * periodically.
+     */
+    public long getMaxExecutionDelayMillis() {
+        return maxExecutionDelayMillis;
+    }
+
+    /**
+     * Track whether this task will repeat with a given period.
+     */
+    public boolean isPeriodic() {
+        return isPeriodic;
+    }
+
+    /**
+     * Set to the interval between occurrences of this task. This value is <b>not</b> set if the
+     * task does not recur periodically.
+     */
+    public long getIntervalMillis() {
+        return intervalMillis;
+    }
+
+    /**
+     * The amount of time the TaskManager will wait before rescheduling a failed task. This value
+     * will be increased depending on the backoff policy specified at task creation time. Defaults
+     * to 5 seconds.
+     */
+    public long getInitialBackoffMillis() {
+        return initialBackoffMillis;
+    }
+
+    /**
+     * See {@link android.content.Task.BackoffPolicy} for an explanation of the values this field
+     * can take. This defaults to exponential.
+     */
+    public int getBackoffPolicy() {
+        return backoffPolicy;
+    }
+
+    private Task(Parcel in) {
+        taskId = in.readInt();
+        extras = in.readBundle();
+        service = ComponentName.readFromParcel(in);
+        requireCharging = in.readInt() == 1;
+        requireDeviceIdle = in.readInt() == 1;
+        networkCapabilities = in.readInt();
+        minLatencyMillis = in.readLong();
+        maxExecutionDelayMillis = in.readLong();
+        isPeriodic = in.readInt() == 1;
+        intervalMillis = in.readLong();
+        initialBackoffMillis = in.readLong();
+        backoffPolicy = in.readInt();
+    }
+
+    private Task(Task.Builder b) {
+        taskId = b.mTaskId;
+        extras = new Bundle(b.mExtras);
+        service = b.mTaskService;
+        requireCharging = b.mRequiresCharging;
+        requireDeviceIdle = b.mRequiresDeviceIdle;
+        networkCapabilities = b.mNetworkCapabilities;
+        minLatencyMillis = b.mMinLatencyMillis;
+        maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
+        isPeriodic = b.mIsPeriodic;
+        intervalMillis = b.mIntervalMillis;
+        initialBackoffMillis = b.mInitialBackoffMillis;
+        backoffPolicy = b.mBackoffPolicy;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(taskId);
+        out.writeBundle(extras);
+        ComponentName.writeToParcel(service, out);
+        out.writeInt(requireCharging ? 1 : 0);
+        out.writeInt(requireDeviceIdle ? 1 : 0);
+        out.writeInt(networkCapabilities);
+        out.writeLong(minLatencyMillis);
+        out.writeLong(maxExecutionDelayMillis);
+        out.writeInt(isPeriodic ? 1 : 0);
+        out.writeLong(intervalMillis);
+        out.writeLong(initialBackoffMillis);
+        out.writeInt(backoffPolicy);
+    }
+
+    public static final Creator<Task> CREATOR = new Creator<Task>() {
+        @Override
+        public Task createFromParcel(Parcel in) {
+            return new Task(in);
+        }
+
+        @Override
+        public Task[] newArray(int size) {
+            return new Task[size];
+        }
+    };
+
+    /**
+     * Builder class for constructing {@link Task} objects.
+     */
+    public final class Builder {
+        private int mTaskId;
+        private Bundle mExtras;
+        private ComponentName mTaskService;
+        // Requirements.
+        private boolean mRequiresCharging;
+        private boolean mRequiresDeviceIdle;
+        private int mNetworkCapabilities;
+        // One-off parameters.
+        private long mMinLatencyMillis;
+        private long mMaxExecutionDelayMillis;
+        // Periodic parameters.
+        private boolean mIsPeriodic;
+        private long mIntervalMillis;
+        // Back-off parameters.
+        private long mInitialBackoffMillis = 5000L;
+        private int mBackoffPolicy = BackoffPolicy.EXPONENTIAL;
+        /** Easy way to track whether the client has tried to set a back-off policy. */
+        private boolean mBackoffPolicySet = false;
+
+        /**
+         * @param taskId Application-provided id for this task. Subsequent calls to cancel, or
+         *               tasks created with the same taskId, will update the pre-existing task with
+         *               the same id.
+         * @param taskService The endpoint that you implement that will receive the callback from the
+         *            TaskManager.
+         */
+        public Builder(int taskId, ComponentName taskService) {
+            mTaskService = taskService;
+            mTaskId = taskId;
+        }
+
+        /**
+         * Set optional extras. This is persisted, so we only allow primitive types.
+         * @param extras Bundle containing extras you want the scheduler to hold on to for you.
+         */
+        public Builder setExtras(Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /**
+         * Set some description of the kind of network capabilities you would like to have. This
+         * will be a parameter defined in {@link android.content.Task.NetworkType}.
+         * Not calling this function means the network is not necessary.
+         * Bear in mind that calling this function defines network as a strict requirement for your
+         * task if the network requested is not available your task will never run. See
+         * {@link #setOverrideDeadline(long)} to change this behaviour.
+         */
+        public Builder setRequiredNetworkCapabilities(int networkCapabilities) {
+            mNetworkCapabilities = networkCapabilities;
+            return this;
+        }
+
+        /*
+         * Specify that to run this task, the device needs to be plugged in. This defaults to
+         * false.
+         * @param requireCharging Whether or not the device is plugged in.
+         */
+        public Builder setRequiresCharging(boolean requiresCharging) {
+            mRequiresCharging = requiresCharging;
+            return this;
+        }
+
+        /**
+         * Specify that to run, the task needs the device to be in idle mode. This defaults to
+         * false.
+         * <p>Idle mode is a loose definition provided by the system, which means that the device
+         * is not in use, and has not been in use for some time. As such, it is a good time to
+         * perform resource heavy tasks. Bear in mind that battery usage will still be attributed
+         * to your application, and surfaced to the user in battery stats.</p>
+         * @param requiresDeviceIdle Whether or not the device need be within an idle maintenance
+         *                           window.
+         */
+        public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) {
+            mRequiresDeviceIdle = requiresDeviceIdle;
+            return this;
+        }
+
+        /**
+         * Specify that this task should recur with the provided interval, not more than once per
+         * period. You have no control over when within this interval this task will be executed,
+         * only the guarantee that it will be executed at most once within this interval.
+         * A periodic task will be repeated until the phone is turned off, however it will only be
+         * persisted beyond boot if the client app has declared the
+         * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission. You can schedule
+         * periodic tasks without this permission, they simply will cease to exist after the phone
+         * restarts.
+         * Setting this function on the builder with {@link #setMinimumLatency(long)} or
+         * {@link #setOverrideDeadline(long)} will result in an error.
+         * @param intervalMillis Millisecond interval for which this task will repeat.
+         */
+        public Builder setPeriodic(long intervalMillis) {
+            mIsPeriodic = true;
+            mIntervalMillis = intervalMillis;
+            return this;
+        }
+
+        /**
+         * Specify that this task should be delayed by the provided amount of time.
+         * Because it doesn't make sense setting this property on a periodic task, doing so will
+         * throw an {@link java.lang.IllegalArgumentException} when
+         * {@link android.content.Task.Builder#build()} is called.
+         * @param minLatencyMillis Milliseconds before which this task will not be considered for
+         *                         execution.
+         */
+        public Builder setMinimumLatency(long minLatencyMillis) {
+            mMinLatencyMillis = minLatencyMillis;
+            return this;
+        }
+
+        /**
+         * Set deadline which is the maximum scheduling latency. The task will be run by this
+         * deadline even if other requirements are not met. Because it doesn't make sense setting
+         * this property on a periodic task, doing so will throw an
+         * {@link java.lang.IllegalArgumentException} when
+         * {@link android.content.Task.Builder#build()} is called.
+         */
+        public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
+            mMaxExecutionDelayMillis = maxExecutionDelayMillis;
+            return this;
+        }
+
+        /**
+         * Set up the back-off/retry policy.
+         * This defaults to some respectable values: {5 seconds, Exponential}. We cap back-off at
+         * 1hr.
+         * Note that trying to set a backoff criteria for a task with
+         * {@link #setRequiresDeviceIdle(boolean)} will throw an exception when you call build().
+         * This is because back-off typically does not make sense for these types of tasks. See
+         * {@link android.app.task.TaskService#taskFinished(android.app.task.TaskParams, boolean)}
+         * for more description of the return value for the case of a task executing while in idle
+         * mode.
+         * @param initialBackoffMillis Millisecond time interval to wait initially when task has
+         *                             failed.
+         * @param backoffPolicy is one of {@link BackoffPolicy}
+         */
+        public Builder setBackoffCriteria(long initialBackoffMillis, int backoffPolicy) {
+            mBackoffPolicySet = true;
+            mInitialBackoffMillis = initialBackoffMillis;
+            mBackoffPolicy = backoffPolicy;
+            return this;
+        }
+
+        /**
+         * @return The task object to hand to the TaskManager. This object is immutable.
+         */
+        public Task build() {
+            // Check that extras bundle only contains primitive types.
+            try {
+                for (String key : extras.keySet()) {
+                    Object value = extras.get(key);
+                    if (value == null) continue;
+                    if (value instanceof Long) continue;
+                    if (value instanceof Integer) continue;
+                    if (value instanceof Boolean) continue;
+                    if (value instanceof Float) continue;
+                    if (value instanceof Double) continue;
+                    if (value instanceof String) continue;
+                    throw new IllegalArgumentException("Unexpected value type: "
+                            + value.getClass().getName());
+                }
+            } catch (IllegalArgumentException e) {
+                throw e;
+            } catch (RuntimeException exc) {
+                throw new IllegalArgumentException("error unparcelling Bundle", exc);
+            }
+            // Check that a deadline was not set on a periodic task.
+            if (mIsPeriodic && (mMaxExecutionDelayMillis != 0L)) {
+                throw new IllegalArgumentException("Can't call setOverrideDeadline() on a " +
+                        "periodic task.");
+            }
+            if (mIsPeriodic && (mMinLatencyMillis != 0L)) {
+                throw new IllegalArgumentException("Can't call setMinimumLatency() on a " +
+                        "periodic task");
+            }
+            if (mBackoffPolicySet && mRequiresDeviceIdle) {
+                throw new IllegalArgumentException("An idle mode task will not respect any" +
+                        " back-off policy, so calling setBackoffCriteria with" +
+                        " setRequiresDeviceIdle is an error.");
+            }
+            return new Task(this);
+        }
+    }
+
+}
diff --git a/core/java/android/content/TaskManager.java b/core/java/android/content/TaskManager.java
new file mode 100644
index 0000000..d28d78a
--- /dev/null
+++ b/core/java/android/content/TaskManager.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 and
+ * limitations under the License
+ */
+
+package android.content;
+
+import java.util.List;
+
+/**
+ * Class for scheduling various types of tasks with the scheduling framework on the device.
+ *
+ * Get an instance of this class through {@link Context#getSystemService(String)}.
+ */
+public abstract class TaskManager {
+    /*
+     * Returned from {@link #schedule(Task)} when an invalid parameter was supplied. This can occur
+     * if the run-time for your task is too short, or perhaps the system can't resolve the
+     * requisite {@link TaskService} in your package.
+     */
+    static final int RESULT_INVALID_PARAMETERS = -1;
+    /**
+     * Returned from {@link #schedule(Task)} if this application has made too many requests for
+     * work over too short a time.
+     */
+    // TODO: Determine if this is necessary.
+    static final int RESULT_OVER_QUOTA = -2;
+
+    /*
+     * @param task The task you wish scheduled. See {@link Task#TaskBuilder} for more detail on
+     * the sorts of tasks you can schedule.
+     * @return If >0, this int corresponds to the taskId of the successfully scheduled task.
+     * Otherwise you have to compare the return value to the error codes defined in this class.
+     */
+    public abstract int schedule(Task task);
+
+    /**
+     * Cancel a task that is pending in the TaskManager.
+     * @param taskId unique identifier for this task. Obtain this value from the tasks returned by
+     * {@link #getAllPendingTasks()}.
+     * @return
+     */
+    public abstract void cancel(int taskId);
+
+    /**
+     * Cancel all tasks that have been registered with the TaskManager by this package.
+     */
+    public abstract void cancelAll();
+
+    /**
+     * @return a list of all the tasks registered by this package that have not yet been executed.
+     */
+    public abstract List<Task> getAllPendingTasks();
+
+}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index c53e545..c2fe3a2 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -67,7 +67,37 @@
      * {@link #LAUNCH_SINGLE_INSTANCE}.
      */
     public int launchMode;
-    
+
+    /**
+     * Constant corresponding to <code>none</code> in
+     * the {@link android.R.attr#documentLaunchMode} attribute.
+     */
+    public static final int DOCUMENT_LAUNCH_NONE = 0;
+    /**
+     * Constant corresponding to <code>intoExisting</code> in
+     * the {@link android.R.attr#documentLaunchMode} attribute.
+     */
+    public static final int DOCUMENT_LAUNCH_INTO_EXISTING = 1;
+    /**
+     * Constant corresponding to <code>always</code> in
+     * the {@link android.R.attr#documentLaunchMode} attribute.
+     */
+    public static final int DOCUMENT_LAUNCH_ALWAYS = 2;
+    /**
+     * The document launch mode style requested by the activity. From the
+     * {@link android.R.attr#documentLaunchMode} attribute, one of
+     * {@link #DOCUMENT_LAUNCH_NONE}, {@link #DOCUMENT_LAUNCH_INTO_EXISTING},
+     * {@link #DOCUMENT_LAUNCH_ALWAYS}.
+     *
+     * <p>Modes DOCUMENT_LAUNCH_ALWAYS
+     * and DOCUMENT_LAUNCH_INTO_EXISTING are equivalent to {@link
+     * android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT
+     * Intent.FLAG_ACTIVITY_NEW_DOCUMENT} with and without {@link
+     * android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
+     * Intent.FLAG_ACTIVITY_MULTIPLE_TASK} respectively.
+     */
+    public int documentLaunchMode;
+
     /**
      * Optional name of a permission required to be able to access this
      * Activity.  From the "permission" attribute.
@@ -192,10 +222,15 @@
      * Bit in {@link #flags} indicating that this activity is to be persisted across
      * reboots for display in the Recents list.
      * {@link android.R.attr#persistable}
-     * @hide
      */
     public static final int FLAG_PERSISTABLE = 0x1000;
     /**
+     * Bit in {@link #flags} indicating that tasks started with this activity are to be
+     * removed from the recent list of tasks when the last activity in the task is finished.
+     * {@link android.R.attr#autoRemoveFromRecents}
+     */
+    public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 0x2000;
+    /**
      * @hide Bit in {@link #flags}: If set, this component will only be seen
      * by the primary user.  Only works with broadcast receivers.  Set from the
      * android.R.attr#primaryUserOnly attribute.
diff --git a/core/java/android/content/pm/ContainerEncryptionParams.java b/core/java/android/content/pm/ContainerEncryptionParams.java
index 88112a7..dd1332b 100644
--- a/core/java/android/content/pm/ContainerEncryptionParams.java
+++ b/core/java/android/content/pm/ContainerEncryptionParams.java
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.annotation.PrivateApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -31,8 +32,11 @@
 /**
  * Represents encryption parameters used to read a container.
  *
+ * @deprecated encrypted containers are legacy.
  * @hide
  */
+@PrivateApi
+@Deprecated
 public class ContainerEncryptionParams implements Parcelable {
     protected static final String TAG = "ContainerEncryptionParams";
 
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index 796b113..0acf043 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -35,4 +35,6 @@
     ResolveInfo resolveActivity(in Intent intent, in UserHandle user);
     void startActivityAsUser(in ComponentName component, in Rect sourceBounds,
             in Bundle opts, in UserHandle user);
+    boolean isPackageEnabled(String packageName, in UserHandle user);
+    boolean isActivityEnabled(in ComponentName component, in UserHandle user);
 }
diff --git a/core/java/android/content/pm/IPackageInstallObserver2.aidl b/core/java/android/content/pm/IPackageInstallObserver2.aidl
index 2602ab5..7205ce7 100644
--- a/core/java/android/content/pm/IPackageInstallObserver2.aidl
+++ b/core/java/android/content/pm/IPackageInstallObserver2.aidl
@@ -1,22 +1,22 @@
 /*
-**
-** 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.
-*/
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.IntentSender;
 import android.os.Bundle;
 
 /**
@@ -40,6 +40,5 @@
      * </tr>
      * </table>
      */
-    void packageInstalled(in String packageName, in Bundle extras, int returnCode);
+    void packageInstalled(String basePackageName, in Bundle extras, int returnCode);
 }
-
diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl
new file mode 100644
index 0000000..68c019b
--- /dev/null
+++ b/core/java/android/content/pm/IPackageInstaller.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.IPackageInstallerSession;
+import android.content.pm.PackageInstallerParams;
+import android.os.ParcelFileDescriptor;
+
+/** {@hide} */
+interface IPackageInstaller {
+    int createSession(int userId, String installerPackageName, in PackageInstallerParams params);
+    IPackageInstallerSession openSession(int sessionId);
+
+    int[] getSessions(int userId, String installerPackageName);
+
+    void uninstall(int userId, String basePackageName, in IPackageDeleteObserver observer);
+    void uninstallSplit(int userId, String basePackageName, String splitName, in IPackageDeleteObserver observer);
+}
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
new file mode 100644
index 0000000..f881acd
--- /dev/null
+++ b/core/java/android/content/pm/IPackageInstallerSession.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.content.pm;
+
+import android.content.pm.IPackageInstallObserver2;
+import android.os.ParcelFileDescriptor;
+
+/** {@hide} */
+interface IPackageInstallerSession {
+    void updateProgress(int progress);
+
+    ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes);
+
+    void install(in IPackageInstallObserver2 observer);
+    void destroy();
+}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 488e25f..6cb781f 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -26,6 +26,7 @@
 import android.content.pm.FeatureInfo;
 import android.content.pm.IPackageInstallObserver;
 import android.content.pm.IPackageInstallObserver2;
+import android.content.pm.IPackageInstaller;
 import android.content.pm.IPackageDeleteObserver;
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageMoveObserver;
@@ -111,6 +112,8 @@
 
     ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags, int userId);
 
+    boolean canForwardTo(in Intent intent, String resolvedType, int userIdFrom, int userIdDest);
+
     List<ResolveInfo> queryIntentActivities(in Intent intent, 
             String resolvedType, int flags, int userId);
 
@@ -245,6 +248,11 @@
 
     void clearPackagePersistentPreferredActivities(String packageName, int userId);
 
+    void addForwardingIntentFilter(in IntentFilter filter, boolean removable, int userIdOrig,
+            int userIdDest);
+
+    void clearForwardingIntentFilters(int userIdOrig);
+
     /**
      * Report the set of 'Home' activity candidates, plus (if any) which of them
      * is the current "always use this one" setting.
@@ -443,4 +451,6 @@
 
     boolean setApplicationBlockedSettingAsUser(String packageName, boolean blocked, int userId);
     boolean getApplicationBlockedSettingAsUser(String packageName, int userId);
+
+    IPackageInstaller getPackageInstaller();
 }
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 5187181..8025b60 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -187,6 +187,39 @@
     }
 
     /**
+     * Checks if the package is installed and enabled for a profile.
+     *
+     * @param packageName The package to check.
+     * @param user The UserHandle of the profile.
+     *
+     * @return true if the package exists and is enabled.
+     */
+    public boolean isPackageEnabledForProfile(String packageName, UserHandle user) {
+        try {
+            return mService.isPackageEnabled(packageName, user);
+        } catch (RemoteException re) {
+            return false;
+        }
+    }
+
+    /**
+     * Checks if the activity exists and it enabled for a profile.
+     *
+     * @param component The activity to check.
+     * @param user The UserHandle of the profile.
+     *
+     * @return true if the activity exists and is enabled.
+     */
+    public boolean isActivityEnabledForProfile(ComponentName component, UserHandle user) {
+        try {
+            return mService.isActivityEnabled(component, user);
+        } catch (RemoteException re) {
+            return false;
+        }
+    }
+
+
+    /**
      * Adds a listener for changes to packages in current and managed profiles.
      *
      * @param listener The listener to add.
diff --git a/core/java/android/content/pm/ManifestDigest.java b/core/java/android/content/pm/ManifestDigest.java
index 409b5ae..943534f 100644
--- a/core/java/android/content/pm/ManifestDigest.java
+++ b/core/java/android/content/pm/ManifestDigest.java
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.annotation.PrivateApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Slog;
@@ -36,6 +37,7 @@
  *
  * @hide
  */
+@PrivateApi
 public class ManifestDigest implements Parcelable {
     private static final String TAG = "ManifestDigest";
 
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
new file mode 100644
index 0000000..d7bd473
--- /dev/null
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.app.PackageInstallObserver;
+import android.app.PackageUninstallObserver;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+
+/** {@hide} */
+public class PackageInstaller {
+    private final PackageManager mPm;
+    private final IPackageInstaller mInstaller;
+    private final int mUserId;
+    private final String mInstallerPackageName;
+
+    /** {@hide} */
+    public PackageInstaller(PackageManager pm, IPackageInstaller installer, int userId,
+            String installerPackageName) {
+        mPm = pm;
+        mInstaller = installer;
+        mUserId = userId;
+        mInstallerPackageName = installerPackageName;
+    }
+
+    public boolean isPackageAvailable(String basePackageName) {
+        try {
+            final ApplicationInfo info = mPm.getApplicationInfo(basePackageName,
+                    PackageManager.GET_UNINSTALLED_PACKAGES);
+            return ((info.flags & ApplicationInfo.FLAG_INSTALLED) != 0);
+        } catch (NameNotFoundException e) {
+            return false;
+        }
+    }
+
+    public void installAvailablePackage(String basePackageName, PackageInstallObserver observer) {
+        int returnCode;
+        try {
+            returnCode = mPm.installExistingPackage(basePackageName);
+        } catch (NameNotFoundException e) {
+            returnCode = PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
+        }
+        observer.packageInstalled(basePackageName, null, returnCode);
+    }
+
+    public int createSession(PackageInstallerParams params) {
+        try {
+            return mInstaller.createSession(mUserId, mInstallerPackageName, params);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    public Session openSession(int sessionId) {
+        try {
+            return new Session(mInstaller.openSession(sessionId));
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    public int[] getSessions() {
+        try {
+            return mInstaller.getSessions(mUserId, mInstallerPackageName);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    public void uninstall(String basePackageName, PackageUninstallObserver observer) {
+        try {
+            mInstaller.uninstall(mUserId, basePackageName, observer.getBinder());
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    public void uninstall(String basePackageName, String splitName,
+            PackageUninstallObserver observer) {
+        try {
+            mInstaller.uninstallSplit(mUserId, basePackageName, splitName, observer.getBinder());
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /**
+     * An installation that is being actively staged. For an install to succeed,
+     * all existing and new packages must have identical package names, version
+     * codes, and signing certificates.
+     * <p>
+     * A session may contain any number of split packages. If the application
+     * does not yet exist, this session must include a base package.
+     * <p>
+     * If a package included in this session is already defined by the existing
+     * installation (for example, the same split name), the package in this
+     * session will replace the existing package.
+     */
+    public class Session {
+        private IPackageInstallerSession mSession;
+
+        /** {@hide} */
+        public Session(IPackageInstallerSession session) {
+            mSession = session;
+        }
+
+        public void updateProgress(int progress) {
+            try {
+                mSession.updateProgress(progress);
+            } catch (RemoteException e) {
+                throw e.rethrowAsRuntimeException();
+            }
+        }
+
+        public ParcelFileDescriptor openWrite(String overlayName, long offsetBytes,
+                long lengthBytes) {
+            try {
+                return mSession.openWrite(overlayName, offsetBytes, lengthBytes);
+            } catch (RemoteException e) {
+                throw e.rethrowAsRuntimeException();
+            }
+        }
+
+        public void install(PackageInstallObserver observer) {
+            try {
+                mSession.install(observer.getBinder());
+            } catch (RemoteException e) {
+                throw e.rethrowAsRuntimeException();
+            }
+        }
+
+        public void close() {
+            // No resources to release at the moment
+        }
+
+        public void destroy() {
+            try {
+                mSession.destroy();
+            } catch (RemoteException e) {
+                throw e.rethrowAsRuntimeException();
+            }
+        }
+    }
+}
diff --git a/core/java/android/content/pm/PackageInstallerParams.aidl b/core/java/android/content/pm/PackageInstallerParams.aidl
new file mode 100644
index 0000000..b3dde21
--- /dev/null
+++ b/core/java/android/content/pm/PackageInstallerParams.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.content.pm;
+
+parcelable PackageInstallerParams;
diff --git a/core/java/android/content/pm/PackageInstallerParams.java b/core/java/android/content/pm/PackageInstallerParams.java
new file mode 100644
index 0000000..67cf276
--- /dev/null
+++ b/core/java/android/content/pm/PackageInstallerParams.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.content.pm;
+
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Parameters that define an installation session.
+ *
+ * {@hide}
+ */
+public class PackageInstallerParams implements Parcelable {
+
+    // TODO: extend to support remaining VerificationParams
+
+    /** {@hide} */
+    public boolean fullInstall;
+    /** {@hide} */
+    public int installFlags;
+    /** {@hide} */
+    public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
+    /** {@hide} */
+    public Signature[] signatures;
+    /** {@hide} */
+    public long deltaSize = -1;
+    /** {@hide} */
+    public Bitmap icon;
+    /** {@hide} */
+    public String title;
+    /** {@hide} */
+    public Uri originatingUri;
+    /** {@hide} */
+    public Uri referrerUri;
+
+    public PackageInstallerParams() {
+    }
+
+    /** {@hide} */
+    public PackageInstallerParams(Parcel source) {
+        this.fullInstall = source.readInt() != 0;
+        this.installFlags = source.readInt();
+        this.installLocation = source.readInt();
+        this.signatures = (Signature[]) source.readParcelableArray(null);
+        deltaSize = source.readLong();
+        if (source.readInt() != 0) {
+            icon = Bitmap.CREATOR.createFromParcel(source);
+        }
+        title = source.readString();
+        originatingUri = Uri.CREATOR.createFromParcel(source);
+        referrerUri = Uri.CREATOR.createFromParcel(source);
+    }
+
+    public void setFullInstall(boolean fullInstall) {
+        this.fullInstall = fullInstall;
+    }
+
+    public void setInstallFlags(int installFlags) {
+        this.installFlags = installFlags;
+    }
+
+    public void setInstallLocation(int installLocation) {
+        this.installLocation = installLocation;
+    }
+
+    public void setSignatures(Signature[] signatures) {
+        this.signatures = signatures;
+    }
+
+    public void setDeltaSize(long deltaSize) {
+        this.deltaSize = deltaSize;
+    }
+
+    public void setIcon(Bitmap icon) {
+        this.icon = icon;
+    }
+
+    public void setTitle(CharSequence title) {
+        this.title = (title != null) ? title.toString() : null;
+    }
+
+    public void setOriginatingUri(Uri originatingUri) {
+        this.originatingUri = originatingUri;
+    }
+
+    public void setReferrerUri(Uri referrerUri) {
+        this.referrerUri = referrerUri;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(fullInstall ? 1 : 0);
+        dest.writeInt(installFlags);
+        dest.writeInt(installLocation);
+        dest.writeParcelableArray(signatures, flags);
+        dest.writeLong(deltaSize);
+        if (icon != null) {
+            dest.writeInt(1);
+            icon.writeToParcel(dest, flags);
+        } else {
+            dest.writeInt(0);
+        }
+        dest.writeString(title);
+        dest.writeParcelable(originatingUri, flags);
+        dest.writeParcelable(referrerUri, flags);
+    }
+
+    public static final Parcelable.Creator<PackageInstallerParams>
+            CREATOR = new Parcelable.Creator<PackageInstallerParams>() {
+                @Override
+                public PackageInstallerParams createFromParcel(Parcel p) {
+                    return new PackageInstallerParams(p);
+                }
+
+                @Override
+                public PackageInstallerParams[] newArray(int size) {
+                    return new PackageInstallerParams[size];
+                }
+            };
+}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 484a2a1..2aa34d8 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -17,6 +17,7 @@
 package android.content.pm;
 
 import android.annotation.IntDef;
+import android.annotation.PrivateApi;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.PackageInstallObserver;
@@ -369,6 +370,7 @@
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} on success.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_SUCCEEDED = 1;
 
     /**
@@ -377,6 +379,7 @@
      * already installed.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_ALREADY_EXISTS = -1;
 
     /**
@@ -385,6 +388,7 @@
      * file is invalid.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_INVALID_APK = -2;
 
     /**
@@ -393,6 +397,7 @@
      * is invalid.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_INVALID_URI = -3;
 
     /**
@@ -401,6 +406,7 @@
      * service found that the device didn't have enough storage space to install the app.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_INSUFFICIENT_STORAGE = -4;
 
     /**
@@ -409,6 +415,7 @@
      * package is already installed with the same name.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_DUPLICATE_PACKAGE = -5;
 
     /**
@@ -417,6 +424,7 @@
      * the requested shared user does not exist.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_NO_SHARED_USER = -6;
 
     /**
@@ -426,6 +434,7 @@
      * than the new package (and the old package's data was not removed).
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_UPDATE_INCOMPATIBLE = -7;
 
     /**
@@ -435,6 +444,7 @@
      * device and does not have matching signature.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_SHARED_USER_INCOMPATIBLE = -8;
 
     /**
@@ -443,6 +453,7 @@
      * the new package uses a shared library that is not available.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_MISSING_SHARED_LIBRARY = -9;
 
     /**
@@ -451,6 +462,7 @@
      * the new package uses a shared library that is not available.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_REPLACE_COULDNT_DELETE = -10;
 
     /**
@@ -460,6 +472,7 @@
      * either because there was not enough storage or the validation failed.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_DEXOPT = -11;
 
     /**
@@ -469,6 +482,7 @@
      * that required by the package.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_OLDER_SDK = -12;
 
     /**
@@ -478,6 +492,7 @@
      * same authority as a provider already installed in the system.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13;
 
     /**
@@ -487,6 +502,7 @@
      * that required by the package.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_NEWER_SDK = -14;
 
     /**
@@ -497,6 +513,7 @@
      * flag.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_TEST_ONLY = -15;
 
     /**
@@ -506,6 +523,7 @@
      * compatible with the the device's CPU_ABI.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_CPU_ABI_INCOMPATIBLE = -16;
 
     /**
@@ -514,6 +532,7 @@
      * the new package uses a feature that is not available.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_MISSING_FEATURE = -17;
 
     // ------ Errors related to sdcard
@@ -523,6 +542,7 @@
      * a secure container mount point couldn't be accessed on external media.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_CONTAINER_ERROR = -18;
 
     /**
@@ -532,6 +552,7 @@
      * location.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_INVALID_INSTALL_LOCATION = -19;
 
     /**
@@ -541,6 +562,7 @@
      * location because the media is not available.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_MEDIA_UNAVAILABLE = -20;
 
     /**
@@ -549,6 +571,7 @@
      * the new package couldn't be installed because the verification timed out.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_VERIFICATION_TIMEOUT = -21;
 
     /**
@@ -557,6 +580,7 @@
      * the new package couldn't be installed because the verification did not succeed.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_VERIFICATION_FAILURE = -22;
 
     /**
@@ -565,6 +589,7 @@
      * the package changed from what the calling program expected.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_PACKAGE_CHANGED = -23;
 
     /**
@@ -590,6 +615,7 @@
      * '.apk' extension.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_PARSE_FAILED_NOT_APK = -100;
 
     /**
@@ -598,6 +624,7 @@
      * if the parser was unable to retrieve the AndroidManifest.xml file.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_PARSE_FAILED_BAD_MANIFEST = -101;
 
     /**
@@ -606,6 +633,7 @@
      * if the parser encountered an unexpected exception.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102;
 
     /**
@@ -614,6 +642,7 @@
      * if the parser did not find any certificates in the .apk.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103;
 
     /**
@@ -622,6 +651,7 @@
      * if the parser found inconsistent certificates on the files in the .apk.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES = -104;
 
     /**
@@ -631,6 +661,7 @@
      * files in the .apk.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING = -105;
 
     /**
@@ -639,6 +670,7 @@
      * if the parser encountered a bad or missing package name in the manifest.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME = -106;
 
     /**
@@ -647,6 +679,7 @@
      * if the parser encountered a bad shared user id name in the manifest.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID = -107;
 
     /**
@@ -655,6 +688,7 @@
      * if the parser encountered some structural problem in the manifest.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_PARSE_FAILED_MANIFEST_MALFORMED = -108;
 
     /**
@@ -664,6 +698,7 @@
      * in the manifest.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_PARSE_FAILED_MANIFEST_EMPTY = -109;
 
     /**
@@ -672,6 +707,7 @@
      * if the system failed to install the package because of system issues.
      * @hide
      */
+    @PrivateApi
     public static final int INSTALL_FAILED_INTERNAL_ERROR = -110;
 
     /**
@@ -936,13 +972,21 @@
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device has at least one camera pointing in
-     * some direction.
+     * some direction, or can support an external camera being connected to it.
      */
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_CAMERA_ANY = "android.hardware.camera.any";
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device can support having an external camera connected to it.
+     * The external camera may not always be connected or available to applications to use.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_CAMERA_EXTERNAL = "android.hardware.camera.external";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device's camera supports flash.
      */
     @SdkConstant(SdkConstantType.FEATURE)
@@ -1083,6 +1127,13 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device includes a heart rate monitor.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_SENSOR_HEART_RATE = "android.hardware.sensor.heartrate";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device has a telephony radio with data
      * communication support.
      */
@@ -2848,6 +2899,7 @@
      * instead.  This method will continue to be supported but the older observer interface
      * will not get additional failure details.
      */
+    @PrivateApi
     public abstract void installPackage(
             Uri packageURI, IPackageInstallObserver observer, int flags,
             String installerPackageName);
@@ -2882,6 +2934,7 @@
      * continue to be supported but the older observer interface will not get additional failure
      * details.
      */
+    @PrivateApi
     public abstract void installPackageWithVerification(Uri packageURI,
             IPackageInstallObserver observer, int flags, String installerPackageName,
             Uri verificationURI, ManifestDigest manifestDigest,
@@ -3010,6 +3063,7 @@
      * on the system for other users, also install it for the calling user.
      * @hide
      */
+    @PrivateApi
     public abstract int installExistingPackage(String packageName)
             throws NameNotFoundException;
 
@@ -3099,6 +3153,7 @@
      *
      * @hide
      */
+    @PrivateApi
     public abstract void deletePackage(
             String packageName, IPackageDeleteObserver observer, int flags);
 
@@ -3167,6 +3222,7 @@
      *
      * @hide
      */
+    @PrivateApi
     public abstract void freeStorageAndNotify(long freeStorageSize, IPackageDataObserver observer);
 
     /**
@@ -3495,6 +3551,9 @@
      */
     public abstract VerifierDeviceIdentity getVerifierDeviceIdentity();
 
+    /** {@hide} */
+    public abstract PackageInstaller getPackageInstaller();
+
     /**
      * Returns the data directory for a particular user and package, given the uid of the package.
      * @param uid uid of the package, including the userId and appId
@@ -3507,4 +3566,26 @@
         return Environment.getDataDirectory().toString() + "/user/" + userId
                 + "/" + packageName;
     }
+
+    /**
+     * Adds a forwarding intent filter. After calling this method all intents sent from the user
+     * with id userIdOrig can also be be resolved by activities in the user with id userIdDest if
+     * they match the specified intent filter.
+     * @param filter the {@link IntentFilter} the intent has to match to be forwarded
+     * @param removable if set to false, {@link clearForwardingIntents} will not remove this intent
+     * filter
+     * @param userIdOrig user from which the intent can be forwarded
+     * @param userIdDest user to which the intent can be forwarded
+     * @hide
+     */
+    public abstract void addForwardingIntentFilter(IntentFilter filter, boolean removable,
+            int userIdOrig, int userIdDest);
+
+    /**
+     * Clearing all removable {@link ForwardingIntentFilter}s that are set with the given user as
+     * the origin.
+     * @param userIdOrig user from which the intent can be forwarded
+     * @hide
+     */
+    public abstract void clearForwardingIntentFilters(int userIdOrig);
 }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 080b37b..1c838c3 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -16,6 +16,9 @@
 
 package android.content.pm;
 
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -32,6 +35,7 @@
 import android.util.Base64;
 import android.util.DisplayMetrics;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.TypedValue;
 
@@ -41,6 +45,7 @@
 import java.io.InputStream;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
+import java.security.GeneralSecurityException;
 import java.security.KeyFactory;
 import java.security.NoSuchAlgorithmException;
 import java.security.PublicKey;
@@ -51,7 +56,6 @@
 import java.security.spec.X509EncodedKeySpec;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -61,6 +65,7 @@
 import java.util.jar.StrictJarFile;
 import java.util.zip.ZipEntry;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -207,16 +212,20 @@
      */
     public static class PackageLite {
         public final String packageName;
+        public final String splitName;
         public final int versionCode;
         public final int installLocation;
         public final VerifierInfo[] verifiers;
+        public final Signature[] signatures;
 
-        public PackageLite(String packageName, int versionCode,
-                int installLocation, List<VerifierInfo> verifiers) {
+        public PackageLite(String packageName, String splitName, int versionCode,
+                int installLocation, List<VerifierInfo> verifiers, Signature[] signatures) {
             this.packageName = packageName;
+            this.splitName = splitName;
             this.versionCode = versionCode;
             this.installLocation = installLocation;
             this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
+            this.signatures = signatures;
         }
     }
 
@@ -459,7 +468,7 @@
         return pi;
     }
 
-    private Certificate[][] loadCertificates(StrictJarFile jarFile, ZipEntry je,
+    private static Certificate[][] loadCertificates(StrictJarFile jarFile, ZipEntry je,
             byte[] readBuffer) {
         try {
             // We must read the stream for the JarEntry to retrieve
@@ -486,6 +495,7 @@
     public final static int PARSE_ON_SDCARD = 1<<5;
     public final static int PARSE_IS_SYSTEM_DIR = 1<<6;
     public final static int PARSE_IS_PRIVILEGED = 1<<7;
+    public final static int PARSE_GET_SIGNATURES = 1<<8;
 
     public int getParseError() {
         return mParseError;
@@ -722,12 +732,8 @@
                 mReadBuffer = readBufferRef;
             }
 
-            if (certs != null && certs.length > 0) {
-                final int N = certs.length;
-                pkg.mSignatures = new Signature[certs.length];
-                for (int i=0; i<N; i++) {
-                    pkg.mSignatures[i] = new Signature(certs[i]);
-                }
+            if (!ArrayUtils.isEmpty(certs)) {
+                pkg.mSignatures = convertToSignatures(certs);
             } else {
                 Slog.e(TAG, "Package " + pkg.packageName
                         + " has no certificates; ignoring!");
@@ -762,6 +768,39 @@
         return true;
     }
 
+    /**
+     * Only collect certificates on the manifest; does not validate signatures
+     * across remainder of package.
+     */
+    private static Signature[] collectCertificates(String packageFilePath) {
+        try {
+            final StrictJarFile jarFile = new StrictJarFile(packageFilePath);
+            try {
+                final ZipEntry jarEntry = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
+                if (jarEntry != null) {
+                    final Certificate[][] certs = loadCertificates(jarFile, jarEntry, null);
+                    return convertToSignatures(certs);
+                }
+            } finally {
+                jarFile.close();
+            }
+        } catch (GeneralSecurityException e) {
+            Slog.w(TAG, "Failed to collect certs from " + packageFilePath + ": " + e);
+        } catch (IOException e) {
+            Slog.w(TAG, "Failed to collect certs from " + packageFilePath + ": " + e);
+        }
+        return null;
+    }
+
+    private static Signature[] convertToSignatures(Certificate[][] certs)
+            throws CertificateEncodingException {
+        final Signature[] res = new Signature[certs.length];
+        for (int i = 0; i < certs.length; i++) {
+            res[i] = new Signature(certs[i]);
+        }
+        return res;
+    }
+
     /*
      * Utility method that retrieves just the package name and install
      * location from the apk location at the given file path.
@@ -794,11 +833,22 @@
             return null;
         }
 
+        // Only collect certificates on the manifest; does not validate
+        // signatures across remainder of package.
+        final Signature[] signatures;
+        if ((flags & PARSE_GET_SIGNATURES) != 0) {
+            signatures = collectCertificates(packageFilePath);
+        } else {
+            signatures = null;
+        }
+
         final AttributeSet attrs = parser;
         final String errors[] = new String[1];
         PackageLite packageLite = null;
         try {
-            packageLite = parsePackageLite(res, parser, attrs, flags, errors);
+            packageLite = parsePackageLite(res, parser, attrs, flags, signatures, errors);
+        } catch (PackageParserException e) {
+            Slog.w(TAG, packageFilePath, e);
         } catch (IOException e) {
             Slog.w(TAG, packageFilePath, e);
         } catch (XmlPullParserException e) {
@@ -840,72 +890,51 @@
                 ? null : "must have at least one '.' separator";
     }
 
-    private static String parsePackageName(XmlPullParser parser,
-            AttributeSet attrs, int flags, String[] outError)
-            throws IOException, XmlPullParserException {
+    private static Pair<String, String> parsePackageSplitNames(XmlPullParser parser,
+            AttributeSet attrs, int flags) throws IOException, XmlPullParserException,
+            PackageParserException {
 
         int type;
         while ((type = parser.next()) != XmlPullParser.START_TAG
                 && type != XmlPullParser.END_DOCUMENT) {
-            ;
         }
 
         if (type != XmlPullParser.START_TAG) {
-            outError[0] = "No start tag found";
-            return null;
+            throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "No start tag found");
         }
-        if (DEBUG_PARSER)
-            Slog.v(TAG, "Root element name: '" + parser.getName() + "'");
         if (!parser.getName().equals("manifest")) {
-            outError[0] = "No <manifest> tag";
-            return null;
-        }
-        String pkgName = attrs.getAttributeValue(null, "package");
-        if (pkgName == null || pkgName.length() == 0) {
-            outError[0] = "<manifest> does not specify package";
-            return null;
-        }
-        String nameError = validateName(pkgName, true);
-        if (nameError != null && !"android".equals(pkgName)) {
-            outError[0] = "<manifest> specifies bad package name \""
-                + pkgName + "\": " + nameError;
-            return null;
+            throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "No <manifest> tag");
         }
 
-        return pkgName.intern();
+        final String packageName = attrs.getAttributeValue(null, "package");
+        if (!"android".equals(packageName)) {
+            final String error = validateName(packageName, true);
+            if (error != null) {
+                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+                        "Invalid manifest package: " + error);
+            }
+        }
+
+        final String splitName = attrs.getAttributeValue(null, "split");
+        if (splitName != null) {
+            final String error = validateName(splitName, true);
+            if (error != null) {
+                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+                        "Invalid manifest split: " + error);
+            }
+        }
+
+        return Pair.create(packageName.intern(),
+                (splitName != null) ? splitName.intern() : splitName);
     }
 
     private static PackageLite parsePackageLite(Resources res, XmlPullParser parser,
-            AttributeSet attrs, int flags, String[] outError) throws IOException,
-            XmlPullParserException {
+            AttributeSet attrs, int flags, Signature[] signatures, String[] outError)
+            throws IOException, XmlPullParserException, PackageParserException {
+        final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs, flags);
 
-        int type;
-        while ((type = parser.next()) != XmlPullParser.START_TAG
-                && type != XmlPullParser.END_DOCUMENT) {
-            ;
-        }
-
-        if (type != XmlPullParser.START_TAG) {
-            outError[0] = "No start tag found";
-            return null;
-        }
-        if (DEBUG_PARSER)
-            Slog.v(TAG, "Root element name: '" + parser.getName() + "'");
-        if (!parser.getName().equals("manifest")) {
-            outError[0] = "No <manifest> tag";
-            return null;
-        }
-        String pkgName = attrs.getAttributeValue(null, "package");
-        if (pkgName == null || pkgName.length() == 0) {
-            outError[0] = "<manifest> does not specify package";
-            return null;
-        }
-        String nameError = validateName(pkgName, true);
-        if (nameError != null && !"android".equals(pkgName)) {
-            outError[0] = "<manifest> specifies bad package name \""
-                + pkgName + "\": " + nameError;
-            return null;
-        }
         int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
         int versionCode = 0;
         int numFound = 0;
@@ -925,6 +954,7 @@
         }
 
         // Only search the tree when the tag is directly below <manifest>
+        int type;
         final int searchDepth = parser.getDepth() + 1;
 
         final List<VerifierInfo> verifiers = new ArrayList<VerifierInfo>();
@@ -942,7 +972,8 @@
             }
         }
 
-        return new PackageLite(pkgName.intern(), versionCode, installLocation, verifiers);
+        return new PackageLite(packageSplit.first, packageSplit.second, versionCode,
+                installLocation, verifiers, signatures);
     }
 
     /**
@@ -966,12 +997,18 @@
         mParseActivityArgs = null;
         mParseServiceArgs = null;
         mParseProviderArgs = null;
-        
-        String pkgName = parsePackageName(parser, attrs, flags, outError);
-        if (pkgName == null) {
+
+        final String pkgName;
+        final String splitName;
+        try {
+            Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs, flags);
+            pkgName = packageSplit.first;
+            splitName = packageSplit.second;
+        } catch (PackageParserException e) {
             mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
             return null;
         }
+
         int type;
 
         if (mOnlyCoreApps) {
@@ -982,9 +1019,9 @@
             }
         }
 
-        final Package pkg = new Package(pkgName);
+        final Package pkg = new Package(pkgName, splitName);
         boolean foundApp = false;
-        
+
         TypedArray sa = res.obtainAttributes(attrs,
                 com.android.internal.R.styleable.AndroidManifest);
         pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
@@ -2462,17 +2499,6 @@
             a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_persistable, false)) {
-            a.info.flags |= ActivityInfo.FLAG_PERSISTABLE;
-        }
-
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_allowEmbedded,
-                false)) {
-            a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
-        }
-
         if (!receiver) {
             if (sa.getBoolean(
                     com.android.internal.R.styleable.AndroidManifestActivity_hardwareAccelerated,
@@ -2483,6 +2509,9 @@
             a.info.launchMode = sa.getInt(
                     com.android.internal.R.styleable.AndroidManifestActivity_launchMode,
                     ActivityInfo.LAUNCH_MULTIPLE);
+            a.info.documentLaunchMode = sa.getInt(
+                    com.android.internal.R.styleable.AndroidManifestActivity_documentLaunchMode,
+                    ActivityInfo.DOCUMENT_LAUNCH_NONE);
             a.info.screenOrientation = sa.getInt(
                     com.android.internal.R.styleable.AndroidManifestActivity_screenOrientation,
                     ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
@@ -2492,6 +2521,23 @@
             a.info.softInputMode = sa.getInt(
                     com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode,
                     0);
+
+            if (sa.getBoolean(
+                    com.android.internal.R.styleable.AndroidManifestActivity_persistable, false)) {
+                a.info.flags |= ActivityInfo.FLAG_PERSISTABLE;
+            }
+
+            if (sa.getBoolean(
+                    com.android.internal.R.styleable.AndroidManifestActivity_allowEmbedded,
+                    false)) {
+                a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
+            }
+
+            if (sa.getBoolean(
+                    com.android.internal.R.styleable.AndroidManifestActivity_autoRemoveFromRecents,
+                    false)) {
+                a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
+            }
         } else {
             a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
             a.info.configChanges = 0;
@@ -3535,6 +3581,7 @@
     public final static class Package {
 
         public String packageName;
+        public String splitName;
 
         // For now we only support one application per package.
         public final ApplicationInfo applicationInfo = new ApplicationInfo();
@@ -3591,10 +3638,13 @@
         // For use by the package manager to keep track of the path to the
         // file an app came from.
         public String mScanPath;
-        
-        // For use by package manager to keep track of where it has done dexopt.
-        public boolean mDidDexOpt;
-        
+
+        // For use by package manager to keep track of where it needs to do dexopt.
+        public boolean mDexOptNeeded = true;
+
+        // For use by package manager to keep track of when a package was last used.
+        public long mLastPackageUsageTimeInMills;
+
         // // User set enabled state.
         // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
         //
@@ -3648,9 +3698,10 @@
         public Set<PublicKey> mSigningKeys;
         public Map<String, Set<PublicKey>> mKeySetMapping;
 
-        public Package(String _name) {
-            packageName = _name;
-            applicationInfo.packageName = _name;
+        public Package(String packageName, String splitName) {
+            this.packageName = packageName;
+            this.splitName = splitName;
+            applicationInfo.packageName = packageName;
             applicationInfo.uid = -1;
         }
 
@@ -4255,4 +4306,13 @@
     public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) {
         sCompatibilityModeEnabled = compatibilityModeEnabled;
     }
+
+    public static class PackageParserException extends Exception {
+        public final int error;
+
+        public PackageParserException(int error, String detailMessage) {
+            super(detailMessage);
+            this.error = error;
+        }
+    }
 }
diff --git a/core/java/android/content/pm/Signature.java b/core/java/android/content/pm/Signature.java
index f4e7dc3..96aa083 100644
--- a/core/java/android/content/pm/Signature.java
+++ b/core/java/android/content/pm/Signature.java
@@ -31,8 +31,10 @@
 import java.util.Arrays;
 
 /**
- * Opaque, immutable representation of a signature associated with an
+ * Opaque, immutable representation of a signing certificate associated with an
  * application package.
+ * <p>
+ * This class name is slightly misleading, since it's not actually a signature.
  */
 public class Signature implements Parcelable {
     private final byte[] mSignature;
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index f53aa4c..c0383a3 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -27,8 +27,8 @@
  */
 public class UserInfo implements Parcelable {
 
-    /** 6 bits for user type */
-    public static final int FLAG_MASK_USER_TYPE = 0x0000003F;
+    /** 8 bits for user type */
+    public static final int FLAG_MASK_USER_TYPE = 0x000000FF;
 
     /**
      * *************************** NOTE ***************************
@@ -70,6 +70,11 @@
      */
     public static final int FLAG_MANAGED_PROFILE = 0x00000020;
 
+    /**
+     * Indicates that this user is disabled.
+     */
+    public static final int FLAG_DISABLED = 0x00000040;
+
 
     public static final int NO_PROFILE_GROUP_ID = -1;
 
@@ -117,6 +122,10 @@
         return (flags & FLAG_MANAGED_PROFILE) == FLAG_MANAGED_PROFILE;
     }
 
+    public boolean isEnabled() {
+        return (flags & FLAG_DISABLED) != FLAG_DISABLED;
+    }
+
     /**
      * @return true if this user can be switched to.
      **/
diff --git a/core/java/android/content/pm/VerificationParams.java b/core/java/android/content/pm/VerificationParams.java
index 22e1a85..bf1f77f 100644
--- a/core/java/android/content/pm/VerificationParams.java
+++ b/core/java/android/content/pm/VerificationParams.java
@@ -24,8 +24,10 @@
 /**
  * Represents verification parameters used to verify packages to be installed.
  *
+ * @deprecated callers should migrate to {@link PackageInstallerParams}.
  * @hide
  */
+@Deprecated
 public class VerificationParams implements Parcelable {
     /** A constant used to indicate that a uid value is not present. */
     public static final int NO_UID = -1;
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 4879c23..499de17 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -2308,8 +2308,8 @@
      */
     private Drawable loadDrawableForCookie(TypedValue value, int id, Theme theme) {
         if (value.string == null) {
-            throw new NotFoundException(
-                    "Resource is not a Drawable (color or path): " + value);
+            throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
+                    + Integer.toHexString(id) + ")  is not a Drawable (color or path): " + value);
         }
 
         final String file = value.string.toString();
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 4bea9ee..86208fc 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -397,6 +397,32 @@
     public static final String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
 
     /**
+     * A constant describing a wake gesture sensor.
+     * <p>
+     * Wake gesture sensors enable waking up the device based on a device specific motion.
+     * <p>
+     * When this sensor triggers, the device behaves as if the power button was pressed, turning the
+     * screen on. This behavior (turning on the screen when this sensor triggers) might be
+     * deactivated by the user in the device settings. Changes in settings do not impact the
+     * behavior of the sensor: only whether the framework turns the screen on when it triggers.
+     * <p>
+     * The actual gesture to be detected is not specified, and can be chosen by the manufacturer of
+     * the device. This sensor must be low power, as it is likely to be activated 24/7.
+     * Values of events created by this sensors should not be used.
+     *
+     * @hide This sensor is expected to only be used by the power manager
+     */
+    public static final int TYPE_WAKE_GESTURE = 42;
+
+    /**
+     * A constant string describing a wake gesture sensor.
+     *
+     * @hide This sensor is expected to only be used by the power manager
+     * @see #TYPE_WAKE_GESTURE
+     */
+    public static final String STRING_TYPE_WAKE_GESTURE = "android.sensor.wake_gesture";
+
+    /**
      * A constant describing all sensor types.
      */
     public static final int TYPE_ALL = -1;
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 722d956..5f2af8cf 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -372,7 +372,6 @@
 
     /**
      * <p>Optional. Hyperfocal distance for this lens.</p>
-     * <p>If the lens is fixed focus, the camera device will report 0.</p>
      * <p>If the lens is not fixed focus, the camera device will report this
      * field when {@link CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION android.lens.info.focusDistanceCalibration} is APPROXIMATE or CALIBRATED.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
@@ -1278,20 +1277,6 @@
             new Key<Integer>("android.sensor.orientation", int.class);
 
     /**
-     * <p>The number of input samples for each dimension of
-     * {@link CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP android.sensor.profileHueSatMap}.</p>
-     * <p>The number of input samples for the hue, saturation, and value
-     * dimension of {@link CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP android.sensor.profileHueSatMap}. The order of the
-     * dimensions given is hue, saturation, value; where hue is the 0th
-     * element.</p>
-     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
-     *
-     * @see CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP
-     */
-    public static final Key<int[]> SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS =
-            new Key<int[]>("android.sensor.profileHueSatMapDimensions", int[].class);
-
-    /**
      * <p>Optional. Defaults to [OFF]. Lists the supported test
      * pattern modes for {@link CaptureRequest#SENSOR_TEST_PATTERN_MODE android.sensor.testPatternMode}.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index bb290af..9d0e0e1 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -192,8 +192,9 @@
      *
      * <p>The camera device will query each Surface's size and formats upon this
      * call, so they must be set to a valid setting at this time (in particular:
-     * if the format is user-visible, it must be one of android.scaler.availableFormats;
-     * and the size must be one of android.scaler.available[Processed|Jpeg]Sizes).</p>
+     * if the format is user-visible, it must be one of
+     * {@link StreamConfigurationMap#getOutputFormats}; and the size must be one of
+     * {@link StreamConfigurationMap#getOutputSizes(int)}).</p>
      *
      * <p>When this method is called with valid Surfaces, the device will transition to the {@link
      * StateListener#onBusy busy state}. Once configuration is complete, the device will transition
@@ -239,6 +240,9 @@
      * @see StateListener#onUnconfigured
      * @see #stopRepeating
      * @see #flush
+     * @see StreamConfigurationMap#getOutputFormats()
+     * @see StreamConfigurationMap#getOutputSizes(int)
+     * @see StreamConfigurationMap#getOutputSizes(Class)
      */
     public void configureOutputs(List<Surface> outputs) throws CameraAccessException;
 
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index ba8db3a..6659278 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -17,6 +17,7 @@
 package android.hardware.camera2;
 
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.utils.TypeReference;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
@@ -126,11 +127,13 @@
         return keyList;
     }
 
+    // TODO: make final or abstract
     public static class Key<T> {
 
         private boolean mHasTag;
         private int mTag;
         private final Class<T> mType;
+        private final TypeReference<T> mTypeReference;
         private final String mName;
 
         /**
@@ -144,6 +147,22 @@
             }
             mName = name;
             mType = type;
+            mTypeReference = TypeReference.createSpecializedTypeReference(type);
+        }
+
+        /**
+         * @hide
+         */
+        @SuppressWarnings("unchecked")
+        public Key(String name, TypeReference<T> typeReference) {
+            if (name == null) {
+                throw new NullPointerException("Key needs a valid name");
+            } else if (typeReference == null) {
+                throw new NullPointerException("TypeReference needs to be non-null");
+            }
+            mName = name;
+            mType = (Class<T>)typeReference.getRawType();
+            mTypeReference = typeReference;
         }
 
         public final String getName() {
@@ -152,11 +171,10 @@
 
         @Override
         public final int hashCode() {
-            return mName.hashCode();
+            return mName.hashCode() ^ mTypeReference.hashCode();
         }
 
         @Override
-        @SuppressWarnings("unchecked")
         public final boolean equals(Object o) {
             if (this == o) {
                 return true;
@@ -166,9 +184,8 @@
                 return false;
             }
 
-            Key lhs = (Key) o;
-
-            return mName.equals(lhs.mName) && mType.equals(lhs.mType);
+            Key<?> lhs = (Key<?>)o;
+            return mName.equals(lhs.mName) && mTypeReference.equals(lhs.mTypeReference);
         }
 
         /**
@@ -192,11 +209,29 @@
         }
 
         /**
+         * Get the raw class backing the type {@code T} for this key.
+         *
+         * <p>The distinction is only important if {@code T} is a generic, e.g.
+         * {@code Range<Integer>} since the nested type will be erased.</p>
+         *
          * @hide
          */
         public final Class<T> getType() {
+            // TODO: remove this; other places should use #getTypeReference() instead
             return mType;
         }
+
+        /**
+         * Get the type reference backing the type {@code T} for this key.
+         *
+         * <p>The distinction is only important if {@code T} is a generic, e.g.
+         * {@code Range<Integer>} since the nested type will be retained.</p>
+         *
+         * @hide
+         */
+        public final TypeReference<T> getTypeReference() {
+            return mTypeReference;
+        }
     }
 
     /*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
@@ -1295,6 +1330,20 @@
     public static final int CONTROL_SCENE_MODE_BARCODE = 16;
 
     //
+    // Enumeration values for CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
+    //
+
+    /**
+     * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
+     */
+    public static final int CONTROL_VIDEO_STABILIZATION_MODE_OFF = 0;
+
+    /**
+     * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
+     */
+    public static final int CONTROL_VIDEO_STABILIZATION_MODE_ON = 1;
+
+    //
     // Enumeration values for CaptureRequest#EDGE_MODE
     //
 
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index c4e342c..0ca9161 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -458,7 +458,19 @@
      * brightness</p>
      * <p>For example, if EV step is 0.333, '6' will mean an
      * exposure compensation of +2 EV; -3 will mean an exposure
-     * compensation of -1</p>
+     * compensation of -1 EV. Note that this control will only be effective
+     * if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} <code>!=</code> OFF. This control will take effect even when
+     * {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} <code>== true</code>.</p>
+     * <p>In the event of exposure compensation value being changed, camera device
+     * may take several frames to reach the newly requested exposure target.
+     * During that time, {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} field will be in the SEARCHING
+     * state. Once the new exposure target is reached, {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} will
+     * change from SEARCHING to either CONVERGED, LOCKED (if AE lock is enabled), or
+     * FLASH_REQUIRED (if the scene is too dark for still capture).</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_LOCK
+     * @see CaptureRequest#CONTROL_AE_MODE
+     * @see CaptureResult#CONTROL_AE_STATE
      */
     public static final Key<Integer> CONTROL_AE_EXPOSURE_COMPENSATION =
             new Key<Integer>("android.control.aeExposureCompensation", int.class);
@@ -469,6 +481,8 @@
      * <p>Note that even when AE is locked, the flash may be
      * fired if the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_AUTO_FLASH / ON_ALWAYS_FLASH /
      * ON_AUTO_FLASH_REDEYE.</p>
+     * <p>When {@link CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION android.control.aeExposureCompensation} is changed, even if the AE lock
+     * is ON, the camera device will still adjust its exposure value.</p>
      * <p>If AE precapture is triggered (see {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger})
      * when AE is already locked, the camera device will not change the exposure time
      * ({@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}) and sensitivity ({@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity})
@@ -477,6 +491,7 @@
      * {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_ALWAYS_FLASH, the scene may become overexposed.</p>
      * <p>See {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE lock related state transition details.</p>
      *
+     * @see CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
      * @see CaptureResult#CONTROL_AE_STATE
@@ -831,9 +846,11 @@
      * stabilized</p>
      *
      * @see CaptureRequest#SCALER_CROP_REGION
+     * @see #CONTROL_VIDEO_STABILIZATION_MODE_OFF
+     * @see #CONTROL_VIDEO_STABILIZATION_MODE_ON
      */
-    public static final Key<Boolean> CONTROL_VIDEO_STABILIZATION_MODE =
-            new Key<Boolean>("android.control.videoStabilizationMode", boolean.class);
+    public static final Key<Integer> CONTROL_VIDEO_STABILIZATION_MODE =
+            new Key<Integer>("android.control.videoStabilizationMode", int.class);
 
     /**
      * <p>Operation mode for edge
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index d8981c8..42a3de8 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -124,6 +124,58 @@
 
 
     /**
+     * <p>The mode control selects how the image data is converted from the
+     * sensor's native color into linear sRGB color.</p>
+     * <p>When auto-white balance is enabled with {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, this
+     * control is overridden by the AWB routine. When AWB is disabled, the
+     * application controls how the color mapping is performed.</p>
+     * <p>We define the expected processing pipeline below. For consistency
+     * across devices, this is always the case with TRANSFORM_MATRIX.</p>
+     * <p>When either FULL or HIGH_QUALITY is used, the camera device may
+     * do additional processing but {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
+     * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform} will still be provided by the
+     * camera device (in the results) and be roughly correct.</p>
+     * <p>Switching to TRANSFORM_MATRIX and using the data provided from
+     * FAST or HIGH_QUALITY will yield a picture with the same white point
+     * as what was produced by the camera device in the earlier frame.</p>
+     * <p>The expected processing pipeline is as follows:</p>
+     * <p><img alt="White balance processing pipeline" src="../../../../images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png" /></p>
+     * <p>The white balance is encoded by two values, a 4-channel white-balance
+     * gain vector (applied in the Bayer domain), and a 3x3 color transform
+     * matrix (applied after demosaic).</p>
+     * <p>The 4-channel white-balance gains are defined as:</p>
+     * <pre><code>{@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} = [ R G_even G_odd B ]
+     * </code></pre>
+     * <p>where <code>G_even</code> is the gain for green pixels on even rows of the
+     * output, and <code>G_odd</code> is the gain for green pixels on the odd rows.
+     * These may be identical for a given camera device implementation; if
+     * the camera device does not support a separate gain for even/odd green
+     * channels, it will use the <code>G_even</code> value, and write <code>G_odd</code> equal to
+     * <code>G_even</code> in the output result metadata.</p>
+     * <p>The matrices for color transforms are defined as a 9-entry vector:</p>
+     * <pre><code>{@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform} = [ I0 I1 I2 I3 I4 I5 I6 I7 I8 ]
+     * </code></pre>
+     * <p>which define a transform from input sensor colors, <code>P_in = [ r g b ]</code>,
+     * to output linear sRGB, <code>P_out = [ r' g' b' ]</code>,</p>
+     * <p>with colors as follows:</p>
+     * <pre><code>r' = I0r + I1g + I2b
+     * g' = I3r + I4g + I5b
+     * b' = I6r + I7g + I8b
+     * </code></pre>
+     * <p>Both the input and output value ranges must match. Overflow/underflow
+     * values are clipped to fit within the range.</p>
+     *
+     * @see CaptureRequest#COLOR_CORRECTION_GAINS
+     * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
+     * @see CaptureRequest#CONTROL_AWB_MODE
+     * @see #COLOR_CORRECTION_MODE_TRANSFORM_MATRIX
+     * @see #COLOR_CORRECTION_MODE_FAST
+     * @see #COLOR_CORRECTION_MODE_HIGH_QUALITY
+     */
+    public static final Key<Integer> COLOR_CORRECTION_MODE =
+            new Key<Integer>("android.colorCorrection.mode", int.class);
+
+    /**
      * <p>A color transform matrix to use to transform
      * from sensor RGB color space to output linear sRGB color space</p>
      * <p>This matrix is either set by the camera device when the request
@@ -176,6 +228,97 @@
             new Key<Integer>("android.control.aePrecaptureId", int.class);
 
     /**
+     * <p>The desired setting for the camera device's auto-exposure
+     * algorithm's antibanding compensation.</p>
+     * <p>Some kinds of lighting fixtures, such as some fluorescent
+     * lights, flicker at the rate of the power supply frequency
+     * (60Hz or 50Hz, depending on country). While this is
+     * typically not noticeable to a person, it can be visible to
+     * a camera device. If a camera sets its exposure time to the
+     * wrong value, the flicker may become visible in the
+     * viewfinder as flicker or in a final captured image, as a
+     * set of variable-brightness bands across the image.</p>
+     * <p>Therefore, the auto-exposure routines of camera devices
+     * include antibanding routines that ensure that the chosen
+     * exposure value will not cause such banding. The choice of
+     * exposure time depends on the rate of flicker, which the
+     * camera device can detect automatically, or the expected
+     * rate can be selected by the application using this
+     * control.</p>
+     * <p>A given camera device may not support all of the possible
+     * options for the antibanding mode. The
+     * {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_ANTIBANDING_MODES android.control.aeAvailableAntibandingModes} key contains
+     * the available modes for a given camera device.</p>
+     * <p>The default mode is AUTO, which must be supported by all
+     * camera devices.</p>
+     * <p>If manual exposure control is enabled (by setting
+     * {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} or {@link CaptureRequest#CONTROL_MODE android.control.mode} to OFF),
+     * then this setting has no effect, and the application must
+     * ensure it selects exposure times that do not cause banding
+     * issues. The {@link CaptureResult#STATISTICS_SCENE_FLICKER android.statistics.sceneFlicker} key can assist
+     * the application in this.</p>
+     *
+     * @see CameraCharacteristics#CONTROL_AE_AVAILABLE_ANTIBANDING_MODES
+     * @see CaptureRequest#CONTROL_AE_MODE
+     * @see CaptureRequest#CONTROL_MODE
+     * @see CaptureResult#STATISTICS_SCENE_FLICKER
+     * @see #CONTROL_AE_ANTIBANDING_MODE_OFF
+     * @see #CONTROL_AE_ANTIBANDING_MODE_50HZ
+     * @see #CONTROL_AE_ANTIBANDING_MODE_60HZ
+     * @see #CONTROL_AE_ANTIBANDING_MODE_AUTO
+     */
+    public static final Key<Integer> CONTROL_AE_ANTIBANDING_MODE =
+            new Key<Integer>("android.control.aeAntibandingMode", int.class);
+
+    /**
+     * <p>Adjustment to AE target image
+     * brightness</p>
+     * <p>For example, if EV step is 0.333, '6' will mean an
+     * exposure compensation of +2 EV; -3 will mean an exposure
+     * compensation of -1 EV. Note that this control will only be effective
+     * if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} <code>!=</code> OFF. This control will take effect even when
+     * {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} <code>== true</code>.</p>
+     * <p>In the event of exposure compensation value being changed, camera device
+     * may take several frames to reach the newly requested exposure target.
+     * During that time, {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} field will be in the SEARCHING
+     * state. Once the new exposure target is reached, {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} will
+     * change from SEARCHING to either CONVERGED, LOCKED (if AE lock is enabled), or
+     * FLASH_REQUIRED (if the scene is too dark for still capture).</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_LOCK
+     * @see CaptureRequest#CONTROL_AE_MODE
+     * @see CaptureResult#CONTROL_AE_STATE
+     */
+    public static final Key<Integer> CONTROL_AE_EXPOSURE_COMPENSATION =
+            new Key<Integer>("android.control.aeExposureCompensation", int.class);
+
+    /**
+     * <p>Whether AE is currently locked to its latest
+     * calculated values.</p>
+     * <p>Note that even when AE is locked, the flash may be
+     * fired if the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_AUTO_FLASH / ON_ALWAYS_FLASH /
+     * ON_AUTO_FLASH_REDEYE.</p>
+     * <p>When {@link CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION android.control.aeExposureCompensation} is changed, even if the AE lock
+     * is ON, the camera device will still adjust its exposure value.</p>
+     * <p>If AE precapture is triggered (see {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger})
+     * when AE is already locked, the camera device will not change the exposure time
+     * ({@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}) and sensitivity ({@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity})
+     * 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>
+     * <p>See {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE lock related state transition details.</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION
+     * @see CaptureRequest#CONTROL_AE_MODE
+     * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
+     * @see CaptureResult#CONTROL_AE_STATE
+     * @see CaptureRequest#SENSOR_EXPOSURE_TIME
+     * @see CaptureRequest#SENSOR_SENSITIVITY
+     */
+    public static final Key<Boolean> CONTROL_AE_LOCK =
+            new Key<Boolean>("android.control.aeLock", boolean.class);
+
+    /**
      * <p>The desired mode for the camera device's
      * auto-exposure routine.</p>
      * <p>This control is only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} is
@@ -237,6 +380,35 @@
             new Key<int[]>("android.control.aeRegions", int[].class);
 
     /**
+     * <p>Range over which fps can be adjusted to
+     * maintain exposure</p>
+     * <p>Only constrains AE algorithm, not manual control
+     * of {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}</p>
+     *
+     * @see CaptureRequest#SENSOR_EXPOSURE_TIME
+     */
+    public static final Key<int[]> CONTROL_AE_TARGET_FPS_RANGE =
+            new Key<int[]>("android.control.aeTargetFpsRange", int[].class);
+
+    /**
+     * <p>Whether the camera device will trigger a precapture
+     * metering sequence when it processes this request.</p>
+     * <p>This entry is normally set to IDLE, or is not
+     * included at all in the request settings. When included and
+     * set to START, the camera device will trigger the autoexposure
+     * precapture metering sequence.</p>
+     * <p>The effect of AE precapture trigger depends on the current
+     * AE mode and state; see {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE precapture
+     * state transition details.</p>
+     *
+     * @see CaptureResult#CONTROL_AE_STATE
+     * @see #CONTROL_AE_PRECAPTURE_TRIGGER_IDLE
+     * @see #CONTROL_AE_PRECAPTURE_TRIGGER_START
+     */
+    public static final Key<Integer> CONTROL_AE_PRECAPTURE_TRIGGER =
+            new Key<Integer>("android.control.aePrecaptureTrigger", int.class);
+
+    /**
      * <p>Current state of AE algorithm</p>
      * <p>Switching between or enabling AE modes ({@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode}) always
      * resets the AE state to INACTIVE. Similarly, switching between {@link CaptureRequest#CONTROL_MODE android.control.mode},
@@ -481,6 +653,24 @@
             new Key<int[]>("android.control.afRegions", int[].class);
 
     /**
+     * <p>Whether the camera device will trigger autofocus for this request.</p>
+     * <p>This entry is normally set to IDLE, or is not
+     * included at all in the request settings.</p>
+     * <p>When included and set to START, the camera device will trigger the
+     * autofocus algorithm. If autofocus is disabled, this trigger has no effect.</p>
+     * <p>When set to CANCEL, the camera device will cancel any active trigger,
+     * and return to its initial AF state.</p>
+     * <p>See {@link CaptureResult#CONTROL_AF_STATE android.control.afState} for what that means for each AF mode.</p>
+     *
+     * @see CaptureResult#CONTROL_AF_STATE
+     * @see #CONTROL_AF_TRIGGER_IDLE
+     * @see #CONTROL_AF_TRIGGER_START
+     * @see #CONTROL_AF_TRIGGER_CANCEL
+     */
+    public static final Key<Integer> CONTROL_AF_TRIGGER =
+            new Key<Integer>("android.control.afTrigger", int.class);
+
+    /**
      * <p>Current state of AF algorithm.</p>
      * <p>Switching between or enabling AF modes ({@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}) always
      * resets the AF state to INACTIVE. Similarly, switching between {@link CaptureRequest#CONTROL_MODE android.control.mode},
@@ -889,6 +1079,16 @@
             new Key<Integer>("android.control.afTriggerId", int.class);
 
     /**
+     * <p>Whether AWB is currently locked to its
+     * latest calculated values.</p>
+     * <p>Note that AWB lock is only meaningful for AUTO
+     * mode; in other modes, AWB is already fixed to a specific
+     * setting.</p>
+     */
+    public static final Key<Boolean> CONTROL_AWB_LOCK =
+            new Key<Boolean>("android.control.awbLock", boolean.class);
+
+    /**
      * <p>Whether AWB is currently setting the color
      * transform fields, and what its illumination target
      * is.</p>
@@ -948,6 +1148,30 @@
             new Key<int[]>("android.control.awbRegions", int[].class);
 
     /**
+     * <p>Information to the camera device 3A (auto-exposure,
+     * auto-focus, auto-white balance) routines about the purpose
+     * of this capture, to help the camera device to decide optimal 3A
+     * strategy.</p>
+     * <p>This control (except for MANUAL) is only effective if
+     * <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code> and any 3A routine is active.</p>
+     * <p>ZERO_SHUTTER_LAG must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+     * contains ZSL. MANUAL must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+     * contains MANUAL_SENSOR.</p>
+     *
+     * @see CaptureRequest#CONTROL_MODE
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     * @see #CONTROL_CAPTURE_INTENT_CUSTOM
+     * @see #CONTROL_CAPTURE_INTENT_PREVIEW
+     * @see #CONTROL_CAPTURE_INTENT_STILL_CAPTURE
+     * @see #CONTROL_CAPTURE_INTENT_VIDEO_RECORD
+     * @see #CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT
+     * @see #CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG
+     * @see #CONTROL_CAPTURE_INTENT_MANUAL
+     */
+    public static final Key<Integer> CONTROL_CAPTURE_INTENT =
+            new Key<Integer>("android.control.captureIntent", int.class);
+
+    /**
      * <p>Current state of AWB algorithm</p>
      * <p>Switching between or enabling AWB modes ({@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}) always
      * resets the AWB state to INACTIVE. Similarly, switching between {@link CaptureRequest#CONTROL_MODE android.control.mode},
@@ -1078,6 +1302,31 @@
             new Key<Integer>("android.control.awbState", int.class);
 
     /**
+     * <p>A special color effect to apply.</p>
+     * <p>When this mode is set, a color effect will be applied
+     * to images produced by the camera device. The interpretation
+     * and implementation of these color effects is left to the
+     * implementor of the camera device, and should not be
+     * depended on to be consistent (or present) across all
+     * devices.</p>
+     * <p>A color effect will only be applied if
+     * {@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF.</p>
+     *
+     * @see CaptureRequest#CONTROL_MODE
+     * @see #CONTROL_EFFECT_MODE_OFF
+     * @see #CONTROL_EFFECT_MODE_MONO
+     * @see #CONTROL_EFFECT_MODE_NEGATIVE
+     * @see #CONTROL_EFFECT_MODE_SOLARIZE
+     * @see #CONTROL_EFFECT_MODE_SEPIA
+     * @see #CONTROL_EFFECT_MODE_POSTERIZE
+     * @see #CONTROL_EFFECT_MODE_WHITEBOARD
+     * @see #CONTROL_EFFECT_MODE_BLACKBOARD
+     * @see #CONTROL_EFFECT_MODE_AQUA
+     */
+    public static final Key<Integer> CONTROL_EFFECT_MODE =
+            new Key<Integer>("android.control.effectMode", int.class);
+
+    /**
      * <p>Overall mode of 3A control
      * routines.</p>
      * <p>High-level 3A control. When set to OFF, all 3A control
@@ -1106,6 +1355,57 @@
             new Key<Integer>("android.control.mode", int.class);
 
     /**
+     * <p>A camera mode optimized for conditions typical in a particular
+     * capture setting.</p>
+     * <p>This is the mode that that is active when
+     * <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == USE_SCENE_MODE</code>. Aside from FACE_PRIORITY,
+     * these modes will disable {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode},
+     * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, and {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode} while in use.</p>
+     * <p>The interpretation and implementation of these scene modes is left
+     * to the implementor of the camera device. Their behavior will not be
+     * consistent across all devices, and any given device may only implement
+     * a subset of these modes.</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_MODE
+     * @see CaptureRequest#CONTROL_AF_MODE
+     * @see CaptureRequest#CONTROL_AWB_MODE
+     * @see CaptureRequest#CONTROL_MODE
+     * @see #CONTROL_SCENE_MODE_DISABLED
+     * @see #CONTROL_SCENE_MODE_FACE_PRIORITY
+     * @see #CONTROL_SCENE_MODE_ACTION
+     * @see #CONTROL_SCENE_MODE_PORTRAIT
+     * @see #CONTROL_SCENE_MODE_LANDSCAPE
+     * @see #CONTROL_SCENE_MODE_NIGHT
+     * @see #CONTROL_SCENE_MODE_NIGHT_PORTRAIT
+     * @see #CONTROL_SCENE_MODE_THEATRE
+     * @see #CONTROL_SCENE_MODE_BEACH
+     * @see #CONTROL_SCENE_MODE_SNOW
+     * @see #CONTROL_SCENE_MODE_SUNSET
+     * @see #CONTROL_SCENE_MODE_STEADYPHOTO
+     * @see #CONTROL_SCENE_MODE_FIREWORKS
+     * @see #CONTROL_SCENE_MODE_SPORTS
+     * @see #CONTROL_SCENE_MODE_PARTY
+     * @see #CONTROL_SCENE_MODE_CANDLELIGHT
+     * @see #CONTROL_SCENE_MODE_BARCODE
+     */
+    public static final Key<Integer> CONTROL_SCENE_MODE =
+            new Key<Integer>("android.control.sceneMode", int.class);
+
+    /**
+     * <p>Whether video stabilization is
+     * active</p>
+     * <p>If enabled, video stabilization can modify the
+     * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream
+     * stabilized</p>
+     *
+     * @see CaptureRequest#SCALER_CROP_REGION
+     * @see #CONTROL_VIDEO_STABILIZATION_MODE_OFF
+     * @see #CONTROL_VIDEO_STABILIZATION_MODE_ON
+     */
+    public static final Key<Integer> CONTROL_VIDEO_STABILIZATION_MODE =
+            new Key<Integer>("android.control.videoStabilizationMode", int.class);
+
+    /**
      * <p>Operation mode for edge
      * enhancement.</p>
      * <p>Edge/sharpness/detail enhancement. OFF means no
@@ -1621,36 +1921,6 @@
             new Key<Rational[]>("android.sensor.neutralColorPoint", Rational[].class);
 
     /**
-     * <p>A mapping containing a hue shift, saturation scale, and value scale
-     * for each pixel.</p>
-     * <p>hue_samples, saturation_samples, and value_samples are given in
-     * {@link CameraCharacteristics#SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS android.sensor.profileHueSatMapDimensions}.</p>
-     * <p>Each entry of this map contains three floats corresponding to the
-     * hue shift, saturation scale, and value scale, respectively; where the
-     * hue shift has the lowest index. The map entries are stored in the tag
-     * in nested loop order, with the value divisions in the outer loop, the
-     * hue divisions in the middle loop, and the saturation divisions in the
-     * inner loop. All zero input saturation entries are required to have a
-     * value scale factor of 1.0.</p>
-     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
-     *
-     * @see CameraCharacteristics#SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS
-     */
-    public static final Key<float[]> SENSOR_PROFILE_HUE_SAT_MAP =
-            new Key<float[]>("android.sensor.profileHueSatMap", float[].class);
-
-    /**
-     * <p>A list of x,y samples defining a tone-mapping curve for gamma adjustment.</p>
-     * <p>This tag contains a default tone curve that can be applied while
-     * processing the image as a starting point for user adjustments.
-     * The curve is specified as a list of value pairs in linear gamma.
-     * The curve is interpolated using a cubic spline.</p>
-     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
-     */
-    public static final Key<float[]> SENSOR_PROFILE_TONE_CURVE =
-            new Key<float[]>("android.sensor.profileToneCurve", float[].class);
-
-    /**
      * <p>The worst-case divergence between Bayer green channels.</p>
      * <p>This value is an estimate of the worst case split between the
      * Bayer green channels in the red and blue rows in the sensor color
@@ -1688,6 +1958,22 @@
             new Key<Float>("android.sensor.greenSplit", float.class);
 
     /**
+     * <p>A pixel <code>[R, G_even, G_odd, B]</code> that supplies the test pattern
+     * when {@link CaptureRequest#SENSOR_TEST_PATTERN_MODE android.sensor.testPatternMode} is SOLID_COLOR.</p>
+     * <p>Each color channel is treated as an unsigned 32-bit integer.
+     * The camera device then uses the most significant X bits
+     * that correspond to how many bits are in its Bayer raw sensor
+     * output.</p>
+     * <p>For example, a sensor with RAW10 Bayer output would use the
+     * 10 most significant bits from each color channel.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#SENSOR_TEST_PATTERN_MODE
+     */
+    public static final Key<int[]> SENSOR_TEST_PATTERN_DATA =
+            new Key<int[]>("android.sensor.testPatternData", int[].class);
+
+    /**
      * <p>When enabled, the sensor sends a test pattern instead of
      * doing a real exposure from the camera.</p>
      * <p>When a test pattern is enabled, all manual sensor controls specified
@@ -1936,6 +2222,20 @@
             new Key<int[]>("android.statistics.hotPixelMap", int[].class);
 
     /**
+     * <p>Whether the camera device will output the lens
+     * shading map in output result metadata.</p>
+     * <p>When set to ON,
+     * {@link CaptureResult#STATISTICS_LENS_SHADING_MAP android.statistics.lensShadingMap} must be provided in
+     * the output result metadata.</p>
+     *
+     * @see CaptureResult#STATISTICS_LENS_SHADING_MAP
+     * @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
+     * @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
+     */
+    public static final Key<Integer> STATISTICS_LENS_SHADING_MAP_MODE =
+            new Key<Integer>("android.statistics.lensShadingMapMode", int.class);
+
+    /**
      * <p>Tonemapping / contrast / gamma curve for the blue
      * channel, to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is
      * CONTRAST_CURVE.</p>
diff --git a/core/java/android/hardware/camera2/ColorSpaceTransform.java b/core/java/android/hardware/camera2/ColorSpaceTransform.java
new file mode 100644
index 0000000..5e4c0a2
--- /dev/null
+++ b/core/java/android/hardware/camera2/ColorSpaceTransform.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+
+import static com.android.internal.util.Preconditions.*;
+
+import android.hardware.camera2.utils.HashCodeHelpers;
+
+import java.util.Arrays;
+
+/**
+ * Immutable class for describing a 3x3 matrix of {@link Rational} values in row-major order.
+ *
+ * <p>This matrix maps a transform from one color space to another. For the particular color space
+ * source and target, see the appropriate camera metadata documentation for the key that provides
+ * this value.</p>
+ *
+ * @see CameraMetadata
+ */
+public final class ColorSpaceTransform {
+
+    /** The number of rows in this matrix. */
+    private static final int ROWS = 3;
+
+    /** The number of columns in this matrix. */
+    private static final int COLUMNS = 3;
+
+    /** The number of total Rational elements in this matrix. */
+    private static final int COUNT = ROWS * COLUMNS;
+
+    /** Number of int elements in a rational. */
+    private static final int RATIONAL_SIZE = 2;
+
+    /** Numerator offset inside a rational (pair). */
+    private static final int OFFSET_NUMERATOR = 0;
+
+    /** Denominator offset inside a rational (pair). */
+    private static final int OFFSET_DENOMINATOR = 1;
+
+    /** Number of int elements in this matrix. */
+    private static final int COUNT_INT = ROWS * COLUMNS * RATIONAL_SIZE;
+
+    /**
+     * Create a new immutable {@link ColorSpaceTransform} instance from a {@link Rational} array.
+     *
+     * <p>The elements must be stored in a row-major order.</p>
+     *
+     * @param elements An array of {@code 9} elements
+     *
+     * @throws IllegalArgumentException
+     *            if the count of {@code elements} is not {@code 9}
+     * @throws NullPointerException
+     *            if {@code elements} or any sub-element is {@code null}
+     */
+    public ColorSpaceTransform(Rational[] elements) {
+
+        checkNotNull(elements, "elements must not be null");
+        if (elements.length != COUNT) {
+            throw new IllegalArgumentException("elements must be " + COUNT + " length");
+        }
+
+        mElements = new int[COUNT_INT];
+
+        for (int i = 0; i < elements.length; ++i) {
+            checkNotNull(elements, "element[" + i + "] must not be null");
+            mElements[i * RATIONAL_SIZE + OFFSET_NUMERATOR] = elements[i].getNumerator();
+            mElements[i * RATIONAL_SIZE + OFFSET_DENOMINATOR] = elements[i].getDenominator();
+        }
+    }
+
+    /**
+     * Create a new immutable {@link ColorSpaceTransform} instance from an {@code int} array.
+     *
+     * <p>The elements must be stored in a row-major order. Each rational is stored
+     * contiguously as a {@code (numerator, denominator)} pair.</p>
+     *
+     * <p>In particular:<pre>{@code
+     * int[] elements = new int[
+     *     N11, D11, N12, D12, N13, D13,
+     *     N21, D21, N22, D22, N23, D23,
+     *     N31, D31, N32, D32, N33, D33
+     * ];
+     *
+     * new ColorSpaceTransform(elements)}</pre>
+     *
+     * where {@code Nij} and {@code Dij} is the numerator and denominator for row {@code i} and
+     * column {@code j}.</p>
+     *
+     * @param elements An array of {@code 18} elements
+     *
+     * @throws IllegalArgumentException
+     *            if the count of {@code elements} is not {@code 18}
+     * @throws NullPointerException
+     *            if {@code elements} is {@code null}
+     */
+    public ColorSpaceTransform(int[] elements) {
+        checkNotNull(elements, "elements must not be null");
+        if (elements.length != COUNT_INT) {
+            throw new IllegalArgumentException("elements must be " + COUNT_INT + " length");
+        }
+
+        for (int i = 0; i < elements.length; ++i) {
+            checkNotNull(elements, "element " + i + " must not be null");
+        }
+
+        mElements = Arrays.copyOf(elements, elements.length);
+    }
+
+    /**
+     * Get an element of this matrix by its row and column.
+     *
+     * <p>The rows must be within the range [0, 3),
+     * and the column must be within the range [0, 3).</p>
+     *
+     * @return element (non-{@code null})
+     *
+     * @throws IllegalArgumentException if column or row was out of range
+     */
+    public Rational getElement(int column, int row) {
+        if (column < 0 || column >= COLUMNS) {
+            throw new IllegalArgumentException("column out of range");
+        } else if (row < 0 || row >= ROWS) {
+            throw new IllegalArgumentException("row out of range");
+        }
+
+        int numerator = mElements[row * ROWS * RATIONAL_SIZE + column + OFFSET_NUMERATOR];
+        int denominator = mElements[row * ROWS * RATIONAL_SIZE + column + OFFSET_DENOMINATOR];
+
+        return new Rational(numerator, denominator);
+    }
+
+    /**
+     * Copy the {@link Rational} elements in row-major order from this matrix into the destination.
+     *
+     * @param destination
+     *          an array big enough to hold at least {@code 9} elements after the
+     *          {@code offset}
+     * @param offset
+     *          a non-negative offset into the array
+     * @throws NullPointerException
+     *          If {@code destination} was {@code null}
+     * @throws ArrayIndexOutOfBoundsException
+     *          If there's not enough room to write the elements at the specified destination and
+     *          offset.
+     */
+    public void copyElements(Rational[] destination, int offset) {
+        checkArgumentNonnegative(offset, "offset must not be negative");
+        checkNotNull(destination, "destination must not be null");
+        if (destination.length + offset < COUNT) {
+            throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
+        }
+
+        for (int i = 0, j = 0; i < COUNT; ++i, j += RATIONAL_SIZE) {
+            int numerator = mElements[j + OFFSET_NUMERATOR];
+            int denominator = mElements[j + OFFSET_DENOMINATOR];
+
+            destination[i + offset] = new Rational(numerator, denominator);
+        }
+    }
+
+    /**
+     * Copy the {@link Rational} elements in row-major order from this matrix into the destination.
+     *
+     * <p>Each element is stored as a contiguous rational packed as a
+     * {@code (numerator, denominator)} pair of ints, identical to the
+     * {@link ColorSpaceTransform#ColorSpaceTransform(int[]) constructor}.</p>
+     *
+     * @param destination
+     *          an array big enough to hold at least {@code 18} elements after the
+     *          {@code offset}
+     * @param offset
+     *          a non-negative offset into the array
+     * @throws NullPointerException
+     *          If {@code destination} was {@code null}
+     * @throws ArrayIndexOutOfBoundsException
+     *          If there's not enough room to write the elements at the specified destination and
+     *          offset.
+     *
+     * @see ColorSpaceTransform#ColorSpaceTransform(int[])
+     */
+    public void copyElements(int[] destination, int offset) {
+        checkArgumentNonnegative(offset, "offset must not be negative");
+        checkNotNull(destination, "destination must not be null");
+        if (destination.length + offset < COUNT_INT) {
+            throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
+        }
+
+        // Manual copy faster than System#arraycopy for very small loops
+        for (int i = 0; i < COUNT_INT; ++i) {
+            destination[i + offset] = mElements[i];
+        }
+    }
+
+    /**
+     * Check if this {@link ColorSpaceTransform} is equal to another {@link ColorSpaceTransform}.
+     *
+     * <p>Two color space transforms are equal if and only if all of their elements are
+     * {@link Object#equals equal}.</p>
+     *
+     * @return {@code true} if the objects were equal, {@code false} otherwise
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof ColorSpaceTransform) {
+            final ColorSpaceTransform other = (ColorSpaceTransform) obj;
+            return Arrays.equals(mElements, other.mElements);
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return HashCodeHelpers.hashCode(mElements);
+    }
+
+    private final int[] mElements;
+};
diff --git a/core/java/android/hardware/camera2/LensShadingMap.java b/core/java/android/hardware/camera2/LensShadingMap.java
new file mode 100644
index 0000000..2b0108c
--- /dev/null
+++ b/core/java/android/hardware/camera2/LensShadingMap.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+
+import static com.android.internal.util.Preconditions.*;
+import static android.hardware.camera2.RggbChannelVector.*;
+
+import android.hardware.camera2.utils.HashCodeHelpers;
+
+import java.util.Arrays;
+
+/**
+ * Immutable class for describing a {@code 4 x N x M} lens shading map of floats.
+ *
+ * @see CameraCharacteristics#LENS_SHADING_MAP
+ */
+public final class LensShadingMap {
+
+    /**
+     * The smallest gain factor in this map.
+     *
+     * <p>All values in this map will be at least this large.</p>
+     */
+    public static final float MINIMUM_GAIN_FACTOR = 1.0f;
+
+    /**
+     * Create a new immutable LensShadingMap instance.
+     *
+     * <p>The elements must be stored in a row-major order (fully packed).</p>
+     *
+     * <p>This constructor takes over the array; do not write to the array afterwards.</p>
+     *
+     * @param elements
+     *          An array of elements whose length is
+     *          {@code RggbChannelVector.COUNT * rows * columns}
+     *
+     * @throws IllegalArgumentException
+     *            if the {@code elements} array length is invalid,
+     *            if any of the subelems are not finite or less than {@value #MINIMUM_GAIN_FACTOR},
+     *            or if rows or columns is not positive
+     * @throws NullPointerException
+     *            if {@code elements} is {@code null}
+     *
+     * @hide
+     */
+    public LensShadingMap(final float[] elements, final int rows, final int columns) {
+
+        mRows = checkArgumentPositive(rows, "rows must be positive");
+        mColumns = checkArgumentPositive(rows, "columns must be positive");
+        mElements = checkNotNull(elements, "elements must not be null");
+
+        if (elements.length != getGainFactorCount()) {
+            throw new IllegalArgumentException("elements must be " + getGainFactorCount() +
+                    " length");
+        }
+
+        // Every element must be finite and >= 1.0f
+        checkArrayElementsInRange(elements, MINIMUM_GAIN_FACTOR, Float.MAX_VALUE, "elements");
+    }
+
+    /**
+     * Get the number of rows in this map.
+     */
+    public int getRowCount() {
+        return mRows;
+    }
+
+    /**
+     * Get the number of columns in this map.
+     */
+    public int getColumnCount() {
+        return mColumns;
+    }
+
+    /**
+     * Get the total number of gain factors in this map.
+     *
+     * <p>A single gain factor contains exactly one color channel.
+     * Use with {@link #copyGainFactors} to allocate a large-enough array.</p>
+     */
+    public int getGainFactorCount() {
+        return mRows * mColumns * COUNT;
+    }
+
+    /**
+     * Get a single color channel gain factor from this lens shading map by its row and column.
+     *
+     * <p>The rows must be within the range [0, {@link #getRowCount}),
+     * the column must be within the range [0, {@link #getColumnCount}),
+     * and the color channel must be within the range [0, {@value RggbChannelVector#COUNT}).</p>
+     *
+     * <p>The channel order is {@code [R, Geven, Godd, B]}, where
+     * {@code Geven} is the green channel for the even rows of a Bayer pattern, and
+     * {@code Godd} is the odd rows.
+     * </p>
+     *
+     * @param colorChannel color channel from {@code [R, Geven, Godd, B]}
+     * @param column within the range [0, {@link #getColumnCount})
+     * @param row within the range [0, {@link #getRowCount})
+     *
+     * @return a gain factor >= {@value #MINIMUM_GAIN_FACTOR}
+     *
+     * @throws IllegalArgumentException if any of the parameters was out of range
+     *
+     * @see #RED
+     * @see #GREEN_EVEN
+     * @see #GREEN_ODD
+     * @see #BLUE
+     * @see #getRowCount
+     * @see #getColumnCount
+     */
+    public float getGainFactor(final int colorChannel, final int column, final int row) {
+        if (colorChannel < 0 || colorChannel > COUNT) {
+            throw new IllegalArgumentException("colorChannel out of range");
+        } else if (column < 0 || column >= mColumns) {
+            throw new IllegalArgumentException("column out of range");
+        } else if (row < 0 || row >= mRows) {
+            throw new IllegalArgumentException("row out of range");
+        }
+
+        return mElements[colorChannel + (row * mColumns +  column) * COUNT ];
+    }
+
+    /**
+     * Get a gain factor vector from this lens shading map by its row and column.
+     *
+     * <p>The rows must be within the range [0, {@link #getRowCount}),
+     * the column must be within the range [0, {@link #getColumnCount}).</p>
+     *
+     * @param column within the range [0, {@link #getColumnCount})
+     * @param row within the range [0, {@link #getRowCount})
+     *
+     * @return an {@link RggbChannelVector} where each gain factor >= {@value #MINIMUM_GAIN_FACTOR}
+     *
+     * @throws IllegalArgumentException if any of the parameters was out of range
+     *
+     * @see #getRowCount
+     * @see #getColumnCount
+     */
+    public RggbChannelVector getGainFactorVector(final int column, final int row) {
+        if (column < 0 || column >= mColumns) {
+            throw new IllegalArgumentException("column out of range");
+        } else if (row < 0 || row >= mRows) {
+            throw new IllegalArgumentException("row out of range");
+        }
+
+        final int offset = (row * mColumns +  column) * COUNT;
+
+        final float red =
+                mElements[RED + offset];
+        final float greenEven =
+                mElements[GREEN_EVEN + offset];
+        final float greenOdd =
+                mElements[GREEN_ODD + offset];
+        final float blue =
+                mElements[BLUE + offset];
+
+        return new RggbChannelVector(red, greenEven, greenOdd, blue);
+    }
+
+    /**
+     * Copy all gain factors in row-major order from this lens shading map into the destination.
+     *
+     * <p>Each gain factor will be >= {@link #MINIMUM_GAIN_FACTOR}.</p>
+     *
+     * @param destination
+     *          an array big enough to hold at least {@link RggbChannelVector#COUNT}
+     *          elements after the {@code offset}
+     * @param offset
+     *          a non-negative offset into the array
+     * @throws NullPointerException
+     *          If {@code destination} was {@code null}
+     * @throws IllegalArgumentException
+     *          If offset was negative
+     * @throws ArrayIndexOutOfBoundsException
+     *          If there's not enough room to write the elements at the specified destination and
+     *          offset.
+     *
+     * @see CaptureResult#STATISTICS_LENS_SHADING_MAP
+     */
+    public void copyGainFactors(final float[] destination, final int offset) {
+        checkArgumentNonnegative(offset, "offset must not be negative");
+        checkNotNull(destination, "destination must not be null");
+        if (destination.length + offset < getGainFactorCount()) {
+            throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
+        }
+
+        System.arraycopy(mElements, /*srcPos*/0, destination, offset, getGainFactorCount());
+    }
+
+    /**
+     * Check if this LensShadingMap is equal to another LensShadingMap.
+     *
+     * <p>Two lens shading maps are equal if and only if they have the same rows/columns,
+     * and all of their elements are {@link Object#equals equal}.</p>
+     *
+     * @return {@code true} if the objects were equal, {@code false} otherwise
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof LensShadingMap) {
+            final LensShadingMap other = (LensShadingMap) obj;
+            return mRows == other.mRows
+                    && mColumns == other.mColumns
+                    && Arrays.equals(mElements, other.mElements);
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        int elemsHash = HashCodeHelpers.hashCode(mElements);
+        return HashCodeHelpers.hashCode(mRows, mColumns, elemsHash);
+    }
+
+
+    private final int mRows;
+    private final int mColumns;
+    private final float[] mElements;
+};
diff --git a/core/java/android/hardware/camera2/MeteringRectangle.java b/core/java/android/hardware/camera2/MeteringRectangle.java
new file mode 100644
index 0000000..bb8e5b1
--- /dev/null
+++ b/core/java/android/hardware/camera2/MeteringRectangle.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+
+import android.util.Size;
+import static com.android.internal.util.Preconditions.*;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.camera2.utils.HashCodeHelpers;
+
+/**
+ * An immutable class to represent a rectangle {@code (x,y, width, height)} with an
+ * additional weight component.
+ *
+ * </p>The rectangle is defined to be inclusive of the specified coordinates.</p>
+ *
+ * <p>When used with a {@link CaptureRequest}, the coordinate system is based on the active pixel
+ * array, with {@code (0,0)} being the top-left pixel in the
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE active pixel array}, and
+ * {@code (android.sensor.info.activeArraySize.width - 1,
+ * android.sensor.info.activeArraySize.height - 1)}
+ * being the bottom-right pixel in the active pixel array.
+ * </p>
+ *
+ * <p>The metering weight is nonnegative.</p>
+ */
+public final class MeteringRectangle {
+
+    private final int mX;
+    private final int mY;
+    private final int mWidth;
+    private final int mHeight;
+    private final int mWeight;
+
+    /**
+     * Create a new metering rectangle.
+     *
+     * @param x coordinate >= 0
+     * @param y coordinate >= 0
+     * @param width width >= 0
+     * @param height height >= 0
+     * @param meteringWeight weight >= 0
+     *
+     * @throws IllegalArgumentException if any of the parameters were non-negative
+     */
+    public MeteringRectangle(int x, int y, int width, int height, int meteringWeight) {
+        mX = checkArgumentNonnegative(x, "x must be nonnegative");
+        mY = checkArgumentNonnegative(y, "y must be nonnegative");
+        mWidth = checkArgumentNonnegative(width, "width must be nonnegative");
+        mHeight = checkArgumentNonnegative(height, "height must be nonnegative");
+        mWeight = checkArgumentNonnegative(meteringWeight, "meteringWeight must be nonnegative");
+    }
+
+    /**
+     * Create a new metering rectangle.
+     *
+     * @param xy a non-{@code null} {@link Point} with both x,y >= 0
+     * @param dimensions a non-{@code null} {@link android.util.Size Size} with width, height >= 0
+     * @param meteringWeight weight >= 0
+     *
+     * @throws IllegalArgumentException if any of the parameters were non-negative
+     * @throws NullPointerException if any of the arguments were null
+     */
+    public MeteringRectangle(Point xy, Size dimensions, int meteringWeight) {
+        checkNotNull(xy, "xy must not be null");
+        checkNotNull(dimensions, "dimensions must not be null");
+
+        mX = checkArgumentNonnegative(xy.x, "x must be nonnegative");
+        mY = checkArgumentNonnegative(xy.y, "y must be nonnegative");
+        mWidth = checkArgumentNonnegative(dimensions.getWidth(), "width must be nonnegative");
+        mHeight = checkArgumentNonnegative(dimensions.getHeight(), "height must be nonnegative");
+        mWeight = checkArgumentNonnegative(meteringWeight, "meteringWeight must be nonnegative");
+    }
+
+    /**
+     * Create a new metering rectangle.
+     *
+     * @param rect a non-{@code null} rectangle with all x,y,w,h dimensions >= 0
+     * @param meteringWeight weight >= 0
+     *
+     * @throws IllegalArgumentException if any of the parameters were non-negative
+     * @throws NullPointerException if any of the arguments were null
+     */
+    public MeteringRectangle(Rect rect, int meteringWeight) {
+        checkNotNull(rect, "rect must not be null");
+
+        mX = checkArgumentNonnegative(rect.left, "rect.left must be nonnegative");
+        mY = checkArgumentNonnegative(rect.top, "rect.top must be nonnegative");
+        mWidth = checkArgumentNonnegative(rect.width(), "rect.width must be nonnegative");
+        mHeight = checkArgumentNonnegative(rect.height(), "rect.height must be nonnegative");
+        mWeight = checkArgumentNonnegative(meteringWeight, "meteringWeight must be nonnegative");
+    }
+
+    /**
+     * Return the X coordinate of the left side of the rectangle.
+     *
+     * @return x coordinate >= 0
+     */
+    public int getX() {
+        return mX;
+    }
+
+    /**
+     * Return the Y coordinate of the upper side of the rectangle.
+     *
+     * @return y coordinate >= 0
+     */
+    public int getY() {
+        return mY;
+    }
+
+    /**
+     * Return the width of the rectangle.
+     *
+     * @return width >= 0
+     */
+    public int getWidth() {
+        return mWidth;
+    }
+
+    /**
+     * Return the height of the rectangle.
+     *
+     * @return height >= 0
+     */
+    public int getHeight() {
+        return mHeight;
+    }
+
+    /**
+     * Return the metering weight of the rectangle.
+     *
+     * @return weight >= 0
+     */
+    public int getMeteringWeight() {
+        return mWeight;
+    }
+
+    /**
+     * Convenience method to create the upper-left (X,Y) coordinate as a {@link Point}.
+     *
+     * @return {@code (x,y)} point with both x,y >= 0
+     */
+    public Point getUpperLeftPoint() {
+        return new Point(mX, mY);
+    }
+
+    /**
+     * Convenience method to create the size from this metering rectangle.
+     *
+     * <p>This strips away the X,Y,weight from the rectangle.</p>
+     *
+     * @return a Size with non-negative width and height
+     */
+    public Size getSize() {
+        return new Size(mWidth, mHeight);
+    }
+
+    /**
+     * Convenience method to create a {@link Rect} from this metering rectangle.
+     *
+     * <p>This strips away the weight from the rectangle.</p>
+     *
+     * @return a {@link Rect} with non-negative x1, y1, x2, y2
+     */
+    public Rect getRect() {
+        return new Rect(mX, mY, mX + mWidth, mY + mHeight);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(final Object other) {
+        return other instanceof MeteringRectangle && equals((MeteringRectangle)other);
+    }
+
+    /**
+     * Compare two metering rectangles to see if they are equal.
+     *
+     * Two weighted rectangles are only considered equal if each of their components
+     * (x, y, width, height, weight) is respectively equal.
+     *
+     * @param other Another MeteringRectangle
+     *
+     * @return {@code true} if the metering rectangles are equal, {@code false} otherwise
+     */
+    public boolean equals(final MeteringRectangle other) {
+        if (other == null) {
+            return false;
+        }
+
+        return (mX == other.mX
+                && mY == other.mY
+                && mWidth == other.mWidth
+                && mHeight == other.mHeight
+                && mWidth == other.mWidth);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return HashCodeHelpers.hashCode(mX, mY, mWidth, mHeight, mWeight);
+    }
+}
diff --git a/core/java/android/hardware/camera2/Rational.java b/core/java/android/hardware/camera2/Rational.java
index 77b8c26..693ee2b 100644
--- a/core/java/android/hardware/camera2/Rational.java
+++ b/core/java/android/hardware/camera2/Rational.java
@@ -91,14 +91,14 @@
      * <p>A reduced form of a Rational is calculated by dividing both the numerator and the
      * denominator by their greatest common divisor.</p>
      *
-     * <pre>
+     * <pre>{@code
      *      (new Rational(1, 2)).equals(new Rational(1, 2)) == true   // trivially true
      *      (new Rational(2, 3)).equals(new Rational(1, 2)) == false  // trivially false
      *      (new Rational(1, 2)).equals(new Rational(2, 4)) == true   // true after reduction
      *      (new Rational(0, 0)).equals(new Rational(0, 0)) == true   // NaN.equals(NaN)
      *      (new Rational(1, 0)).equals(new Rational(5, 0)) == true   // both are +infinity
      *      (new Rational(1, 0)).equals(new Rational(-1, 0)) == false // +infinity != -infinity
-     * </pre>
+     * }</pre>
      *
      * @param obj a reference to another object
      *
@@ -159,16 +159,15 @@
         return (float) mNumerator / (float) mDenominator;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public int hashCode() {
-        final long INT_MASK = 0xffffffffL;
+        // Bias the hash code for the first (2^16) values for both numerator and denominator
+        int numeratorFlipped = mNumerator << 16 | mNumerator >>> 16;
 
-        long asLong = INT_MASK & mNumerator;
-        asLong <<= 32;
-
-        asLong |= (INT_MASK & mDenominator);
-
-        return ((Long)asLong).hashCode();
+        return mDenominator ^ numeratorFlipped;
     }
 
     /**
diff --git a/core/java/android/hardware/camera2/ReprocessFormatsMap.java b/core/java/android/hardware/camera2/ReprocessFormatsMap.java
new file mode 100644
index 0000000..894a499
--- /dev/null
+++ b/core/java/android/hardware/camera2/ReprocessFormatsMap.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 android.hardware.camera2;
+
+import static com.android.internal.util.Preconditions.*;
+
+import android.hardware.camera2.utils.HashCodeHelpers;
+
+import java.util.Arrays;
+
+/**
+ * Immutable class to store the input to output formats
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP map} to be used for with
+ * camera image reprocessing.
+ *
+ * <p>
+ * The mapping of image formats that are supported by this camera device for input streams,
+ * to their corresponding output formats.</p>
+ *
+ * <p>
+ * Attempting to configure an input stream with output streams not listed as available in this map
+ * is not valid.
+ * </p>
+ *
+ * @see CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ *
+ * <!-- hide this until we expose input streams through public API -->
+ * @hide
+ */
+public final class ReprocessFormatsMap {
+    /**
+     * Create a new {@link ReprocessFormatsMap}
+     *
+     * <p>This value is encoded as a variable-size array-of-arrays.
+     * The inner array always contains {@code [format, length, ...]} where ... has length elements.
+     * An inner array is followed by another inner array if the total metadata entry size hasn't
+     * yet been exceeded.</p>
+     *
+     * <p>Entry must not be {@code null}. Empty array is acceptable.</p>
+     *
+     * <p>The entry array ownership is passed to this instance after construction; do not
+     * write to it afterwards.</p>
+     *
+     * @param entry Array of ints, not yet deserialized (not-null)
+     *
+     * @throws IllegalArgumentException
+     *              if the data was poorly formatted
+     *              (missing output format length or too few output formats)
+     * @throws NullPointerException
+     *              if entry was null
+     *
+     * @hide
+     */
+    public ReprocessFormatsMap(final int[] entry) {
+        checkNotNull(entry, "entry must not be null");
+
+        int numInputs = 0;
+        int left = entry.length;
+        for (int i = 0; i < entry.length; ) {
+            final int format = entry[i];
+
+            left--;
+            i++;
+
+            if (left < 1) {
+                throw new IllegalArgumentException(
+                        String.format("Input %x had no output format length listed", format));
+            }
+
+            final int length = entry[i];
+            left--;
+            i++;
+
+            if (length > 0) {
+                if (left < length) {
+                    throw new IllegalArgumentException(
+                            String.format(
+                                    "Input %x had too few output formats listed (actual: %d, " +
+                                    "expected: %d)", format, left, length));
+                }
+
+                i += length;
+                left -= length;
+            }
+
+            numInputs++;
+        }
+
+        mEntry = entry;
+        mInputCount = numInputs;
+    }
+
+    /**
+     * Get a list of all input image formats that can be used to reprocess an input
+     * stream into an output stream.
+     *
+     * <p>Use this input format to look up the available output formats with {@link #getOutputs}.
+     * </p>
+     *
+     * @return an array of inputs (possibly empty, but never {@code null})
+     *
+     * @see ImageFormat
+     * @see #getOutputs
+     */
+    public int[] getInputs() {
+        final int[] inputs = new int[mInputCount];
+
+        int left = mEntry.length;
+        for (int i = 0, j = 0; i < mEntry.length; j++) {
+            final int format = mEntry[i];
+
+            left--;
+            i++;
+
+            if (left < 1) {
+                throw new AssertionError(
+                        String.format("Input %x had no output format length listed", format));
+            }
+            // TODO: check format is a valid input format
+
+            final int length = mEntry[i];
+            left--;
+            i++;
+
+            if (length > 0) {
+                if (left < length) {
+                    throw new AssertionError(
+                            String.format(
+                                    "Input %x had too few output formats listed (actual: %d, " +
+                                    "expected: %d)", format, left, length));
+                }
+
+                i += length;
+                left -= length;
+            }
+
+            // TODO: check output format is a valid output format
+
+            inputs[j] = format;
+        }
+
+        return inputs;
+    }
+
+    /**
+     * Get the list of output formats that can be reprocessed into from the input {@code format}.
+     *
+     * <p>The input {@code format} must be one of the formats returned by {@link #getInputs}.</p>
+     *
+     * @param format an input format
+     *
+     * @return list of output image formats
+     *
+     * @see ImageFormat
+     * @see #getInputs
+     */
+    public int[] getOutputs(final int format) {
+
+        int left = mEntry.length;
+        for (int i = 0; i < mEntry.length; ) {
+            final int inputFormat = mEntry[i];
+
+            left--;
+            i++;
+
+            if (left < 1) {
+                throw new AssertionError(
+                        String.format("Input %x had no output format length listed", format));
+            }
+
+            final int length = mEntry[i];
+            left--;
+            i++;
+
+            if (length > 0) {
+                if (left < length) {
+                    throw new AssertionError(
+                            String.format(
+                                    "Input %x had too few output formats listed (actual: %d, " +
+                                    "expected: %d)", format, left, length));
+                }
+            }
+
+            if (inputFormat == format) {
+                int[] outputs = new int[length];
+
+                // Copying manually faster than System.arraycopy for small arrays
+                for (int k = 0; k < length; ++k) {
+                    outputs[k] = mEntry[i + k];
+                }
+
+                return outputs;
+            }
+
+            i += length;
+            left -= length;
+
+        }
+
+        throw new IllegalArgumentException(
+                String.format("Input format %x was not one in #getInputs", format));
+    }
+
+    /**
+     * Check if this {@link ReprocessFormatsMap} is equal to another
+     * {@link ReprocessFormatsMap}.
+     *
+     * <p>These two objects are only equal if and only if each of the respective elements is equal.
+     * </p>
+     *
+     * @return {@code true} if the objects were equal, {@code false} otherwise
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof ReprocessFormatsMap) {
+            final ReprocessFormatsMap other = (ReprocessFormatsMap) obj;
+            // Do not compare anything besides mEntry, since the rest of the values are derived
+            return Arrays.equals(mEntry, other.mEntry);
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        // Do not hash anything besides mEntry since the rest of the values are derived
+        return HashCodeHelpers.hashCode(mEntry);
+    }
+
+    private final int[] mEntry;
+    /*
+     * Dependent fields: values are derived from mEntry
+     */
+    private final int mInputCount;
+}
diff --git a/core/java/android/hardware/camera2/RggbChannelVector.java b/core/java/android/hardware/camera2/RggbChannelVector.java
new file mode 100644
index 0000000..80167c6
--- /dev/null
+++ b/core/java/android/hardware/camera2/RggbChannelVector.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+
+import static com.android.internal.util.Preconditions.*;
+
+/**
+ * Immutable class to store a 4-element vector of floats indexable by a bayer RAW 2x2 pixel block.
+ */
+public final class RggbChannelVector {
+    /**
+     * The number of color channels in this vector.
+     */
+    public static final int COUNT = 4;
+
+    /** Red color channel in a bayer Raw pattern. */
+    public static final int RED = 0;
+
+    /** Green color channel in a bayer Raw pattern used by the even rows. */
+    public static final int GREEN_EVEN = 1;
+
+    /** Green color channel in a bayer Raw pattern used by the odd rows. */
+    public static final int GREEN_ODD = 2;
+
+    /** Blue color channel in a bayer Raw pattern. */
+    public static final int BLUE = 3;
+
+    /**
+     * Create a new {@link RggbChannelVector} from an RGGB 2x2 pixel.
+     *
+     * <p>All pixel values are considered normalized within {@code [0.0f, 1.0f]}
+     * (i.e. {@code 1.0f} could be linearized to {@code 255} if converting to a
+     * non-floating point pixel representation).</p>
+     *
+     * <p>All arguments must be finite; NaN and infinity is not allowed.</p>
+     *
+     * @param red red pixel
+     * @param greenEven green pixel (even row)
+     * @param greenOdd green pixel (odd row)
+     * @param blue blue pixel
+     *
+     * @throws IllegalArgumentException if any of the arguments were not finite
+     */
+    public RggbChannelVector(final float red, final float greenEven, final float greenOdd,
+            final float blue) {
+        mRed = checkArgumentFinite(red, "red");
+        mGreenEven = checkArgumentFinite(greenEven, "greenEven");
+        mGreenOdd = checkArgumentFinite(greenOdd, "greenOdd");
+        mBlue = checkArgumentFinite(blue, "blue");
+    }
+
+    /**
+     * Get the red component.
+     *
+     * @return a floating point value (guaranteed to be finite)
+     */
+    public final float getRed() {
+        return mRed;
+    }
+
+    /**
+     * Get the green (even rows) component.
+     *
+     * @return a floating point value (guaranteed to be finite)
+     */
+    public float getGreenEven() {
+        return mGreenEven;
+    }
+
+    /**
+     * Get the green (odd rows) component.
+     *
+     * @return a floating point value (guaranteed to be finite)
+     */
+    public float getGreenOdd() {
+        return mGreenOdd;
+    }
+
+    /**
+     * Get the blue component.
+     *
+     * @return a floating point value (guaranteed to be finite)
+     */
+    public float getBlue() {
+        return mBlue;
+    }
+
+    /**
+     * Get the component by the color channel index.
+     *
+     * <p>{@code colorChannel} must be one of {@link #RED}, {@link #GREEN_EVEN}, {@link #GREEN_ODD},
+     * {@link #BLUE}.</p>
+     *
+     * @param colorChannel greater or equal to {@code 0} and less than {@link #COUNT}
+     * @return a floating point value (guaranteed to be finite)
+     *
+     * @throws IllegalArgumentException if {@code colorChannel} was out of range
+     */
+    public float getComponent(final int colorChannel) {
+        if (colorChannel < 0 || colorChannel >= COUNT) {
+            throw new IllegalArgumentException("Color channel out of range");
+        }
+
+        switch (colorChannel) {
+            case RED:
+                return mRed;
+            case GREEN_EVEN:
+                return mGreenEven;
+            case GREEN_ODD:
+                return mGreenOdd;
+            case BLUE:
+                return mBlue;
+            default:
+                throw new AssertionError("Unhandled case " + colorChannel);
+        }
+    }
+
+    /**
+     * Copy the vector into the destination in the order {@code [R, Geven, Godd, B]}.
+     *
+     * @param destination
+     *          an array big enough to hold at least {@value #COUNT} elements after the
+     *          {@code offset}
+     * @param offset
+     *          a non-negative offset into the array
+     *
+     * @throws NullPointerException
+     *          If {@code destination} was {@code null}
+     * @throws ArrayIndexOutOfBoundsException
+     *          If there's not enough room to write the elements at the specified destination and
+     *          offset.
+     */
+    public void copyTo(final float[] destination, final int offset) {
+        checkNotNull(destination, "destination must not be null");
+        if (destination.length + offset < COUNT) {
+            throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
+        }
+
+        destination[offset + RED] = mRed;
+        destination[offset + GREEN_EVEN] = mGreenEven;
+        destination[offset + GREEN_ODD] = mGreenOdd;
+        destination[offset + BLUE] = mBlue;
+    }
+
+    /**
+     * Check if this {@link RggbChannelVector} is equal to another {@link RggbChannelVector}.
+     *
+     * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
+     *
+     * @return {@code true} if the objects were equal, {@code false} otherwise
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof RggbChannelVector) {
+            final RggbChannelVector other = (RggbChannelVector) obj;
+            return mRed == other.mRed &&
+                    mGreenEven == other.mGreenEven &&
+                    mGreenOdd == other.mGreenOdd &&
+                    mBlue == other.mBlue;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return Float.floatToIntBits(mRed) ^
+                Float.floatToIntBits(mGreenEven) ^
+                Float.floatToIntBits(mGreenOdd) ^
+                Float.floatToIntBits(mBlue);
+    }
+
+    private final float mRed;
+    private final float mGreenEven;
+    private final float mGreenOdd;
+    private final float mBlue;
+}
diff --git a/core/java/android/hardware/camera2/Size.java b/core/java/android/hardware/camera2/Size.java
index 45aaeae..9328a003 100644
--- a/core/java/android/hardware/camera2/Size.java
+++ b/core/java/android/hardware/camera2/Size.java
@@ -16,32 +16,55 @@
 
 package android.hardware.camera2;
 
+// TODO: Delete this class, since it was moved to android.util as public API
+
 /**
- * A simple immutable class for describing the dimensions of camera image
- * buffers.
+ * Immutable class for describing width and height dimensions in pixels.
+ *
+ * @hide
  */
 public final class Size {
     /**
-     * Create a new immutable Size instance
+     * Create a new immutable Size instance.
      *
-     * @param width The width to store in the Size instance
-     * @param height The height to store in the Size instance
+     * @param width The width of the size, in pixels
+     * @param height The height of the size, in pixels
      */
-    public Size(int width, int height) {
+    public Size(final int width, final int height) {
         mWidth = width;
         mHeight = height;
     }
 
+    /**
+     * Get the width of the size (in pixels).
+     * @return width
+     */
     public final int getWidth() {
         return mWidth;
     }
 
+    /**
+     * Get the height of the size (in pixels).
+     * @return height
+     */
     public final int getHeight() {
         return mHeight;
     }
 
+    /**
+     * Check if this size is equal to another size.
+     * <p>
+     * Two sizes are equal if and only if both their widths and heights are
+     * equal.
+     * </p>
+     * <p>
+     * A size object is never equal to any other type of object.
+     * </p>
+     *
+     * @return {@code true} if the objects were equal, {@code false} otherwise
+     */
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(final Object obj) {
         if (obj == null) {
             return false;
         }
@@ -49,27 +72,29 @@
             return true;
         }
         if (obj instanceof Size) {
-            Size other = (Size) obj;
+            final Size other = (Size) obj;
             return mWidth == other.mWidth && mHeight == other.mHeight;
         }
         return false;
     }
 
+    /**
+     * Return the size represented as a string with the format {@code "WxH"}
+     *
+     * @return string representation of the size
+     */
     @Override
     public String toString() {
         return mWidth + "x" + mHeight;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public int hashCode() {
-        final long INT_MASK = 0xffffffffL;
-
-        long asLong = INT_MASK & mWidth;
-        asLong <<= 32;
-
-        asLong |= (INT_MASK & mHeight);
-
-        return ((Long)asLong).hashCode();
+        // assuming most sizes are <2^16, doing a rotate will give us perfect hashing
+        return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2)));
     }
 
     private final int mWidth;
diff --git a/core/java/android/hardware/camera2/StreamConfiguration.java b/core/java/android/hardware/camera2/StreamConfiguration.java
new file mode 100644
index 0000000..a514034
--- /dev/null
+++ b/core/java/android/hardware/camera2/StreamConfiguration.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+
+import static com.android.internal.util.Preconditions.*;
+import static android.hardware.camera2.StreamConfigurationMap.checkArgumentFormatInternal;
+
+import android.graphics.ImageFormat;
+import android.hardware.camera2.utils.HashCodeHelpers;
+import android.util.Size;
+
+/**
+ * Immutable class to store the available stream
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS configurations} to be used
+ * when configuring streams with {@link CameraDevice#configureOutputs}.
+ * <!-- TODO: link to input stream configuration -->
+ *
+ * <p>This is the authoritative list for all input/output formats (and sizes respectively
+ * for that format) that are supported by a camera device.</p>
+ *
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ *
+ * @hide
+ */
+public final class StreamConfiguration {
+
+    /**
+     * Create a new {@link StreamConfiguration}.
+     *
+     * @param format image format
+     * @param width image width, in pixels (positive)
+     * @param height image height, in pixels (positive)
+     * @param input true if this is an input configuration, false for output configurations
+     *
+     * @throws IllegalArgumentException
+     *              if width/height were not positive
+     *              or if the format was not user-defined in ImageFormat/PixelFormat
+     *                  (IMPL_DEFINED is ok)
+     *
+     * @hide
+     */
+    public StreamConfiguration(
+            final int format, final int width, final int height, final boolean input) {
+        mFormat = checkArgumentFormatInternal(format);
+        mWidth = checkArgumentPositive(width, "width must be positive");
+        mHeight = checkArgumentPositive(height, "height must be positive");
+        mInput = input;
+    }
+
+    /**
+     * Get the image {@code format} in this stream configuration.
+     *
+     * @return an integer format
+     *
+     * @see ImageFormat
+     */
+    public final int getFormat() {
+        return mFormat;
+    }
+
+
+    /**
+     * Return the width of the stream configuration.
+     *
+     * @return width > 0
+     */
+    public int getWidth() {
+        return mWidth;
+    }
+
+    /**
+     * Return the height of the stream configuration.
+     *
+     * @return height > 0
+     */
+    public int getHeight() {
+        return mHeight;
+    }
+
+    /**
+     * Convenience method to return the size of this stream configuration.
+     *
+     * @return a Size with positive width and height
+     */
+    public Size getSize() {
+        return new Size(mWidth, mHeight);
+    }
+
+    /**
+     * Determines if this configuration is usable for input streams.
+     *
+     * <p>Input and output stream configurations are not interchangeable;
+     * input stream configurations must be used when configuring inputs.</p>
+     *
+     * @return {@code true} if input configuration, {@code false} otherwise
+     */
+    public boolean isInput() {
+        return mInput;
+    }
+
+    /**
+     * Determines if this configuration is usable for output streams.
+     *
+     * <p>Input and output stream configurations are not interchangeable;
+     * out stream configurations must be used when configuring outputs.</p>
+     *
+     * @return {@code true} if output configuration, {@code false} otherwise
+     *
+     * @see CameraDevice#configureOutputs
+     */
+    public boolean isOutput() {
+        return !mInput;
+    }
+
+    /**
+     * Check if this {@link StreamConfiguration} is equal to another {@link StreamConfiguration}.
+     *
+     * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
+     *
+     * @return {@code true} if the objects were equal, {@code false} otherwise
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof StreamConfiguration) {
+            final StreamConfiguration other = (StreamConfiguration) obj;
+            return mFormat == other.mFormat &&
+                    mWidth == other.mWidth &&
+                    mHeight == other.mHeight &&
+                    mInput == other.mInput;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return HashCodeHelpers.hashCode(mFormat, mWidth, mHeight, mInput ? 1 : 0);
+    }
+
+    private final int mFormat;
+    private final int mWidth;
+    private final int mHeight;
+    private final boolean mInput;
+}
diff --git a/core/java/android/hardware/camera2/StreamConfigurationDuration.java b/core/java/android/hardware/camera2/StreamConfigurationDuration.java
new file mode 100644
index 0000000..6a31156
--- /dev/null
+++ b/core/java/android/hardware/camera2/StreamConfigurationDuration.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+
+import static com.android.internal.util.Preconditions.*;
+import static android.hardware.camera2.StreamConfigurationMap.checkArgumentFormatInternal;
+
+import android.graphics.ImageFormat;
+import android.hardware.camera2.utils.HashCodeHelpers;
+import android.util.Size;
+
+/**
+ * Immutable class to store a time duration for any given format/size combination.
+ *
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
+ *
+ * @hide
+ */
+public final class StreamConfigurationDuration {
+
+    /**
+     * Create a new {@link StreamConfigurationDuration}.
+     *
+     * @param format image format
+     * @param width image width, in pixels (positive)
+     * @param height image height, in pixels (positive)
+     * @param durationNs duration in nanoseconds (non-negative)
+     *
+     * @throws IllegalArgumentException
+     *          if width/height were not positive, or durationNs was negative
+     *          or if the format was not user-defined in ImageFormat/PixelFormat
+     *              (IMPL_DEFINED is OK)
+     *
+     *
+     * @hide
+     */
+    public StreamConfigurationDuration(
+            final int format, final int width, final int height, final long durationNs) {
+        mFormat =  checkArgumentFormatInternal(format);
+        mWidth = checkArgumentPositive(width, "width must be positive");
+        mHeight = checkArgumentPositive(height, "height must be positive");
+        mDurationNs = checkArgumentNonnegative(durationNs, "durationNs must be non-negative");
+    }
+
+    /**
+     * Get the image {@code format} in this stream configuration duration
+     *
+     * @return an integer format
+     *
+     * @see ImageFormat
+     */
+    public final int getFormat() {
+        return mFormat;
+    }
+
+
+    /**
+     * Return the width of the stream configuration duration.
+     *
+     * @return width > 0
+     */
+    public int getWidth() {
+        return mWidth;
+    }
+
+    /**
+     * Return the height of the stream configuration duration
+     *
+     * @return height > 0
+     */
+    public int getHeight() {
+        return mHeight;
+    }
+
+    /**
+     * Convenience method to return the size of this stream configuration duration.
+     *
+     * @return a Size with positive width and height
+     */
+    public Size getSize() {
+        return new Size(mWidth, mHeight);
+    }
+
+    /**
+     * Get the time duration (in nanoseconds).
+     *
+     * @return long >= 0
+     */
+    public long getDuration() {
+        return mDurationNs;
+    }
+
+    /**
+     * Check if this {@link StreamConfigurationDuration} is equal to another
+     * {@link StreamConfigurationDuration}.
+     *
+     * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
+     *
+     * @return {@code true} if the objects were equal, {@code false} otherwise
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof StreamConfigurationDuration) {
+            final StreamConfigurationDuration other = (StreamConfigurationDuration) obj;
+            return mFormat == other.mFormat &&
+                    mWidth == other.mWidth &&
+                    mHeight == other.mHeight &&
+                    mDurationNs == other.mDurationNs;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return HashCodeHelpers.hashCode(mFormat, mWidth, mHeight,
+                (int) mDurationNs, (int)(mDurationNs >>> Integer.SIZE));
+    }
+
+    private final int mFormat;
+    private final int mWidth;
+    private final int mHeight;
+    private final long mDurationNs;
+}
diff --git a/core/java/android/hardware/camera2/StreamConfigurationMap.java b/core/java/android/hardware/camera2/StreamConfigurationMap.java
new file mode 100644
index 0000000..5ddd7d6
--- /dev/null
+++ b/core/java/android/hardware/camera2/StreamConfigurationMap.java
@@ -0,0 +1,508 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+
+import android.graphics.ImageFormat;
+import android.graphics.PixelFormat;
+import android.hardware.camera2.utils.HashCodeHelpers;
+import android.view.Surface;
+import android.util.Size;
+
+import java.util.Arrays;
+
+import static com.android.internal.util.Preconditions.*;
+
+/**
+ * Immutable class to store the available stream
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS configurations} to be used
+ * when configuring streams with {@link CameraDevice#configureOutputs}.
+ * <!-- TODO: link to input stream configuration -->
+ *
+ * <p>This is the authoritative list for all <!-- input/ -->output formats (and sizes respectively
+ * for that format) that are supported by a camera device.</p>
+ *
+ * <p>This also contains the minimum frame durations and stall durations for each format/size
+ * combination that can be used to calculate effective frame rate when submitting multiple captures.
+ * </p>
+ *
+ * <p>An instance of this object is available from {@link CameraCharacteristics} using
+ * the {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS} key and the
+ * {@link CameraCharacteristics#get} method.</p.
+ *
+ * <pre>{@code
+ * CameraCharacteristics characteristics = ...;
+ * StreamConfigurationMap configs = characteristics.get(
+ *         CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+ * }</pre>
+ *
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ * @see CameraDevice#configureOutputs
+ */
+public final class StreamConfigurationMap {
+
+    /**
+     * Create a new {@link StreamConfigurationMap}.
+     *
+     * <p>The array parameters ownership is passed to this object after creation; do not
+     * write to them after this constructor is invoked.</p>
+     *
+     * @param configurations a non-{@code null} array of {@link StreamConfiguration}
+     * @param durations a non-{@code null} array of {@link StreamConfigurationDuration}
+     *
+     * @throws NullPointerException if any of the arguments or subelements were {@code null}
+     *
+     * @hide
+     */
+    public StreamConfigurationMap(
+            StreamConfiguration[] configurations,
+            StreamConfigurationDuration[] durations) {
+        // TODO: format check against ImageFormat/PixelFormat ?
+
+        mConfigurations = checkArrayElementsNotNull(configurations, "configurations");
+        mDurations = checkArrayElementsNotNull(durations, "durations");
+
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Get the image {@code format} output formats in this stream configuration.
+     *
+     * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
+     * or in {@link PixelFormat} (and there is no possibility of collision).</p>
+     *
+     * <p>Formats listed in this array are guaranteed to return true if queried with
+     * {@link #isOutputSupportedFor(int).</p>
+     *
+     * @return an array of integer format
+     *
+     * @see ImageFormat
+     * @see PixelFormat
+     */
+    public final int[] getOutputFormats() {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Get the image {@code format} input formats in this stream configuration.
+     *
+     * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
+     * or in {@link PixelFormat} (and there is no possibility of collision).</p>
+     *
+     * @return an array of integer format
+     *
+     * @see ImageFormat
+     * @see PixelFormat
+     *
+     * @hide
+     */
+    public final int[] getInputFormats() {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Get the supported input sizes for this input format.
+     *
+     * <p>The format must have come from {@link #getInputFormats}; otherwise
+     * {@code null} is returned.</p>
+     *
+     * @param format a format from {@link #getInputFormats}
+     * @return a non-empty array of sizes, or {@code null} if the format was not available.
+     *
+     * @hide
+     */
+    public Size[] getInputSizes(final int format) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Determine whether or not output streams can be
+     * {@link CameraDevice#configureOutputs configured} with a particular user-defined format.
+     *
+     * <p>This method determines that the output {@code format} is supported by the camera device;
+     * each output {@code surface} target may or may not itself support that {@code format}.
+     * Refer to the class which provides the surface for additional documentation.</p>
+     *
+     * <p>Formats for which this returns {@code true} are guaranteed to exist in the result
+     * returned by {@link #getOutputSizes}.</p>
+     *
+     * @param format an image format from either {@link ImageFormat} or {@link PixelFormat}
+     * @return
+     *          {@code true} iff using a {@code surface} with this {@code format} will be
+     *          supported with {@link CameraDevice#configureOutputs}
+     *
+     * @throws IllegalArgumentException
+     *          if the image format was not a defined named constant
+     *          from either {@link ImageFormat} or {@link PixelFormat}
+     *
+     * @see ImageFormat
+     * @see PixelFormat
+     * @see CameraDevice#configureOutputs
+     */
+    public boolean isOutputSupportedFor(int format) {
+        checkArgumentFormat(format);
+
+        final int[] formats = getOutputFormats();
+        for (int i = 0; i < formats.length; ++i) {
+            if (format == formats[i]) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Determine whether or not output streams can be configured with a particular class
+     * as a consumer.
+     *
+     * <p>The following list is generally usable for outputs:
+     * <ul>
+     * <li>{@link android.media.ImageReader} -
+     * Recommended for image processing or streaming to external resources (such as a file or
+     * network)
+     * <li>{@link android.media.MediaRecorder} -
+     * Recommended for recording video (simple to use)
+     * <li>{@link android.media.MediaCodec} -
+     * Recommended for recording video (more complicated to use, with more flexibility)
+     * <li>{@link android.renderscript.Allocation} -
+     * Recommended for image processing with {@link android.renderscript RenderScript}
+     * <li>{@link android.view.SurfaceHolder} -
+     * Recommended for low-power camera preview with {@link android.view.SurfaceView}
+     * <li>{@link android.graphics.SurfaceTexture} -
+     * Recommended for OpenGL-accelerated preview processing or compositing with
+     * {@link android.view.TextureView}
+     * </ul>
+     * </p>
+     *
+     * <p>Generally speaking this means that creating a {@link Surface} from that class <i>may</i>
+     * provide a producer endpoint that is suitable to be used with
+     * {@link CameraDevice#configureOutputs}.</p>
+     *
+     * <p>Since not all of the above classes support output of all format and size combinations,
+     * the particular combination should be queried with {@link #isOutputSupportedFor(Surface)}.</p>
+     *
+     * @param klass a non-{@code null} {@link Class} object reference
+     * @return {@code true} if this class is supported as an output, {@code false} otherwise
+     *
+     * @throws NullPointerException if {@code klass} was {@code null}
+     *
+     * @see CameraDevice#configureOutputs
+     * @see #isOutputSupportedFor(Surface)
+     */
+    public static <T> boolean isOutputSupportedFor(final Class<T> klass) {
+        checkNotNull(klass, "klass must not be null");
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Determine whether or not the {@code surface} in its current state is suitable to be
+     * {@link CameraDevice#configureOutputs configured} as an output.
+     *
+     * <p>Not all surfaces are usable with the {@link CameraDevice}, and not all configurations
+     * of that {@code surface} are compatible. Some classes that provide the {@code surface} are
+     * compatible with the {@link CameraDevice} in general
+     * (see {@link #isOutputSupportedFor(Class)}, but it is the caller's responsibility to put the
+     * {@code surface} into a state that will be compatible with the {@link CameraDevice}.</p>
+     *
+     * <p>Reasons for a {@code surface} being specifically incompatible might be:
+     * <ul>
+     * <li>Using a format that's not listed by {@link #getOutputFormats}
+     * <li>Using a format/size combination that's not listed by {@link #getOutputSizes}
+     * <li>The {@code surface} itself is not in a state where it can service a new producer.</p>
+     * </li>
+     * </ul>
+     *
+     * This is not an exhaustive list; see the particular class's documentation for further
+     * possible reasons of incompatibility.</p>
+     *
+     * @param surface a non-{@code null} {@link Surface} object reference
+     * @return {@code true} if this is supported, {@code false} otherwise
+     *
+     * @throws NullPointerException if {@code surface} was {@code null}
+     *
+     * @see CameraDevice#configureOutputs
+     * @see #isOutputSupportedFor(Class)
+     */
+    public boolean isOutputSupportedFor(final Surface surface) {
+        checkNotNull(surface, "surface must not be null");
+
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Get a list of sizes compatible with {@code klass} to use as an output.
+     *
+     * <p>Since some of the supported classes may support additional formats beyond
+     * an opaque/implementation-defined (under-the-hood) format; this function only returns
+     * sizes for the implementation-defined format.</p>
+     *
+     * <p>Some classes such as {@link android.media.ImageReader} may only support user-defined
+     * formats; in particular {@link #isOutputSupportedFor(Class)} will return {@code true} for
+     * that class and this method will return an empty array (but not {@code null}).</p>
+     *
+     * <p>If a well-defined format such as {@code NV21} is required, use
+     * {@link #getOutputSizes(int)} instead.</p>
+     *
+     * <p>The {@code klass} should be a supported output, that querying
+     * {@code #isOutputSupportedFor(Class)} should return {@code true}.</p>
+     *
+     * @param klass
+     *          a non-{@code null} {@link Class} object reference
+     * @return
+     *          an array of supported sizes for implementation-defined formats,
+     *          or {@code null} iff the {@code klass} is not a supported output
+     *
+     * @throws NullPointerException if {@code klass} was {@code null}
+     *
+     * @see #isOutputSupportedFor(Class)
+     */
+    public <T> Size[] getOutputSizes(final Class<T> klass) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Get a list of sizes compatible with the requested image {@code format}.
+     *
+     * <p>The {@code format} should be a supported format (one of the formats returned by
+     * {@link #getOutputFormats}).</p>
+     *
+     * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+     * @return
+     *          an array of supported sizes,
+     *          or {@code null} if the {@code format} is not a supported output
+     *
+     * @see ImageFormat
+     * @see PixelFormat
+     * @see #getOutputFormats
+     */
+    public Size[] getOutputSizes(final int format) {
+        try {
+            checkArgumentFormatSupported(format, /*output*/true);
+        } catch (IllegalArgumentException e) {
+            return null;
+        }
+
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
+     * for the format/size combination (in nanoseconds).
+     *
+     * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p>
+     * <p>{@code size} should be one of the ones returned by
+     * {@link #getOutputSizes(int)}.</p>
+     *
+     * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+     * @param size an output-compatible size
+     * @return a minimum frame duration {@code >=} 0 in nanoseconds
+     *
+     * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
+     * @throws NullPointerException if {@code size} was {@code null}
+     *
+     * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
+     * @see CaptureRequest#SENSOR_FRAME_DURATION
+     * @see ImageFormat
+     * @see PixelFormat
+     */
+    public long getOutputMinFrameDuration(final int format, final Size size) {
+        checkArgumentFormatSupported(format, /*output*/true);
+
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
+     * for the class/size combination (in nanoseconds).
+     *
+     * <p>This assumes a the {@code klass} is set up to use an implementation-defined format.
+     * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p>
+     *
+     * <p>{@code klass} should be one of the ones which is supported by
+     * {@link #isOutputSupportedFor(Class)}.</p>
+     *
+     * <p>{@code size} should be one of the ones returned by
+     * {@link #getOutputSizes(int)}.</p>
+     *
+     * @param klass
+     *          a class which is supported by {@link #isOutputSupportedFor(Class)} and has a
+     *          non-empty array returned by {@link #getOutputSizes(Class)}
+     * @param size an output-compatible size
+     * @return a minimum frame duration {@code >=} 0 in nanoseconds
+     *
+     * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
+     * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
+     *
+     * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
+     * @see CaptureRequest#SENSOR_FRAME_DURATION
+     * @see ImageFormat
+     * @see PixelFormat
+     */
+    public <T> long getOutputMinFrameDuration(final Class<T> klass, final Size size) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Get the {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS stall duration}
+     * for the format/size combination (in nanoseconds).
+     *
+     * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p>
+     * <p>{@code size} should be one of the ones returned by
+     * {@link #getOutputSizes(int)}.</p>
+     *
+     * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+     * @param size an output-compatible size
+     * @return a stall duration {@code >=} 0 in nanoseconds
+     *
+     * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
+     * @throws NullPointerException if {@code size} was {@code null}
+     *
+     * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
+     * @see ImageFormat
+     * @see PixelFormat
+     */
+    public long getOutputStallDuration(final int format, final Size size) {
+        checkArgumentFormatSupported(format, /*output*/true);
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Get the {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS stall duration}
+     * for the class/size combination (in nanoseconds).
+     *
+     * <p>This assumes a the {@code klass} is set up to use an implementation-defined format.
+     * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p>
+     *
+     * <p>{@code klass} should be one of the ones with a non-empty array returned by
+     * {@link #getOutputSizes(Class)}.</p>
+     *
+     * <p>{@code size} should be one of the ones returned by
+     * {@link #getOutputSizes(Class)}.</p>
+     *
+     * @param klass
+     *          a class which is supported by {@link #isOutputSupportedFor(Class)} and has a
+     *          non-empty array returned by {@link #getOutputSizes(Class)}
+     * @param size an output-compatible size
+     * @return a minimum frame duration {@code >=} 0 in nanoseconds
+     *
+     * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
+     * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
+     *
+     * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
+     * @see CaptureRequest#SENSOR_FRAME_DURATION
+     * @see ImageFormat
+     * @see PixelFormat
+     */
+    public <T> long getOutputStallDuration(final Class<T> klass, final Size size) {
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    /**
+     * Check if this {@link StreamConfigurationMap} is equal to another
+     * {@link StreamConfigurationMap}.
+     *
+     * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
+     *
+     * @return {@code true} if the objects were equal, {@code false} otherwise
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof StreamConfigurationMap) {
+            final StreamConfigurationMap other = (StreamConfigurationMap) obj;
+            // TODO: do we care about order?
+            return Arrays.equals(mConfigurations, other.mConfigurations) &&
+                    Arrays.equals(mDurations, other.mDurations);
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        // TODO: do we care about order?
+        return HashCodeHelpers.hashCode(mConfigurations) ^ HashCodeHelpers.hashCode(mDurations);
+    }
+
+    // Check that the argument is supported by #getOutputFormats or #getInputFormats
+    private int checkArgumentFormatSupported(int format, boolean output) {
+        checkArgumentFormat(format);
+
+        int[] formats = output ? getOutputFormats() : getInputFormats();
+        for (int i = 0; i < formats.length; ++i) {
+            if (format == formats[i]) {
+                return format;
+            }
+        }
+
+        throw new IllegalArgumentException(String.format(
+                "format %x is not supported by this stream configuration map", format));
+    }
+
+    /**
+     * Ensures that the format is either user-defined or implementation defined.
+     *
+     * <p>Any invalid/undefined formats will raise an exception.</p>
+     *
+     * @param format image format
+     * @return the format
+     *
+     * @throws IllegalArgumentException if the format was invalid
+     */
+    static int checkArgumentFormatInternal(int format) {
+        if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+            return format;
+        }
+
+        return checkArgumentFormat(format);
+    }
+
+    /**
+     * Ensures that the format is user-defined in either ImageFormat or PixelFormat.
+     *
+     * <p>Any invalid/undefined formats will raise an exception, including implementation-defined.
+     * </p>
+     *
+     * <p>Note that {@code @hide} and deprecated formats will not pass this check.</p>
+     *
+     * @param format image format
+     * @return the format
+     *
+     * @throws IllegalArgumentException if the format was not user-defined
+     */
+    static int checkArgumentFormat(int format) {
+        if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
+            throw new IllegalArgumentException(String.format(
+                    "format %x was not defined in either ImageFormat or PixelFormat", format));
+        }
+
+        return format;
+    }
+
+    private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22;
+
+    private final StreamConfiguration[] mConfigurations;
+    private final StreamConfigurationDuration[] mDurations;
+
+}
diff --git a/core/java/android/hardware/camera2/TonemapCurve.java b/core/java/android/hardware/camera2/TonemapCurve.java
new file mode 100644
index 0000000..2958ebf
--- /dev/null
+++ b/core/java/android/hardware/camera2/TonemapCurve.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+
+import static com.android.internal.util.Preconditions.*;
+
+import android.graphics.PointF;
+import android.hardware.camera2.utils.HashCodeHelpers;
+
+import java.util.Arrays;
+
+/**
+ * Immutable class for describing a {@code 2 x M x 3} tonemap curve of floats.
+ *
+ * <p>This defines red, green, and blue curves that the {@link CameraDevice} will
+ * use as the tonemapping/contrast/gamma curve when {@link CaptureRequest#TONEMAP_MODE} is
+ * set to {@link CameraMetadata#TONEMAP_MODE_CONTRAST_CURVE}.</p>
+ *
+ * <p>The total number of points {@code (Pin, Pout)} for each color channel can be no more than
+ * {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS}.</p>
+ *
+ * <p>The coordinate system for each point is within the inclusive range
+ * [{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].</p>
+ *
+ * @see CaptureRequest#TONEMAP_CURVE_BLUE
+ * @see CaptureRequest#TONEMAP_CURVE_GREEN
+ * @see CaptureRequest#TONEMAP_CURVE_RED
+ * @see CameraMetadata#TONEMAP_MODE_CONTRAST_CURVE
+ * @see CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS
+ */
+public final class TonemapCurve {
+    /**
+     * Lower bound tonemap value corresponding to pure black for a single color channel.
+     */
+    public static final float LEVEL_BLACK = 0.0f;
+
+    /**
+     * Upper bound tonemap value corresponding to a pure white for a single color channel.
+     */
+    public static final float LEVEL_WHITE = 1.0f;
+
+    /**
+     * Number of elements in a {@code (Pin, Pout)} point;
+     */
+    public static final int POINT_SIZE = 2;
+
+    /**
+     * Index of the red color channel curve.
+     */
+    public static final int CHANNEL_RED = 0;
+    /**
+     * Index of the green color channel curve.
+     */
+    public static final int CHANNEL_GREEN = 1;
+    /**
+     * Index of the blue color channel curve.
+     */
+    public static final int CHANNEL_BLUE = 2;
+
+    /**
+     * Create a new immutable TonemapCurve instance.
+     *
+     * <p>Values are stored as a contiguous {@code (Pin, Pout}) point.</p>
+     *
+     * <p>All parameters may have independent length but should have at most
+     * {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS} * {@value #POINT_SIZE} elements.</p>
+     *
+     * <p>All sub-elements must be in the inclusive range of
+     * [{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].</p>
+     *
+     * <p>This constructor copies the array contents and does not retain ownership of the array.</p>
+     *
+     * @param elements An array of elements whose length is {@code CHANNEL_COUNT * rows * columns}
+     *
+     * @throws IllegalArgumentException
+     *            if the {@code elements} array length is invalid,
+     *            if any of the subelems are not finite
+     * @throws NullPointerException
+     *            if any of the parameters is {@code null}
+     *
+     * @hide
+     */
+    public TonemapCurve(float[] red, float[] green, float[] blue) {
+        // TODO: maxCurvePoints check?
+
+        checkNotNull(red, "red must not be null");
+        checkNotNull(green, "green must not be null");
+        checkNotNull(blue, "blue must not be null");
+
+        checkArgumentArrayLengthDivisibleBy(red, POINT_SIZE, "red");
+        checkArgumentArrayLengthDivisibleBy(green, POINT_SIZE, "green");
+        checkArgumentArrayLengthDivisibleBy(blue, POINT_SIZE, "blue");
+
+        checkArrayElementsInRange(red, LEVEL_BLACK, LEVEL_WHITE, "red");
+        checkArrayElementsInRange(green, LEVEL_BLACK, LEVEL_WHITE, "green");
+        checkArrayElementsInRange(blue, LEVEL_BLACK, LEVEL_WHITE, "blue");
+
+        mRed = Arrays.copyOf(red, red.length);
+        mGreen = Arrays.copyOf(green, green.length);
+        mBlue = Arrays.copyOf(blue, blue.length);
+    }
+
+    private static void checkArgumentArrayLengthDivisibleBy(float[] array,
+            int divisible, String arrayName) {
+        if (array.length % divisible != 0) {
+            throw new IllegalArgumentException(arrayName + " size must be divisible by "
+                    + divisible);
+        }
+    }
+
+    private static int checkArgumentColorChannel(int colorChannel) {
+        switch (colorChannel) {
+            case CHANNEL_RED:
+            case CHANNEL_GREEN:
+            case CHANNEL_BLUE:
+                break;
+            default:
+                throw new IllegalArgumentException("colorChannel out of range");
+        }
+
+        return colorChannel;
+    }
+
+    /**
+     * Get the number of points stored in this tonemap curve for the specified color channel.
+     *
+     * @param colorChannel one of {@link #CHANNEL_RED}, {@link #CHANNEL_GREEN}, {@link #CHANNEL_BLUE}
+     * @return number of points stored in this tonemap for that color's curve (>= 0)
+     *
+     * @throws IllegalArgumentException if {@code colorChannel} was out of range
+     */
+    public int getPointCount(int colorChannel) {
+        checkArgumentColorChannel(colorChannel);
+
+        return getCurve(colorChannel).length / POINT_SIZE;
+    }
+
+    /**
+     * Get the point for a color channel at a specified index.
+     *
+     * <p>The index must be at least 0 but no greater than {@link #getPointCount(int)} for
+     * that {@code colorChannel}.</p>
+     *
+     * <p>All returned coordinates in the point are between the range of
+     * [{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].</p>
+     *
+     * @param colorChannel {@link #CHANNEL_RED}, {@link #CHANNEL_GREEN}, or {@link #CHANNEL_BLUE}
+     * @param index at least 0 but no greater than {@code getPointCount(colorChannel)}
+     * @return the {@code (Pin, Pout)} pair mapping the tone for that index
+     *
+     * @throws IllegalArgumentException if {@code colorChannel} or {@code index} was out of range
+     *
+     * @see #LEVEL_BLACK
+     * @see #LEVEL_WHITE
+     */
+    public PointF getPoint(int colorChannel, int index) {
+        checkArgumentColorChannel(colorChannel);
+        if (index < 0 || index >= getPointCount(colorChannel)) {
+            throw new IllegalArgumentException("index out of range");
+        }
+
+        final float[] curve = getCurve(colorChannel);
+
+        final float pIn = curve[index * POINT_SIZE + OFFSET_POINT_IN];
+        final float pOut = curve[index * POINT_SIZE + OFFSET_POINT_OUT];
+
+        return new PointF(pIn, pOut);
+    }
+
+    /**
+     * Copy the color curve for a single color channel from this tonemap curve into the destination.
+     *
+     * <p>
+     * <!--The output is encoded the same as in the constructor -->
+     * Values are stored as packed {@code (Pin, Pout}) points, and there are a total of
+     * {@link #getPointCount} points for that respective channel.</p>
+     *
+     * <p>All returned coordinates are between the range of
+     * [{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].</p>
+     *
+     * @param destination
+     *          an array big enough to hold at least {@link #getPointCount} {@code *}
+     *          {@link #POINT_SIZE} elements after the {@code offset}
+     * @param offset
+     *          a non-negative offset into the array
+     * @throws NullPointerException
+     *          If {@code destination} was {@code null}
+     * @throws IllegalArgumentException
+     *          If offset was negative
+     * @throws ArrayIndexOutOfBoundsException
+     *          If there's not enough room to write the elements at the specified destination and
+     *          offset.
+     *
+     * @see CaptureRequest#TONEMAP_CURVE_BLUE
+     * @see CaptureRequest#TONEMAP_CURVE_RED
+     * @see CaptureRequest#TONEMAP_CURVE_GREEN
+     * @see #LEVEL_BLACK
+     * @see #LEVEL_WHITE
+     */
+    public void copyColorCurve(int colorChannel, float[] destination,
+            int offset) {
+        checkArgumentNonnegative(offset, "offset must not be negative");
+        checkNotNull(destination, "destination must not be null");
+
+        if (destination.length + offset < getPointCount(colorChannel) * POINT_SIZE) {
+            throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
+        }
+
+        float[] curve = getCurve(colorChannel);
+        System.arraycopy(curve, /*srcPos*/0, destination, offset, curve.length);
+    }
+
+    /**
+     * Check if this TonemapCurve is equal to another TonemapCurve.
+     *
+     * <p>Two matrices are equal if and only if all of their elements are
+     * {@link Object#equals equal}.</p>
+     *
+     * @return {@code true} if the objects were equal, {@code false} otherwise
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof TonemapCurve) {
+            final TonemapCurve other = (TonemapCurve) obj;
+            return Arrays.equals(mRed, other.mRed) &&
+                    Arrays.equals(mGreen, other.mGreen) &&
+                    Arrays.equals(mBlue, other.mBlue);
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        if (mHashCalculated) {
+            // Avoid re-calculating hash. Data is immutable so this is both legal and faster.
+            return mHashCode;
+        }
+
+        mHashCode = HashCodeHelpers.hashCode(mRed, mGreen, mBlue);
+        mHashCalculated = true;
+
+        return mHashCode;
+    }
+
+    private float[] getCurve(int colorChannel) {
+        switch (colorChannel) {
+            case CHANNEL_RED:
+                return mRed;
+            case CHANNEL_GREEN:
+                return mGreen;
+            case CHANNEL_BLUE:
+                return mBlue;
+            default:
+                throw new AssertionError("colorChannel out of range");
+        }
+    }
+
+    private final static int OFFSET_POINT_IN = 0;
+    private final static int OFFSET_POINT_OUT = 1;
+
+    private final float[] mRed;
+    private final float[] mGreen;
+    private final float[] mBlue;
+
+    private int mHashCode;
+    private boolean mHashCalculated = false;
+};
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index 40a7905..988f8f9 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -647,7 +647,7 @@
                  * should have arrived. The following line checks whether this holds.
                  */
                 if (frameNumber != mCompletedFrameNumber + 1) {
-                    throw new AssertionError(String.format(
+                    Log.e(TAG, String.format(
                             "result frame number %d comes out of order, should be %d + 1",
                             frameNumber, mCompletedFrameNumber));
                 }
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index c5e5753..9a06e97 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -23,16 +23,33 @@
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.Face;
-import android.hardware.camera2.Rational;
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.marshal.MarshalRegistry;
+import android.hardware.camera2.marshal.impl.MarshalQueryableArray;
+import android.hardware.camera2.marshal.impl.MarshalQueryableBoolean;
+import android.hardware.camera2.marshal.impl.MarshalQueryableColorSpaceTransform;
+import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
+import android.hardware.camera2.marshal.impl.MarshalQueryableMeteringRectangle;
+import android.hardware.camera2.marshal.impl.MarshalQueryableNativeByteToInteger;
+import android.hardware.camera2.marshal.impl.MarshalQueryableParcelable;
+import android.hardware.camera2.marshal.impl.MarshalQueryablePrimitive;
+import android.hardware.camera2.marshal.impl.MarshalQueryableRange;
+import android.hardware.camera2.marshal.impl.MarshalQueryableRect;
+import android.hardware.camera2.marshal.impl.MarshalQueryableReprocessFormatsMap;
+import android.hardware.camera2.marshal.impl.MarshalQueryableRggbChannelVector;
+import android.hardware.camera2.marshal.impl.MarshalQueryableSize;
+import android.hardware.camera2.marshal.impl.MarshalQueryableSizeF;
+import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration;
+import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration;
+import android.hardware.camera2.marshal.impl.MarshalQueryableString;
 import android.os.Parcelable;
 import android.os.Parcel;
 import android.util.Log;
 
-import java.lang.reflect.Array;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
-import java.util.HashMap;
 
 /**
  * Implementation of camera metadata marshal/unmarshal across Binder to
@@ -89,7 +106,6 @@
         nativeWriteToParcel(dest);
     }
 
-    @SuppressWarnings("unchecked")
     @Override
     public <T> T get(Key<T> key) {
         T value = getOverride(key);
@@ -169,275 +185,6 @@
         mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final
     }
 
-    private static int getTypeSize(int nativeType) {
-        switch(nativeType) {
-            case TYPE_BYTE:
-                return 1;
-            case TYPE_INT32:
-            case TYPE_FLOAT:
-                return 4;
-            case TYPE_INT64:
-            case TYPE_DOUBLE:
-            case TYPE_RATIONAL:
-                return 8;
-        }
-
-        throw new UnsupportedOperationException("Unknown type, can't get size "
-                + nativeType);
-    }
-
-    private static Class<?> getExpectedType(int nativeType) {
-        switch(nativeType) {
-            case TYPE_BYTE:
-                return Byte.TYPE;
-            case TYPE_INT32:
-                return Integer.TYPE;
-            case TYPE_FLOAT:
-                return Float.TYPE;
-            case TYPE_INT64:
-                return Long.TYPE;
-            case TYPE_DOUBLE:
-                return Double.TYPE;
-            case TYPE_RATIONAL:
-                return Rational.class;
-        }
-
-        throw new UnsupportedOperationException("Unknown type, can't map to Java type "
-                + nativeType);
-    }
-
-    @SuppressWarnings("unchecked")
-    private static <T> int packSingleNative(T value, ByteBuffer buffer, Class<T> type,
-            int nativeType, boolean sizeOnly) {
-
-        if (!sizeOnly) {
-            /**
-             * Rewrite types when the native type doesn't match the managed type
-             *  - Boolean -> Byte
-             *  - Integer -> Byte
-             */
-
-            if (nativeType == TYPE_BYTE && type == Boolean.TYPE) {
-                // Since a boolean can't be cast to byte, and we don't want to use putBoolean
-                boolean asBool = (Boolean) value;
-                byte asByte = (byte) (asBool ? 1 : 0);
-                value = (T) (Byte) asByte;
-            } else if (nativeType == TYPE_BYTE && type == Integer.TYPE) {
-                int asInt = (Integer) value;
-                byte asByte = (byte) asInt;
-                value = (T) (Byte) asByte;
-            } else if (type != getExpectedType(nativeType)) {
-                throw new UnsupportedOperationException("Tried to pack a type of " + type +
-                        " but we expected the type to be " + getExpectedType(nativeType));
-            }
-
-            if (nativeType == TYPE_BYTE) {
-                buffer.put((Byte) value);
-            } else if (nativeType == TYPE_INT32) {
-                buffer.putInt((Integer) value);
-            } else if (nativeType == TYPE_FLOAT) {
-                buffer.putFloat((Float) value);
-            } else if (nativeType == TYPE_INT64) {
-                buffer.putLong((Long) value);
-            } else if (nativeType == TYPE_DOUBLE) {
-                buffer.putDouble((Double) value);
-            } else if (nativeType == TYPE_RATIONAL) {
-                Rational r = (Rational) value;
-                buffer.putInt(r.getNumerator());
-                buffer.putInt(r.getDenominator());
-            }
-
-        }
-
-        return getTypeSize(nativeType);
-    }
-
-    @SuppressWarnings({"unchecked", "rawtypes"})
-    private static <T> int packSingle(T value, ByteBuffer buffer, Class<T> type, int nativeType,
-            boolean sizeOnly) {
-
-        int size = 0;
-
-        if (type.isPrimitive() || type == Rational.class) {
-            size = packSingleNative(value, buffer, type, nativeType, sizeOnly);
-        } else if (type.isEnum()) {
-            size = packEnum((Enum)value, buffer, (Class<Enum>)type, nativeType, sizeOnly);
-        } else if (type.isArray()) {
-            size = packArray(value, buffer, type, nativeType, sizeOnly);
-        } else {
-            size = packClass(value, buffer, type, nativeType, sizeOnly);
-        }
-
-        return size;
-    }
-
-    private static <T extends Enum<T>> int packEnum(T value, ByteBuffer buffer, Class<T> type,
-            int nativeType, boolean sizeOnly) {
-
-        // TODO: add support for enums with their own values.
-        return packSingleNative(getEnumValue(value), buffer, Integer.TYPE, nativeType, sizeOnly);
-    }
-
-    @SuppressWarnings("unchecked")
-    private static <T> int packClass(T value, ByteBuffer buffer, Class<T> type, int nativeType,
-            boolean sizeOnly) {
-
-        MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType);
-        if (marshaler == null) {
-            throw new IllegalArgumentException(String.format("Unknown Key type: %s", type));
-        }
-
-        return marshaler.marshal(value, buffer, nativeType, sizeOnly);
-    }
-
-    private static <T> int packArray(T value, ByteBuffer buffer, Class<T> type, int nativeType,
-            boolean sizeOnly) {
-
-        int size = 0;
-        int arrayLength = Array.getLength(value);
-
-        @SuppressWarnings("unchecked")
-        Class<Object> componentType = (Class<Object>)type.getComponentType();
-
-        for (int i = 0; i < arrayLength; ++i) {
-            size += packSingle(Array.get(value, i), buffer, componentType, nativeType, sizeOnly);
-        }
-
-        return size;
-    }
-
-    @SuppressWarnings("unchecked")
-    private static <T> T unpackSingleNative(ByteBuffer buffer, Class<T> type, int nativeType) {
-
-        T val;
-
-        if (nativeType == TYPE_BYTE) {
-            val = (T) (Byte) buffer.get();
-        } else if (nativeType == TYPE_INT32) {
-            val = (T) (Integer) buffer.getInt();
-        } else if (nativeType == TYPE_FLOAT) {
-            val = (T) (Float) buffer.getFloat();
-        } else if (nativeType == TYPE_INT64) {
-            val = (T) (Long) buffer.getLong();
-        } else if (nativeType == TYPE_DOUBLE) {
-            val = (T) (Double) buffer.getDouble();
-        } else if (nativeType == TYPE_RATIONAL) {
-            val = (T) new Rational(buffer.getInt(), buffer.getInt());
-        } else {
-            throw new UnsupportedOperationException("Unknown type, can't unpack a native type "
-                + nativeType);
-        }
-
-        /**
-         * Rewrite types when the native type doesn't match the managed type
-         *  - Byte -> Boolean
-         *  - Byte -> Integer
-         */
-
-        if (nativeType == TYPE_BYTE && type == Boolean.TYPE) {
-            // Since a boolean can't be cast to byte, and we don't want to use getBoolean
-            byte asByte = (Byte) val;
-            boolean asBool = asByte != 0;
-            val = (T) (Boolean) asBool;
-        } else if (nativeType == TYPE_BYTE && type == Integer.TYPE) {
-            byte asByte = (Byte) val;
-            int asInt = asByte;
-            val = (T) (Integer) asInt;
-        } else if (type != getExpectedType(nativeType)) {
-            throw new UnsupportedOperationException("Tried to unpack a type of " + type +
-                    " but we expected the type to be " + getExpectedType(nativeType));
-        }
-
-        return val;
-    }
-
-    @SuppressWarnings({"unchecked", "rawtypes"})
-    private static <T> T unpackSingle(ByteBuffer buffer, Class<T> type, int nativeType) {
-
-        if (type.isPrimitive() || type == Rational.class) {
-            return unpackSingleNative(buffer, type, nativeType);
-        }
-
-        if (type.isEnum()) {
-            return (T) unpackEnum(buffer, (Class<Enum>)type, nativeType);
-        }
-
-        if (type.isArray()) {
-            return unpackArray(buffer, type, nativeType);
-        }
-
-        T instance = unpackClass(buffer, type, nativeType);
-
-        return instance;
-    }
-
-    private static <T extends Enum<T>> T unpackEnum(ByteBuffer buffer, Class<T> type,
-            int nativeType) {
-        int ordinal = unpackSingleNative(buffer, Integer.TYPE, nativeType);
-        return getEnumFromValue(type, ordinal);
-    }
-
-    private static <T> T unpackClass(ByteBuffer buffer, Class<T> type, int nativeType) {
-
-        MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType);
-        if (marshaler == null) {
-            throw new IllegalArgumentException("Unknown class type: " + type);
-        }
-
-        return marshaler.unmarshal(buffer, nativeType);
-    }
-
-    @SuppressWarnings("unchecked")
-    private static <T> T unpackArray(ByteBuffer buffer, Class<T> type, int nativeType) {
-
-        Class<?> componentType = type.getComponentType();
-        Object array;
-
-        int elementSize = getTypeSize(nativeType);
-
-        MetadataMarshalClass<?> marshaler = getMarshaler(componentType, nativeType);
-        if (marshaler != null) {
-            elementSize = marshaler.getNativeSize(nativeType);
-        }
-
-        if (elementSize != MetadataMarshalClass.NATIVE_SIZE_DYNAMIC) {
-            int remaining = buffer.remaining();
-            int arraySize = remaining / elementSize;
-
-            if (VERBOSE) {
-                Log.v(TAG,
-                        String.format(
-                            "Attempting to unpack array (count = %d, element size = %d, bytes " +
-                            "remaining = %d) for type %s",
-                            arraySize, elementSize, remaining, type));
-            }
-
-            array = Array.newInstance(componentType, arraySize);
-            for (int i = 0; i < arraySize; ++i) {
-               Object elem = unpackSingle(buffer, componentType, nativeType);
-               Array.set(array, i, elem);
-            }
-        } else {
-            // Dynamic size, use an array list.
-            ArrayList<Object> arrayList = new ArrayList<Object>();
-
-            int primitiveSize = getTypeSize(nativeType);
-            while (buffer.remaining() >= primitiveSize) {
-                Object elem = unpackSingle(buffer, componentType, nativeType);
-                arrayList.add(elem);
-            }
-
-            array = arrayList.toArray((T[]) Array.newInstance(componentType, 0));
-        }
-
-        if (buffer.remaining() != 0) {
-            Log.e(TAG, "Trailing bytes (" + buffer.remaining() + ") left over after unpacking "
-                    + type);
-        }
-
-        return (T) array;
-    }
-
     private <T> T getBase(Key<T> key) {
         int tag = key.getTag();
         byte[] values = readValues(tag);
@@ -445,10 +192,9 @@
             return null;
         }
 
-        int nativeType = getNativeType(tag);
-
+        Marshaler<T> marshaler = getMarshalerForKey(key);
         ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
-        return unpackSingle(buffer, key.getType(), nativeType);
+        return marshaler.unmarshal(buffer);
     }
 
     // Need overwrite some metadata that has different definitions between native
@@ -632,19 +378,19 @@
         int tag = key.getTag();
 
         if (value == null) {
-            writeValues(tag, null);
+            // Erase the entry
+            writeValues(tag, /*src*/null);
             return;
-        }
+        } // else update the entry to a new value
 
-        int nativeType = getNativeType(tag);
-
-        int size = packSingle(value, null, key.getType(), nativeType, /* sizeOnly */true);
+        Marshaler<T> marshaler = getMarshalerForKey(key);
+        int size = marshaler.calculateMarshalSize(value);
 
         // TODO: Optimization. Cache the byte[] and reuse if the size is big enough.
         byte[] values = new byte[size];
 
         ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
-        packSingle(value, buffer, key.getType(), nativeType, /*sizeOnly*/false);
+        marshaler.marshal(value, buffer);
 
         writeValues(tag, values);
     }
@@ -870,125 +616,64 @@
         }
     }
 
-    private static final HashMap<Class<? extends Enum>, int[]> sEnumValues =
-            new HashMap<Class<? extends Enum>, int[]>();
     /**
-     * Register a non-sequential set of values to be used with the pack/unpack functions.
-     * This enables get/set to correctly marshal the enum into a value that is C-compatible.
+     * Get the marshaler compatible with the {@code key} and type {@code T}.
      *
-     * @param enumType The class for an enum
-     * @param values A list of values mapping to the ordinals of the enum
-     *
-     * @hide
+     * @throws UnsupportedOperationException
+     *          if the native/managed type combination for {@code key} is not supported
      */
-    public static <T extends Enum<T>> void registerEnumValues(Class<T> enumType, int[] values) {
-        if (enumType.getEnumConstants().length != values.length) {
-            throw new IllegalArgumentException(
-                    "Expected values array to be the same size as the enumTypes values "
-                            + values.length + " for type " + enumType);
-        }
-        if (VERBOSE) {
-            Log.v(TAG, "Registered enum values for type " + enumType + " values");
-        }
-
-        sEnumValues.put(enumType, values);
+    private static <T> Marshaler<T> getMarshalerForKey(Key<T> key) {
+        return MarshalRegistry.getMarshaler(key.getTypeReference(),
+                getNativeType(key.getTag()));
     }
 
-    /**
-     * Get the numeric value from an enum. This is usually the same as the ordinal value for
-     * enums that have fully sequential values, although for C-style enums the range of values
-     * may not map 1:1.
-     *
-     * @param enumValue Enum instance
-     * @return Int guaranteed to be ABI-compatible with the C enum equivalent
-     */
-    private static <T extends Enum<T>> int getEnumValue(T enumValue) {
-        int[] values;
-        values = sEnumValues.get(enumValue.getClass());
-
-        int ordinal = enumValue.ordinal();
-        if (values != null) {
-            return values[ordinal];
-        }
-
-        return ordinal;
-    }
-
-    /**
-     * Finds the enum corresponding to it's numeric value. Opposite of {@link #getEnumValue} method.
-     *
-     * @param enumType Class of the enum we want to find
-     * @param value The numeric value of the enum
-     * @return An instance of the enum
-     */
-    private static <T extends Enum<T>> T getEnumFromValue(Class<T> enumType, int value) {
-        int ordinal;
-
-        int[] registeredValues = sEnumValues.get(enumType);
-        if (registeredValues != null) {
-            ordinal = -1;
-
-            for (int i = 0; i < registeredValues.length; ++i) {
-                if (registeredValues[i] == value) {
-                    ordinal = i;
-                    break;
-                }
-            }
-        } else {
-            ordinal = value;
-        }
-
-        T[] values = enumType.getEnumConstants();
-
-        if (ordinal < 0 || ordinal >= values.length) {
-            throw new IllegalArgumentException(
-                    String.format(
-                            "Argument 'value' (%d) was not a valid enum value for type %s "
-                                    + "(registered? %b)",
-                            value,
-                            enumType, (registeredValues != null)));
-        }
-
-        return values[ordinal];
-    }
-
-    static HashMap<Class<?>, MetadataMarshalClass<?>> sMarshalerMap = new
-            HashMap<Class<?>, MetadataMarshalClass<?>>();
-
-    private static <T> void registerMarshaler(MetadataMarshalClass<T> marshaler) {
-        sMarshalerMap.put(marshaler.getMarshalingClass(), marshaler);
-    }
-
-    @SuppressWarnings("unchecked")
-    private static <T> MetadataMarshalClass<T> getMarshaler(Class<T> type, int nativeType) {
-        MetadataMarshalClass<T> marshaler = (MetadataMarshalClass<T>) sMarshalerMap.get(type);
-
-        if (marshaler != null && !marshaler.isNativeTypeSupported(nativeType)) {
-            throw new UnsupportedOperationException("Unsupported type " + nativeType +
-                    " to be marshalled to/from a " + type);
-        }
-
-        return marshaler;
-    }
-
-    /**
-     * We use a class initializer to allow the native code to cache some field offsets
-     */
-    static {
-        nativeClassInit();
-
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    private static void registerAllMarshalers() {
         if (VERBOSE) {
             Log.v(TAG, "Shall register metadata marshalers");
         }
 
-        // load built-in marshallers
-        registerMarshaler(new MetadataMarshalRect());
-        registerMarshaler(new MetadataMarshalSize());
-        registerMarshaler(new MetadataMarshalString());
+        MarshalQueryable[] queryList = new MarshalQueryable[] {
+                // marshalers for standard types
+                new MarshalQueryablePrimitive(),
+                new MarshalQueryableEnum(),
+                new MarshalQueryableArray(),
 
+                // pseudo standard types, that expand/narrow the native type into a managed type
+                new MarshalQueryableBoolean(),
+                new MarshalQueryableNativeByteToInteger(),
+
+                // marshalers for custom types
+                new MarshalQueryableRect(),
+                new MarshalQueryableSize(),
+                new MarshalQueryableSizeF(),
+                new MarshalQueryableString(),
+                new MarshalQueryableReprocessFormatsMap(),
+                new MarshalQueryableRange(),
+                new MarshalQueryableMeteringRectangle(),
+                new MarshalQueryableColorSpaceTransform(),
+                new MarshalQueryableStreamConfiguration(),
+                new MarshalQueryableStreamConfigurationDuration(),
+                new MarshalQueryableRggbChannelVector(),
+
+                // generic parcelable marshaler (MUST BE LAST since it has lowest priority)
+                new MarshalQueryableParcelable(),
+        };
+
+        for (MarshalQueryable query : queryList) {
+            MarshalRegistry.registerMarshalQueryable(query);
+        }
         if (VERBOSE) {
             Log.v(TAG, "Registered metadata marshalers");
         }
     }
 
+    static {
+        /*
+         * We use a class initializer to allow the native code to cache some field offsets
+         */
+        nativeClassInit();
+        registerAllMarshalers();
+    }
+
 }
diff --git a/core/java/android/hardware/camera2/impl/MetadataMarshalClass.java b/core/java/android/hardware/camera2/impl/MetadataMarshalClass.java
deleted file mode 100644
index 6d224ef..0000000
--- a/core/java/android/hardware/camera2/impl/MetadataMarshalClass.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.impl;
-
-import java.nio.ByteBuffer;
-
-public interface MetadataMarshalClass<T> {
-
-    /**
-     * Marshal the specified object instance (value) into a byte buffer.
-     *
-     * @param value the value of type T that we wish to write into the byte buffer
-     * @param buffer the byte buffer into which the marshalled object will be written
-     * @param nativeType the native type, e.g.
-     *        {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
-     *        Guaranteed to be one for which isNativeTypeSupported returns true.
-     * @param sizeOnly if this is true, don't write to the byte buffer. calculate the size only.
-     * @return the size that needs to be written to the byte buffer
-     */
-    int marshal(T value, ByteBuffer buffer, int nativeType, boolean sizeOnly);
-
-    /**
-     * Unmarshal a new object instance from the byte buffer.
-     * @param buffer the byte buffer, from which we will read the object
-     * @param nativeType the native type, e.g.
-     *        {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
-     *        Guaranteed to be one for which isNativeTypeSupported returns true.
-     * @return a new instance of type T read from the byte buffer
-     */
-    T unmarshal(ByteBuffer buffer, int nativeType);
-
-    Class<T> getMarshalingClass();
-
-    /**
-     * Determines whether or not this marshaller supports this native type. Most marshallers
-     * will are likely to only support one type.
-     *
-     * @param nativeType the native type, e.g.
-     *        {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
-     * @return true if it supports, false otherwise
-     */
-    boolean isNativeTypeSupported(int nativeType);
-
-    public static int NATIVE_SIZE_DYNAMIC = -1;
-
-    /**
-     * How many bytes T will take up if marshalled to/from nativeType
-     * @param nativeType the native type, e.g.
-     *        {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
-     * @return a size in bytes, or NATIVE_SIZE_DYNAMIC if the size is dynamic
-     */
-    int getNativeSize(int nativeType);
-}
diff --git a/core/java/android/hardware/camera2/impl/MetadataMarshalRect.java b/core/java/android/hardware/camera2/impl/MetadataMarshalRect.java
deleted file mode 100644
index ab72c4f..0000000
--- a/core/java/android/hardware/camera2/impl/MetadataMarshalRect.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.camera2.impl;
-
-import android.graphics.Rect;
-
-import java.nio.ByteBuffer;
-
-public class MetadataMarshalRect implements MetadataMarshalClass<Rect> {
-    private static final int SIZE = 16;
-
-    @Override
-    public int marshal(Rect value, ByteBuffer buffer, int nativeType, boolean sizeOnly) {
-        if (sizeOnly) {
-            return SIZE;
-        }
-
-        buffer.putInt(value.left);
-        buffer.putInt(value.top);
-        buffer.putInt(value.width());
-        buffer.putInt(value.height());
-
-        return SIZE;
-    }
-
-    @Override
-    public Rect unmarshal(ByteBuffer buffer, int nativeType) {
-
-        int left = buffer.getInt();
-        int top = buffer.getInt();
-        int width = buffer.getInt();
-        int height = buffer.getInt();
-
-        int right = left + width;
-        int bottom = top + height;
-
-        return new Rect(left, top, right, bottom);
-    }
-
-    @Override
-    public Class<Rect> getMarshalingClass() {
-        return Rect.class;
-    }
-
-    @Override
-    public boolean isNativeTypeSupported(int nativeType) {
-        return nativeType == CameraMetadataNative.TYPE_INT32;
-    }
-
-    @Override
-    public int getNativeSize(int nativeType) {
-        return SIZE;
-    }
-}
diff --git a/core/java/android/hardware/camera2/impl/MetadataMarshalSize.java b/core/java/android/hardware/camera2/impl/MetadataMarshalSize.java
deleted file mode 100644
index e8143e0..0000000
--- a/core/java/android/hardware/camera2/impl/MetadataMarshalSize.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.camera2.impl;
-
-import android.hardware.camera2.Size;
-
-import java.nio.ByteBuffer;
-
-public class MetadataMarshalSize implements MetadataMarshalClass<Size> {
-
-    private static final int SIZE = 8;
-
-    @Override
-    public int marshal(Size value, ByteBuffer buffer, int nativeType, boolean sizeOnly) {
-        if (sizeOnly) {
-            return SIZE;
-        }
-
-        buffer.putInt(value.getWidth());
-        buffer.putInt(value.getHeight());
-
-        return SIZE;
-    }
-
-    @Override
-    public Size unmarshal(ByteBuffer buffer, int nativeType) {
-        int width = buffer.getInt();
-        int height = buffer.getInt();
-
-        return new Size(width, height);
-    }
-
-    @Override
-    public Class<Size> getMarshalingClass() {
-        return Size.class;
-    }
-
-    @Override
-    public boolean isNativeTypeSupported(int nativeType) {
-        return nativeType == CameraMetadataNative.TYPE_INT32;
-    }
-
-    @Override
-    public int getNativeSize(int nativeType) {
-        return SIZE;
-    }
-}
diff --git a/core/java/android/hardware/camera2/impl/MetadataMarshalString.java b/core/java/android/hardware/camera2/impl/MetadataMarshalString.java
deleted file mode 100644
index b61b8d3..0000000
--- a/core/java/android/hardware/camera2/impl/MetadataMarshalString.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.camera2.impl;
-
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-
-public class MetadataMarshalString implements MetadataMarshalClass<String> {
-
-    private static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
-
-    @Override
-    public int marshal(String value, ByteBuffer buffer, int nativeType, boolean sizeOnly) {
-        byte[] arr = value.getBytes(UTF8_CHARSET);
-
-        if (!sizeOnly) {
-            buffer.put(arr);
-            buffer.put((byte)0); // metadata strings are NULL-terminated
-        }
-
-        return arr.length + 1;
-    }
-
-    @Override
-    public String unmarshal(ByteBuffer buffer, int nativeType) {
-
-        buffer.mark(); // save the current position
-
-        boolean foundNull = false;
-        int stringLength = 0;
-        while (buffer.hasRemaining()) {
-            if (buffer.get() == (byte)0) {
-                foundNull = true;
-                break;
-            }
-
-            stringLength++;
-        }
-        if (!foundNull) {
-            throw new IllegalArgumentException("Strings must be null-terminated");
-        }
-
-        buffer.reset(); // go back to the previously marked position
-
-        byte[] strBytes = new byte[stringLength + 1];
-        buffer.get(strBytes, /*dstOffset*/0, stringLength + 1); // including null character
-
-        // not including null character
-        return new String(strBytes, /*offset*/0, stringLength, UTF8_CHARSET);
-    }
-
-    @Override
-    public Class<String> getMarshalingClass() {
-        return String.class;
-    }
-
-    @Override
-    public boolean isNativeTypeSupported(int nativeType) {
-        return nativeType == CameraMetadataNative.TYPE_BYTE;
-    }
-
-    @Override
-    public int getNativeSize(int nativeType) {
-        return NATIVE_SIZE_DYNAMIC;
-    }
-}
diff --git a/core/java/android/hardware/camera2/marshal/MarshalHelpers.java b/core/java/android/hardware/camera2/marshal/MarshalHelpers.java
new file mode 100644
index 0000000..fd72ee2
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/MarshalHelpers.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.marshal;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static com.android.internal.util.Preconditions.*;
+
+import android.hardware.camera2.Rational;
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+/**
+ * Static functions in order to help implementing various marshaler functionality.
+ *
+ * <p>The intention is to statically import everything from this file into another file when
+ * implementing a new marshaler (or marshal queryable).</p>
+ *
+ * <p>The helpers are centered around providing primitive knowledge of the native types,
+ * such as the native size, the managed class wrappers, and various precondition checks.</p>
+ */
+public final class MarshalHelpers {
+
+    public static final int SIZEOF_BYTE = 1;
+    public static final int SIZEOF_INT32 = Integer.SIZE / Byte.SIZE;
+    public static final int SIZEOF_INT64 = Long.SIZE / Byte.SIZE;
+    public static final int SIZEOF_FLOAT = Float.SIZE / Byte.SIZE;
+    public static final int SIZEOF_DOUBLE = Double.SIZE / Byte.SIZE;
+    public static final int SIZEOF_RATIONAL = SIZEOF_INT32 * 2;
+
+    /**
+     * Get the size in bytes for the native camera metadata type.
+     *
+     * <p>This used to determine how many bytes it would take to encode/decode a single value
+     * of that {@link nativeType}.</p>
+     *
+     * @param nativeType the native type, e.g.
+     *        {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
+     * @return size in bytes >= 1
+     *
+     * @throws UnsupportedOperationException if nativeType was not one of the built-in types
+     */
+    public static int getPrimitiveTypeSize(int nativeType) {
+        switch (nativeType) {
+            case TYPE_BYTE:
+                return SIZEOF_BYTE;
+            case TYPE_INT32:
+                return SIZEOF_INT32;
+            case TYPE_FLOAT:
+                return SIZEOF_FLOAT;
+            case TYPE_INT64:
+                return SIZEOF_INT64;
+            case TYPE_DOUBLE:
+                return SIZEOF_DOUBLE;
+            case TYPE_RATIONAL:
+                return SIZEOF_RATIONAL;
+        }
+
+        throw new UnsupportedOperationException("Unknown type, can't get size for "
+                + nativeType);
+    }
+
+
+    /**
+     * Ensure that the {@code klass} is one of the metadata-primitive classes.
+     *
+     * @param klass a non-{@code null} reference
+     * @return {@code klass} instance
+     *
+     * @throws UnsupportedOperationException if klass was not one of the built-in classes
+     * @throws NullPointerException if klass was null
+     *
+     * @see #isPrimitiveClass
+     */
+    public static <T> Class<T> checkPrimitiveClass(Class<T> klass) {
+        checkNotNull(klass, "klass must not be null");
+
+        if (isPrimitiveClass(klass)) {
+            return klass;
+        }
+
+        throw new UnsupportedOperationException("Unsupported class '" + klass +
+                "'; expected a metadata primitive class");
+    }
+
+    /**
+     * Checks whether or not {@code klass} is one of the metadata-primitive classes.
+     *
+     * <p>The following types (whether boxed or unboxed) are considered primitive:
+     * <ul>
+     * <li>byte
+     * <li>int
+     * <li>float
+     * <li>double
+     * <li>Rational
+     * </ul>
+     * </p>
+     *
+     * <p>This doesn't strictly follow the java understanding of primitive since
+     * boxed objects are included, Rational is included, and other types such as char and
+     * short are not included.</p>
+     *
+     * @param klass a {@link Class} instance; using {@code null} will return {@code false}
+     * @return {@code true} if primitive, {@code false} otherwise
+     */
+    public static <T> boolean isPrimitiveClass(Class<T> klass) {
+        if (klass == null) {
+            return false;
+        }
+
+        if (klass == byte.class || klass == Byte.class) {
+            return true;
+        } else if (klass == int.class || klass == Integer.class) {
+            return true;
+        } else if (klass == float.class || klass == Float.class) {
+            return true;
+        } else if (klass == long.class || klass == Long.class) {
+            return true;
+        } else if (klass == double.class || klass == Double.class) {
+            return true;
+        } else if (klass == Rational.class) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Wrap {@code klass} with its wrapper variant if it was a {@code Class} corresponding
+     * to a Java primitive.
+     *
+     * <p>Non-primitive classes are passed through as-is.</p>
+     *
+     * <p>For example, for a primitive {@code int.class => Integer.class},
+     * but for a non-primitive {@code Rational.class => Rational.class}.</p>
+     *
+     * @param klass a {@code Class} reference
+     *
+     * @return wrapped class object, or same class object if non-primitive
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Class<T> wrapClassIfPrimitive(Class<T> klass) {
+        if (klass == byte.class) {
+            return (Class<T>)Byte.class;
+        } else if (klass == int.class) {
+            return (Class<T>)Integer.class;
+        } else if (klass == float.class) {
+            return (Class<T>)Float.class;
+        } else if (klass == long.class) {
+            return (Class<T>)Long.class;
+        } else if (klass == double.class) {
+            return (Class<T>)Double.class;
+        }
+
+        return klass;
+    }
+
+    /**
+     * Return a human-readable representation of the {@code nativeType}, e.g. "TYPE_INT32"
+     *
+     * <p>Out-of-range values return a string with "UNKNOWN" as the prefix.</p>
+     *
+     * @param nativeType the native type
+     *
+     * @return human readable type name
+     */
+    public static String toStringNativeType(int nativeType) {
+        switch (nativeType) {
+            case TYPE_BYTE:
+                return "TYPE_BYTE";
+            case TYPE_INT32:
+                return "TYPE_INT32";
+            case TYPE_FLOAT:
+                return "TYPE_FLOAT";
+            case TYPE_INT64:
+                return "TYPE_INT64";
+            case TYPE_DOUBLE:
+                return "TYPE_DOUBLE";
+            case TYPE_RATIONAL:
+                return "TYPE_RATIONAL";
+        }
+
+        return "UNKNOWN(" + nativeType + ")";
+    }
+
+    /**
+     * Ensure that the {@code nativeType} is one of the native types supported
+     * by {@link CameraMetadataNative}.
+     *
+     * @param nativeType the native type
+     *
+     * @return the native type
+     *
+     * @throws UnsupportedOperationException if the native type was invalid
+     */
+    public static int checkNativeType(int nativeType) {
+        switch (nativeType) {
+            case TYPE_BYTE:
+            case TYPE_INT32:
+            case TYPE_FLOAT:
+            case TYPE_INT64:
+            case TYPE_DOUBLE:
+            case TYPE_RATIONAL:
+                return nativeType;
+        }
+
+        throw new UnsupportedOperationException("Unknown nativeType " + nativeType);
+    }
+
+    /**
+     * Ensure that the expected and actual native types are equal.
+     *
+     * @param expectedNativeType the expected native type
+     * @param actualNativeType the actual native type
+     * @return the actual native type
+     *
+     * @throws UnsupportedOperationException if the types are not equal
+     */
+    public static int checkNativeTypeEquals(int expectedNativeType, int actualNativeType) {
+        if (expectedNativeType != actualNativeType) {
+            throw new UnsupportedOperationException(
+                    String.format("Expected native type %d, but got %d",
+                            expectedNativeType, actualNativeType));
+        }
+
+        return actualNativeType;
+    }
+
+    private MarshalHelpers() {
+        throw new AssertionError();
+    }
+}
diff --git a/core/java/android/hardware/camera2/marshal/MarshalQueryable.java b/core/java/android/hardware/camera2/marshal/MarshalQueryable.java
new file mode 100644
index 0000000..35fed1f
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/MarshalQueryable.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal;
+
+import android.hardware.camera2.utils.TypeReference;
+
+/**
+ * Query if a marshaler can marshal to/from a particular native and managed type; if it supports
+ * the combination, allow creating a marshaler instance to do the serialization.
+ *
+ * <p>Not all queryable instances will support exactly one combination. Some, such as the
+ * primitive queryable will support all primitive to/from managed mappings (as long as they are
+ * 1:1). Others, such as the rectangle queryable will only support integer to rectangle mappings.
+ * </p>
+ *
+ * <p>Yet some others are codependent on other queryables; e.g. array queryables might only support
+ * a type map for {@code T[]} if another queryable exists with support for the component type
+ * {@code T}.</p>
+ */
+public interface MarshalQueryable<T> {
+    /**
+     * Create a marshaler between the selected managed and native type.
+     *
+     * <p>This marshaler instance is only good for that specific type mapping; and will refuse
+     * to map other managed types, other native types, or an other combination that isn't
+     * this exact one.</p>
+     *
+     * @param managedType a managed type reference
+     * @param nativeType the native type, e.g.
+     *          {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
+     * @return
+     *
+     * @throws UnsupportedOperationException
+     *          if {@link #isTypeMappingSupported} returns {@code false}
+     */
+    public Marshaler<T> createMarshaler(
+            TypeReference<T> managedType, int nativeType);
+
+    /**
+     * Determine whether or not this query marshal is able to create a marshaler that will
+     * support the managed type and native type mapping.
+     *
+     * <p>If this returns {@code true}, then a marshaler can be instantiated by
+     * {@link #createMarshaler} that will marshal data to/from the native type
+     * from/to the managed type.</p>
+     *
+     * <p>Most marshalers are likely to only support one type map.</p>
+     */
+    public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType);
+}
diff --git a/core/java/android/hardware/camera2/marshal/MarshalRegistry.java b/core/java/android/hardware/camera2/marshal/MarshalRegistry.java
new file mode 100644
index 0000000..92d9057
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/MarshalRegistry.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.marshal;
+
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.utils.TypeReference;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Registry of supported marshalers; add new query-able marshalers or lookup existing ones.</p>
+ */
+public class MarshalRegistry {
+
+    /**
+     * Register a marshal queryable for the managed type {@code T}.
+     *
+     * <p>Multiple marshal queryables for the same managed type {@code T} may be registered;
+     * this is desirable if they support different native types (e.g. marshaler 1 supports
+     * {@code Integer <-> TYPE_INT32}, marshaler 2 supports {@code Integer <-> TYPE_BYTE}.</p>
+     *
+     * @param queryable a non-{@code null} marshal queryable that supports marshaling {@code T}
+     */
+    public static <T> void registerMarshalQueryable(MarshalQueryable<T> queryable) {
+        sRegisteredMarshalQueryables.add(queryable);
+    }
+
+    /**
+     * Lookup a marshaler between {@code T} and {@code nativeType}.
+     *
+     * <p>Marshalers are looked up in the order they were registered; earlier registered
+     * marshal queriers get priority.</p>
+     *
+     * @param typeToken The compile-time type reference for {@code T}
+     * @param nativeType The native type, e.g. {@link CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
+     * @return marshaler a non-{@code null} marshaler that supports marshaling the type combo
+     *
+     * @throws UnsupportedOperationException If no marshaler matching the args could be found
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Marshaler<T> getMarshaler(TypeReference<T> typeToken, int nativeType) {
+        // TODO: can avoid making a new token each time by code-genning
+        // the list of type tokens and native types from the keys (at the call sites)
+        MarshalToken<T> marshalToken = new MarshalToken<T>(typeToken, nativeType);
+
+        /*
+         * Marshalers are instantiated lazily once they are looked up; successive lookups
+         * will not instantiate new marshalers.
+         */
+        Marshaler<T> marshaler =
+                (Marshaler<T>) sMarshalerMap.get(marshalToken);
+
+        if (sRegisteredMarshalQueryables.size() == 0) {
+            throw new AssertionError("No available query marshalers registered");
+        }
+
+        if (marshaler == null) {
+            // Query each marshaler to see if they support the native/managed type combination
+            for (MarshalQueryable<?> potentialMarshaler : sRegisteredMarshalQueryables) {
+
+                MarshalQueryable<T> castedPotential =
+                        (MarshalQueryable<T>)potentialMarshaler;
+
+                if (castedPotential.isTypeMappingSupported(typeToken, nativeType)) {
+                    marshaler = castedPotential.createMarshaler(typeToken, nativeType);
+                    break;
+                }
+            }
+        }
+
+        if (marshaler == null) {
+            throw new UnsupportedOperationException(
+                     "Could not find marshaler that matches the requested " +
+                     "combination of type reference " +
+                     typeToken + " and native type " +
+                     MarshalHelpers.toStringNativeType(nativeType));
+        }
+
+        sMarshalerMap.put(marshalToken, marshaler);
+
+        return marshaler;
+    }
+
+    private static class MarshalToken<T> {
+        public MarshalToken(TypeReference<T> typeReference, int nativeType) {
+            this.typeReference = typeReference;
+            this.nativeType = nativeType;
+        }
+
+        final TypeReference<T> typeReference;
+        final int nativeType;
+
+        @Override
+        public boolean equals(Object other) {
+            if (other instanceof MarshalToken<?>) {
+                MarshalToken<?> otherToken = (MarshalToken<?>)other;
+                return typeReference.equals(otherToken.typeReference) &&
+                        nativeType == otherToken.nativeType;
+            }
+
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return typeReference.hashCode() ^ nativeType;
+        }
+    }
+
+    private static List<MarshalQueryable<?>> sRegisteredMarshalQueryables =
+            new ArrayList<MarshalQueryable<?>>();
+    private static HashMap<MarshalToken<?>, Marshaler<?>> sMarshalerMap =
+            new HashMap<MarshalToken<?>, Marshaler<?>>();
+
+    private MarshalRegistry() {
+        throw new AssertionError();
+    }
+}
diff --git a/core/java/android/hardware/camera2/marshal/Marshaler.java b/core/java/android/hardware/camera2/marshal/Marshaler.java
new file mode 100644
index 0000000..eb0ad15
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/Marshaler.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.marshal;
+
+import android.hardware.camera2.utils.TypeReference;
+
+import java.nio.ByteBuffer;
+
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+import static com.android.internal.util.Preconditions.*;
+
+/**
+ * Base class to marshal data to/from managed/native metadata byte buffers.
+ *
+ * <p>This class should not be created directly; an instance of it can be obtained
+ * using {@link MarshalQueryable#createMarshaler} for the same type {@code T} if the native type
+ * mapping for {@code T} {@link MarshalQueryable#isTypeMappingSupported supported}.</p>
+ *
+ * @param <T> the compile-time managed type
+ */
+public abstract class Marshaler<T> {
+
+    protected final TypeReference<T> mTypeReference;
+    protected final int mNativeType;
+
+    /**
+     * Instantiate a marshaler between a single managed/native type combination.
+     *
+     * <p>This particular managed/native type combination must be supported by
+     * {@link #isTypeMappingSupported}.</p>
+     *
+     * @param query an instance of {@link MarshalQueryable}
+     * @param typeReference the managed type reference
+     *        Must be one for which {@link #isTypeMappingSupported} returns {@code true}
+     * @param nativeType the native type, e.g.
+     *        {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
+     *        Must be one for which {@link #isTypeMappingSupported} returns {@code true}.
+     *
+     * @throws NullPointerException if any args were {@code null}
+     * @throws UnsupportedOperationException if the type mapping was not supported
+     */
+    protected Marshaler(
+            MarshalQueryable<T> query, TypeReference<T> typeReference, int nativeType) {
+        mTypeReference = checkNotNull(typeReference, "typeReference must not be null");
+        mNativeType = checkNativeType(nativeType);
+
+        if (!query.isTypeMappingSupported(typeReference, nativeType)) {
+            throw new UnsupportedOperationException(
+                    "Unsupported type marshaling for managed type "
+                            + typeReference + " and native type "
+                            + MarshalHelpers.toStringNativeType(nativeType));
+        }
+    }
+
+    /**
+     * Marshal the specified object instance (value) into a byte buffer.
+     *
+     * <p>Upon completion, the {@link ByteBuffer#position()} will have advanced by
+     * the {@link #calculateMarshalSize marshal size} of {@code value}.</p>
+     *
+     * @param value the value of type T that we wish to write into the byte buffer
+     * @param buffer the byte buffer into which the marshaled object will be written
+     */
+    public abstract void marshal(T value, ByteBuffer buffer);
+
+    /**
+     * Get the size in bytes for how much space would be required to write this {@code value}
+     * into a byte buffer using the given {@code nativeType}.
+     *
+     * <p>If the size of this {@code T} instance when serialized into a buffer is always constant,
+     * then this method will always return the same value (and particularly, it will return
+     * an equivalent value to {@link #getNativeSize()}.</p>
+     *
+     * <p>Overriding this method is a must when the size is {@link NATIVE_SIZE_DYNAMIC dynamic}.</p>
+     *
+     * @param value the value of type T that we wish to write into the byte buffer
+     * @return the size that would need to be written to the byte buffer
+     */
+    public int calculateMarshalSize(T value) {
+        int nativeSize = getNativeSize();
+
+        if (nativeSize == NATIVE_SIZE_DYNAMIC) {
+            throw new AssertionError("Override this function for dynamically-sized objects");
+        }
+
+        return nativeSize;
+    }
+
+    /**
+     * Unmarshal a new object instance from the byte buffer into its managed type.
+     *
+     * <p>Upon completion, the {@link ByteBuffer#position()} will have advanced by
+     * the {@link #calculateMarshalSize marshal size} of the returned {@code T} instance.</p>
+     *
+     * @param buffer the byte buffer, from which we will read the object
+     * @return a new instance of type T read from the byte buffer
+     */
+    public abstract T unmarshal(ByteBuffer buffer);
+
+    /**
+     * Used to denote variable-length data structures.
+     *
+     * <p>If the size is dynamic then we can't know ahead of time how big of a data structure
+     * to preallocate for e.g. arrays, so one object must be unmarshaled at a time.</p>
+     */
+    public static int NATIVE_SIZE_DYNAMIC = -1;
+
+    /**
+     * How many bytes a single instance of {@code T} will take up if marshalled to/from
+     * {@code nativeType}.
+     *
+     * <p>When unmarshaling data from native to managed, the instance {@code T} is not yet
+     * available. If the native size is always a fixed mapping regardless of the instance of
+     * {@code T} (e.g. if the type is not a container of some sort), it can be used to preallocate
+     * containers for {@code T} to avoid resizing them.</p>
+     *
+     * <p>In particular, the array marshaler takes advantage of this (when size is not dynamic)
+     * to preallocate arrays of the right length when unmarshaling an array {@code T[]}.</p>
+     *
+     * @return a size in bytes, or {@link #NATIVE_SIZE_DYNAMIC} if the size is dynamic
+     */
+    public abstract int getNativeSize();
+
+    /**
+     * The type reference for {@code T} for the managed type side of this marshaler.
+     */
+    public TypeReference<T> getTypeReference() {
+        return mTypeReference;
+    }
+
+    /** The native type corresponding to this marshaler for the native side of this marshaler.*/
+    public int getNativeType() {
+        return mNativeType;
+    }
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableArray.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableArray.java
new file mode 100644
index 0000000..22b87ef
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableArray.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.marshal.impl;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.marshal.MarshalRegistry;
+import android.hardware.camera2.utils.TypeReference;
+import android.util.Log;
+
+import java.lang.reflect.Array;
+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}.
+ *
+ * <p>To marshal any {@code T} to/from a native type, the marshaler for T to/from that native type
+ * also has to exist.</p>
+ *
+ * <p>{@code T} can be either a T2[] where T2 is an object type, or a P[] where P is a
+ * built-in primitive (e.g. int[], float[], etc).</p>
+
+ * @param <T> the type of the array (e.g. T = int[], or T = Rational[])
+ */
+public class MarshalQueryableArray<T> implements MarshalQueryable<T> {
+
+    private static final String TAG = MarshalQueryableArray.class.getSimpleName();
+    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+
+    private class MarshalerArray extends Marshaler<T> {
+        private final Class<T> mClass;
+        private final Marshaler<?> mComponentMarshaler;
+        private final Class<?> mComponentClass;
+
+        @SuppressWarnings("unchecked")
+        protected MarshalerArray(TypeReference<T> typeReference, int nativeType) {
+            super(MarshalQueryableArray.this, typeReference, nativeType);
+
+            mClass = (Class<T>)typeReference.getRawType();
+
+            TypeReference<?> componentToken = typeReference.getComponentType();
+            mComponentMarshaler = MarshalRegistry.getMarshaler(componentToken, mNativeType);
+            mComponentClass = componentToken.getRawType();
+        }
+
+        @Override
+        public void marshal(T value, ByteBuffer buffer) {
+            int length = Array.getLength(value);
+            for (int i = 0; i < length; ++i) {
+                marshalArrayElement(mComponentMarshaler, buffer, value, i);
+            }
+        }
+
+        @Override
+        public T unmarshal(ByteBuffer buffer) {
+            Object array;
+
+            int elementSize = mComponentMarshaler.getNativeSize();
+
+            if (elementSize != Marshaler.NATIVE_SIZE_DYNAMIC) {
+                int remaining = buffer.remaining();
+                int arraySize = remaining / elementSize;
+
+                if (remaining % elementSize != 0) {
+                    throw new UnsupportedOperationException("Arrays for " + mTypeReference
+                            + " must be packed tighly into a multiple of " + elementSize
+                            + "; but there are " + (remaining % elementSize) + " left over bytes");
+                }
+
+                if (VERBOSE) {
+                    Log.v(TAG, String.format(
+                            "Attempting to unpack array (count = %d, element size = %d, bytes "
+                            + "remaining = %d) for type %s",
+                            arraySize, elementSize, remaining, mClass));
+                }
+
+                array = Array.newInstance(mComponentClass, arraySize);
+                for (int i = 0; i < arraySize; ++i) {
+                    Object elem = mComponentMarshaler.unmarshal(buffer);
+                    Array.set(array, i, elem);
+                }
+            } else {
+                // Dynamic size, use an array list.
+                ArrayList<Object> arrayList = new ArrayList<Object>();
+
+                // Assumes array is packed tightly; no unused bytes allowed
+                while (buffer.hasRemaining()) {
+                    Object elem = mComponentMarshaler.unmarshal(buffer);
+                    arrayList.add(elem);
+                }
+
+                int arraySize = arrayList.size();
+                array = copyListToArray(arrayList, Array.newInstance(mComponentClass, arraySize));
+            }
+
+            if (buffer.remaining() != 0) {
+                Log.e(TAG, "Trailing bytes (" + buffer.remaining() + ") left over after unpacking "
+                        + mClass);
+            }
+
+            return mClass.cast(array);
+        }
+
+        @Override
+        public int getNativeSize() {
+            return NATIVE_SIZE_DYNAMIC;
+        }
+
+        @Override
+        public int calculateMarshalSize(T value) {
+            int elementSize = mComponentMarshaler.getNativeSize();
+            int arrayLength = Array.getLength(value);
+
+            if (elementSize != Marshaler.NATIVE_SIZE_DYNAMIC) {
+                // The fast way. Every element size is uniform.
+                return elementSize * arrayLength;
+            } else {
+                // The slow way. Accumulate size for each element.
+                int size = 0;
+                for (int i = 0; i < arrayLength; ++i) {
+                    size += calculateElementMarshalSize(mComponentMarshaler, value, i);
+                }
+
+                return size;
+            }
+        }
+
+        /*
+         * Helpers to avoid compiler errors regarding types with wildcards (?)
+         */
+
+        @SuppressWarnings("unchecked")
+        private <TElem> void marshalArrayElement(Marshaler<TElem> marshaler,
+                ByteBuffer buffer, Object array, int index) {
+            marshaler.marshal((TElem)Array.get(array, index), buffer);
+        }
+
+        @SuppressWarnings("unchecked")
+        private Object copyListToArray(ArrayList<?> arrayList, Object arrayDest) {
+            return arrayList.toArray((T[]) arrayDest);
+        }
+
+        @SuppressWarnings("unchecked")
+        private <TElem> int calculateElementMarshalSize(Marshaler<TElem> marshaler,
+                Object array, int index) {
+            Object elem = Array.get(array, index);
+
+            return marshaler.calculateMarshalSize((TElem) elem);
+        }
+    }
+
+    @Override
+    public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) {
+        return new MarshalerArray(managedType, nativeType);
+    }
+
+    @Override
+    public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) {
+        // support both ConcreteType[] and GenericType<ConcreteType>[]
+        return managedType.getRawType().isArray();
+
+        // TODO: Should this recurse deeper and check that there is
+        // a valid marshaler for the ConcreteType as well?
+    }
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableBoolean.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableBoolean.java
new file mode 100644
index 0000000..4aa4b4a
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableBoolean.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Marshal booleans: TYPE_BYTE <-> boolean/Boolean
+ */
+public class MarshalQueryableBoolean implements MarshalQueryable<Boolean> {
+
+    private class MarshalerBoolean extends Marshaler<Boolean> {
+        protected MarshalerBoolean(TypeReference<Boolean> typeReference, int nativeType) {
+            super(MarshalQueryableBoolean.this, typeReference, nativeType);
+        }
+
+        @Override
+        public void marshal(Boolean value, ByteBuffer buffer) {
+            boolean unboxValue = value;
+            buffer.put((byte)(unboxValue ? 1 : 0));
+        }
+
+        @Override
+        public Boolean unmarshal(ByteBuffer buffer) {
+            return buffer.get() != 0;
+        }
+
+        @Override
+        public int getNativeSize() {
+            return SIZEOF_BYTE;
+        }
+    }
+
+    @Override
+    public Marshaler<Boolean> createMarshaler(TypeReference<Boolean> managedType,
+            int nativeType) {
+        return new MarshalerBoolean(managedType, nativeType);
+    }
+
+    @Override
+    public boolean isTypeMappingSupported(TypeReference<Boolean> managedType, int nativeType) {
+        return (Boolean.class.equals(managedType.getType())
+                || boolean.class.equals(managedType.getType())) && nativeType == TYPE_BYTE;
+    }
+
+
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java
new file mode 100644
index 0000000..d3796db
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.marshal.impl;
+
+import android.hardware.camera2.ColorSpaceTransform;
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+
+import java.nio.ByteBuffer;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+/**
+ * Marshal {@link ColorSpaceTransform} to/from {@link #TYPE_RATIONAL}
+ */
+public class MarshalQueryableColorSpaceTransform implements
+        MarshalQueryable<ColorSpaceTransform> {
+
+    private static final int ELEMENTS_INT32 = 3 * 3 * (SIZEOF_RATIONAL / SIZEOF_INT32);
+    private static final int SIZE = SIZEOF_INT32 * ELEMENTS_INT32;
+
+    /** rational x 3 x 3 */
+    private class MarshalerColorSpaceTransform extends Marshaler<ColorSpaceTransform> {
+        protected MarshalerColorSpaceTransform(TypeReference<ColorSpaceTransform> typeReference,
+                int nativeType) {
+            super(MarshalQueryableColorSpaceTransform.this, typeReference, nativeType);
+        }
+
+        @Override
+        public void marshal(ColorSpaceTransform value, ByteBuffer buffer) {
+            int[] transformAsArray = new int[ELEMENTS_INT32];
+            value.copyElements(transformAsArray, /*offset*/0);
+
+            for (int i = 0; i < ELEMENTS_INT32; ++i) {
+                buffer.putInt(transformAsArray[i]);
+            }
+        }
+
+        @Override
+        public ColorSpaceTransform unmarshal(ByteBuffer buffer) {
+            int[] transformAsArray = new int[ELEMENTS_INT32];
+
+            for (int i = 0; i < ELEMENTS_INT32; ++i) {
+                transformAsArray[i] = buffer.getInt();
+            }
+
+            return new ColorSpaceTransform(transformAsArray);
+        }
+
+        @Override
+        public int getNativeSize() {
+            return SIZE;
+        }
+    }
+
+    @Override
+    public Marshaler<ColorSpaceTransform> createMarshaler(
+            TypeReference<ColorSpaceTransform> managedType, int nativeType) {
+        return new MarshalerColorSpaceTransform(managedType, nativeType);
+    }
+
+    @Override
+    public boolean isTypeMappingSupported(
+            TypeReference<ColorSpaceTransform> managedType, int nativeType) {
+        return nativeType == TYPE_RATIONAL &&
+                ColorSpaceTransform.class.equals(managedType.getType());
+    }
+
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableEnum.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableEnum.java
new file mode 100644
index 0000000..fa53db2
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableEnum.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.marshal.impl;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+import android.util.Log;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+/**
+ * Marshal any simple enum (0-arg constructors only) into/from either
+ * {@code TYPE_BYTE} or {@code TYPE_INT32}.
+ *
+ * <p>Default values of the enum are mapped to its ordinal; this can be overridden
+ * by providing a manual value with {@link #registerEnumValues}.</p>
+
+ * @param <T> the type of {@code Enum}
+ */
+public class MarshalQueryableEnum<T extends Enum<T>> implements MarshalQueryable<T> {
+
+    private static final String TAG = MarshalQueryableEnum.class.getSimpleName();
+    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+
+    private static final int UINT8_MIN = 0x0;
+    private static final int UINT8_MAX = (1 << Byte.SIZE) - 1;
+    private static final int UINT8_MASK = UINT8_MAX;
+
+    private class MarshalerEnum extends Marshaler<T> {
+
+        private final Class<T> mClass;
+
+        @SuppressWarnings("unchecked")
+        protected MarshalerEnum(TypeReference<T> typeReference, int nativeType) {
+            super(MarshalQueryableEnum.this, typeReference, nativeType);
+
+            mClass = (Class<T>)typeReference.getRawType();
+        }
+
+        @Override
+        public void marshal(T value, ByteBuffer buffer) {
+            int enumValue = getEnumValue(value);
+
+            if (mNativeType == TYPE_INT32) {
+                buffer.putInt(enumValue);
+            } else if (mNativeType == TYPE_BYTE) {
+                if (enumValue < UINT8_MIN || enumValue > UINT8_MAX) {
+                    throw new UnsupportedOperationException(String.format(
+                            "Enum value %x too large to fit into unsigned byte", enumValue));
+                }
+                buffer.put((byte)enumValue);
+            } else {
+                throw new AssertionError();
+            }
+        }
+
+        @Override
+        public T unmarshal(ByteBuffer buffer) {
+            int enumValue;
+
+            switch (mNativeType) {
+                case TYPE_INT32:
+                    enumValue = buffer.getInt();
+                    break;
+                case TYPE_BYTE:
+                    // get the unsigned byte value; avoid sign extension
+                    enumValue = buffer.get() & UINT8_MASK;
+                    break;
+                default:
+                    throw new AssertionError(
+                            "Unexpected native type; impossible since its not supported");
+            }
+
+            return getEnumFromValue(mClass, enumValue);
+        }
+
+        @Override
+        public int getNativeSize() {
+            return getPrimitiveTypeSize(mNativeType);
+        }
+    }
+
+    @Override
+    public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) {
+        return new MarshalerEnum(managedType, nativeType);
+    }
+
+    @Override
+    public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) {
+        if (nativeType == TYPE_INT32 || nativeType == TYPE_BYTE) {
+            if (managedType.getType() instanceof Class<?>) {
+                Class<?> typeClass = (Class<?>)managedType.getType();
+
+                if (typeClass.isEnum()) {
+                    if (VERBOSE) {
+                        Log.v(TAG, "possible enum detected for " + typeClass);
+                    }
+
+                    // The enum must not take extra arguments
+                    try {
+                        // match a class like: "public enum Fruits { Apple, Orange; }"
+                        typeClass.getDeclaredConstructor(String.class, int.class);
+                        return true;
+                    } catch (NoSuchMethodException e) {
+                        // Skip: custom enum with a special constructor e.g. Foo(T), but need Foo()
+                        Log.e(TAG, "Can't marshal class " + typeClass + "; no default constructor");
+                    } catch (SecurityException e) {
+                        // Skip: wouldn't be able to touch the enum anyway
+                        Log.e(TAG, "Can't marshal class " + typeClass + "; not accessible");
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    @SuppressWarnings("rawtypes")
+    private static final HashMap<Class<? extends Enum>, int[]> sEnumValues =
+            new HashMap<Class<? extends Enum>, int[]>();
+
+    /**
+     * Register a non-sequential set of values to be used with the marshal/unmarshal functions.
+     *
+     * <p>This enables get/set to correctly marshal the enum into a value that is C-compatible.</p>
+     *
+     * @param enumType The class for an enum
+     * @param values A list of values mapping to the ordinals of the enum
+     */
+    public static <T extends Enum<T>> void registerEnumValues(Class<T> enumType, int[] values) {
+        if (enumType.getEnumConstants().length != values.length) {
+            throw new IllegalArgumentException(
+                    "Expected values array to be the same size as the enumTypes values "
+                            + values.length + " for type " + enumType);
+        }
+        if (VERBOSE) {
+            Log.v(TAG, "Registered enum values for type " + enumType + " values");
+        }
+
+        sEnumValues.put(enumType, values);
+    }
+
+    /**
+     * Get the numeric value from an enum.
+     *
+     * <p>This is usually the same as the ordinal value for
+     * enums that have fully sequential values, although for C-style enums the range of values
+     * may not map 1:1.</p>
+     *
+     * @param enumValue Enum instance
+     * @return Int guaranteed to be ABI-compatible with the C enum equivalent
+     */
+    private static <T extends Enum<T>> int getEnumValue(T enumValue) {
+        int[] values;
+        values = sEnumValues.get(enumValue.getClass());
+
+        int ordinal = enumValue.ordinal();
+        if (values != null) {
+            return values[ordinal];
+        }
+
+        return ordinal;
+    }
+
+    /**
+     * Finds the enum corresponding to it's numeric value. Opposite of {@link #getEnumValue} method.
+     *
+     * @param enumType Class of the enum we want to find
+     * @param value The numeric value of the enum
+     * @return An instance of the enum
+     */
+    private static <T extends Enum<T>> T getEnumFromValue(Class<T> enumType, int value) {
+        int ordinal;
+
+        int[] registeredValues = sEnumValues.get(enumType);
+        if (registeredValues != null) {
+            ordinal = -1;
+
+            for (int i = 0; i < registeredValues.length; ++i) {
+                if (registeredValues[i] == value) {
+                    ordinal = i;
+                    break;
+                }
+            }
+        } else {
+            ordinal = value;
+        }
+
+        T[] values = enumType.getEnumConstants();
+
+        if (ordinal < 0 || ordinal >= values.length) {
+            throw new IllegalArgumentException(
+                    String.format(
+                            "Argument 'value' (%d) was not a valid enum value for type %s "
+                                    + "(registered? %b)",
+                            value,
+                            enumType, (registeredValues != null)));
+        }
+
+        return values[ordinal];
+    }
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java
new file mode 100644
index 0000000..c8b9bd8
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.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.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.MeteringRectangle;
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+
+import java.nio.ByteBuffer;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+/**
+ * Marshal {@link MeteringRectangle} to/from {@link #TYPE_INT32}
+ */
+public class MarshalQueryableMeteringRectangle implements MarshalQueryable<MeteringRectangle> {
+    private static final int SIZE = SIZEOF_INT32 * 5;
+
+    /** (xmin, ymin, xmax, ymax, weight) */
+    private class MarshalerMeteringRectangle extends Marshaler<MeteringRectangle> {
+        protected MarshalerMeteringRectangle(TypeReference<MeteringRectangle> typeReference,
+                int nativeType) {
+            super(MarshalQueryableMeteringRectangle.this, typeReference, nativeType);
+        }
+
+        @Override
+        public void marshal(MeteringRectangle value, ByteBuffer buffer) {
+            int xMin = value.getX();
+            int yMin = value.getY();
+            int xMax = xMin + value.getWidth();
+            int yMax = yMin + value.getHeight();
+            int weight = value.getMeteringWeight();
+
+            buffer.putInt(xMin);
+            buffer.putInt(yMin);
+            buffer.putInt(xMax);
+            buffer.putInt(yMax);
+            buffer.putInt(weight);
+        }
+
+        @Override
+        public MeteringRectangle unmarshal(ByteBuffer buffer) {
+            int xMin = buffer.getInt();
+            int yMin = buffer.getInt();
+            int xMax = buffer.getInt();
+            int yMax = buffer.getInt();
+            int weight = buffer.getInt();
+
+            int width = xMax - xMin;
+            int height = yMax - yMin;
+
+            return new MeteringRectangle(xMin, yMin, width, height, weight);
+        }
+
+        @Override
+        public int getNativeSize() {
+            return SIZE;
+        }
+    }
+
+    @Override
+    public Marshaler<MeteringRectangle> createMarshaler(
+            TypeReference<MeteringRectangle> managedType, int nativeType) {
+        return new MarshalerMeteringRectangle(managedType, nativeType);
+    }
+
+    @Override
+    public boolean isTypeMappingSupported(
+            TypeReference<MeteringRectangle> managedType, int nativeType) {
+        return nativeType == TYPE_INT32 && MeteringRectangle.class.equals(managedType.getType());
+    }
+
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableNativeByteToInteger.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableNativeByteToInteger.java
new file mode 100644
index 0000000..3b89c82
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableNativeByteToInteger.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.marshal.impl;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Marshal fake native enums (ints): TYPE_BYTE <-> int/Integer
+ */
+public class MarshalQueryableNativeByteToInteger implements MarshalQueryable<Integer> {
+
+    private static final int UINT8_MASK = (1 << Byte.SIZE) - 1;
+
+    private class MarshalerNativeByteToInteger extends Marshaler<Integer> {
+        protected MarshalerNativeByteToInteger(TypeReference<Integer> typeReference,
+                int nativeType) {
+            super(MarshalQueryableNativeByteToInteger.this, typeReference, nativeType);
+        }
+
+        @Override
+        public void marshal(Integer value, ByteBuffer buffer) {
+            buffer.put((byte)(int)value); // truncate down to byte
+        }
+
+        @Override
+        public Integer unmarshal(ByteBuffer buffer) {
+            // expand unsigned byte to int; avoid sign extension
+            return buffer.get() & UINT8_MASK;
+        }
+
+        @Override
+        public int getNativeSize() {
+            return SIZEOF_BYTE;
+        }
+    }
+
+    @Override
+    public Marshaler<Integer> createMarshaler(TypeReference<Integer> managedType,
+            int nativeType) {
+        return new MarshalerNativeByteToInteger(managedType, nativeType);
+    }
+
+    @Override
+    public boolean isTypeMappingSupported(TypeReference<Integer> managedType, int nativeType) {
+        return (Integer.class.equals(managedType.getType())
+                || int.class.equals(managedType.getType())) && nativeType == TYPE_BYTE;
+    }
+
+
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableParcelable.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableParcelable.java
new file mode 100644
index 0000000..1fd6a1d
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableParcelable.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.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+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
+ *
+ * <p>Use with extreme caution! File descriptors and binders will not be marshaled across.</p>
+ */
+public class MarshalQueryableParcelable<T extends Parcelable>
+        implements MarshalQueryable<T> {
+
+    private static final String TAG = "MarshalParcelable";
+    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+
+    private static final String FIELD_CREATOR = "CREATOR";
+
+    private class MarshalerParcelable extends Marshaler<T> {
+
+        private final Class<T> mClass;
+        private final Parcelable.Creator<T> mCreator;
+
+        @SuppressWarnings("unchecked")
+        protected MarshalerParcelable(TypeReference<T> typeReference,
+                int nativeType) {
+            super(MarshalQueryableParcelable.this, typeReference, nativeType);
+
+            mClass = (Class<T>)typeReference.getRawType();
+            Field creatorField;
+            try {
+                creatorField = mClass.getDeclaredField(FIELD_CREATOR);
+            } catch (NoSuchFieldException e) {
+                // Impossible. All Parcelable implementations must have a 'CREATOR' static field
+                throw new AssertionError(e);
+            }
+
+            try {
+                mCreator = (Parcelable.Creator<T>)creatorField.get(null);
+            } catch (IllegalAccessException e) {
+                // Impossible: All 'CREATOR' static fields must be public
+                throw new AssertionError(e);
+            } catch (IllegalArgumentException e) {
+                // Impossible: This is a static field, so null must be ok
+                throw new AssertionError(e);
+            }
+        }
+
+        @Override
+        public void marshal(T value, ByteBuffer buffer) {
+            if (VERBOSE) {
+                Log.v(TAG, "marshal " + value);
+            }
+
+            Parcel parcel = Parcel.obtain();
+            byte[] parcelContents;
+
+            try {
+                value.writeToParcel(parcel, /*flags*/0);
+
+                if (parcel.hasFileDescriptors()) {
+                    throw new UnsupportedOperationException(
+                            "Parcelable " + value + " must not have file descriptors");
+                }
+
+                parcelContents = parcel.marshall();
+            }
+            finally {
+                parcel.recycle();
+            }
+
+            if (parcelContents.length == 0) {
+                throw new AssertionError("No data marshaled for " + value);
+            }
+
+            buffer.put(parcelContents);
+        }
+
+        @Override
+        public T unmarshal(ByteBuffer buffer) {
+            if (VERBOSE) {
+                Log.v(TAG, "unmarshal, buffer remaining " + buffer.remaining());
+            }
+
+            /*
+             * Quadratically slow when marshaling an array of parcelables.
+             *
+             * Read out the entire byte buffer as an array, then copy it into the parcel.
+             *
+             * Once we unparcel the entire object, advance the byte buffer by only how many
+             * bytes the parcel actually used up.
+             *
+             * Future: If we ever do need to use parcelable arrays, we can do this a little smarter
+             * by reading out a chunk like 4,8,16,24 each time, but not sure how to detect
+             * parcels being too short in this case.
+             *
+             * Future: Alternatively use Parcel#obtain(long) directly into the native
+             * pointer of a ByteBuffer, which would not copy if the ByteBuffer was direct.
+             */
+            buffer.mark();
+
+            Parcel parcel = Parcel.obtain();
+            try {
+                int maxLength = buffer.remaining();
+
+                byte[] remaining = new byte[maxLength];
+                buffer.get(remaining);
+
+                parcel.unmarshall(remaining, /*offset*/0, maxLength);
+                parcel.setDataPosition(/*pos*/0);
+
+                T value = mCreator.createFromParcel(parcel);
+                int actualLength = parcel.dataPosition();
+
+                if (actualLength == 0) {
+                    throw new AssertionError("No data marshaled for " + value);
+                }
+
+                // set the position past the bytes the parcelable actually used
+                buffer.reset();
+                buffer.position(buffer.position() + actualLength);
+
+                if (VERBOSE) {
+                    Log.v(TAG, "unmarshal, parcel length was " + actualLength);
+                    Log.v(TAG, "unmarshal, value is " + value);
+                }
+
+                return mClass.cast(value);
+            } finally {
+                parcel.recycle();
+            }
+        }
+
+        @Override
+        public int getNativeSize() {
+            return NATIVE_SIZE_DYNAMIC;
+        }
+
+        @Override
+        public int calculateMarshalSize(T value) {
+            Parcel parcel = Parcel.obtain();
+            try {
+                value.writeToParcel(parcel, /*flags*/0);
+                int length = parcel.marshall().length;
+
+                if (VERBOSE) {
+                    Log.v(TAG, "calculateMarshalSize, length when parceling "
+                            + value + " is " + length);
+                }
+
+                return length;
+            } finally {
+                parcel.recycle();
+            }
+        }
+    }
+
+    @Override
+    public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) {
+        return new MarshalerParcelable(managedType, nativeType);
+    }
+
+    @Override
+    public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) {
+        return Parcelable.class.isAssignableFrom(managedType.getRawType());
+    }
+
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java
new file mode 100644
index 0000000..708da70
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.marshal.impl;
+
+import android.hardware.camera2.Rational;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+import static com.android.internal.util.Preconditions.*;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Marshal/unmarshal built-in primitive types to and from a {@link ByteBuffer}.
+ *
+ * <p>The following list of type marshaling is supported:
+ * <ul>
+ * <li>byte <-> TYPE_BYTE
+ * <li>int <-> TYPE_INT32
+ * <li>long <-> TYPE_INT64
+ * <li>float <-> TYPE_FLOAT
+ * <li>double <-> TYPE_DOUBLE
+ * <li>Rational <-> TYPE_RATIONAL
+ * </ul>
+ * </p>
+ *
+ * <p>Due to the nature of generics, values are always boxed; this also means that both
+ * the boxed and unboxed types are supported (i.e. both {@code int} and {@code Integer}).</p>
+ *
+ * <p>Each managed type <!--(other than boolean)--> must correspond 1:1 to the native type
+ * (e.g. a byte will not map to a {@link CameraMetadataNative#TYPE_INT32 TYPE_INT32} or vice versa)
+ * for marshaling.</p>
+ */
+public final class MarshalQueryablePrimitive<T> implements MarshalQueryable<T> {
+
+    private class MarshalerPrimitive extends Marshaler<T> {
+        /** Always the wrapped class variant of the primitive class for {@code T} */
+        private final Class<T> mClass;
+
+        @SuppressWarnings("unchecked")
+        protected MarshalerPrimitive(TypeReference<T> typeReference, int nativeType) {
+            super(MarshalQueryablePrimitive.this, typeReference, nativeType);
+
+            // Turn primitives into wrappers, otherwise int.class.cast(Integer) will fail
+            mClass = wrapClassIfPrimitive((Class<T>)typeReference.getRawType());
+        }
+
+        @Override
+        public T unmarshal(ByteBuffer buffer) {
+            return mClass.cast(unmarshalObject(buffer));
+        }
+
+        @Override
+        public int calculateMarshalSize(T value) {
+            return getPrimitiveTypeSize(mNativeType);
+        }
+
+        @Override
+        public void marshal(T value, ByteBuffer buffer) {
+            if (value instanceof Integer) {
+                checkNativeTypeEquals(TYPE_INT32, mNativeType);
+                final int val = (Integer) value;
+                marshalPrimitive(val, buffer);
+            } else if (value instanceof Float) {
+                checkNativeTypeEquals(TYPE_FLOAT, mNativeType);
+                final float val = (Float) value;
+                marshalPrimitive(val, buffer);
+            } else if (value instanceof Long) {
+                checkNativeTypeEquals(TYPE_INT64, mNativeType);
+                final long val = (Long) value;
+                marshalPrimitive(val, buffer);
+            } else if (value instanceof Rational) {
+                checkNativeTypeEquals(TYPE_RATIONAL, mNativeType);
+                marshalPrimitive((Rational) value, buffer);
+            } else if (value instanceof Double) {
+                checkNativeTypeEquals(TYPE_DOUBLE, mNativeType);
+                final double val = (Double) value;
+                marshalPrimitive(val, buffer);
+            } else if (value instanceof Byte) {
+                checkNativeTypeEquals(TYPE_BYTE, mNativeType);
+                final byte val = (Byte) value;
+                marshalPrimitive(val, buffer);
+            } else {
+                throw new UnsupportedOperationException(
+                        "Can't marshal managed type " + mTypeReference);
+            }
+        }
+
+        private void marshalPrimitive(int value, ByteBuffer buffer) {
+            buffer.putInt(value);
+        }
+
+        private void marshalPrimitive(float value, ByteBuffer buffer) {
+            buffer.putFloat(value);
+        }
+
+        private void marshalPrimitive(double value, ByteBuffer buffer) {
+            buffer.putDouble(value);
+        }
+
+        private void marshalPrimitive(long value, ByteBuffer buffer) {
+            buffer.putLong(value);
+        }
+
+        private void marshalPrimitive(Rational value, ByteBuffer buffer) {
+            buffer.putInt(value.getNumerator());
+            buffer.putInt(value.getDenominator());
+        }
+
+        private void marshalPrimitive(byte value, ByteBuffer buffer) {
+            buffer.put(value);
+        }
+
+        private Object unmarshalObject(ByteBuffer buffer) {
+            switch (mNativeType) {
+                case TYPE_INT32:
+                    return buffer.getInt();
+                case TYPE_FLOAT:
+                    return buffer.getFloat();
+                case TYPE_INT64:
+                    return buffer.getLong();
+                case TYPE_RATIONAL:
+                    int numerator = buffer.getInt();
+                    int denominator = buffer.getInt();
+                    return new Rational(numerator, denominator);
+                case TYPE_DOUBLE:
+                    return buffer.getDouble();
+                case TYPE_BYTE:
+                    return buffer.get(); // getByte
+                default:
+                    throw new UnsupportedOperationException(
+                            "Can't unmarshal native type " + mNativeType);
+            }
+        }
+
+        @Override
+        public int getNativeSize() {
+            return getPrimitiveTypeSize(mNativeType);
+        }
+    }
+
+    @Override
+    public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) {
+        return new MarshalerPrimitive(managedType, nativeType);
+    }
+
+    @Override
+    public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) {
+        if (managedType.getType() instanceof Class<?>) {
+            Class<?> klass = (Class<?>)managedType.getType();
+
+            if (klass == byte.class || klass == Byte.class) {
+                return nativeType == TYPE_BYTE;
+            } else if (klass == int.class || klass == Integer.class) {
+                return nativeType == TYPE_INT32;
+            } else if (klass == float.class || klass == Float.class) {
+                return nativeType == TYPE_FLOAT;
+            } else if (klass == long.class || klass == Long.class) {
+                return nativeType == TYPE_INT64;
+            } else if (klass == double.class || klass == Double.class) {
+                return nativeType == TYPE_DOUBLE;
+            } else if (klass == Rational.class) {
+                return nativeType == TYPE_RATIONAL;
+            }
+        }
+        return false;
+    }
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRange.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRange.java
new file mode 100644
index 0000000..8512804
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRange.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.marshal.MarshalRegistry;
+import android.hardware.camera2.utils.TypeReference;
+import android.util.Range;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.ParameterizedType;
+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
+ */
+public class MarshalQueryableRange<T extends Comparable<? super T>>
+        implements MarshalQueryable<Range<T>> {
+    private static final int RANGE_COUNT = 2;
+
+    private class MarshalerRange extends Marshaler<Range<T>> {
+        private final Class<? super Range<T>> mClass;
+        private final Constructor<Range<T>> mConstructor;
+        /** Marshal the {@code T} inside of {@code Range<T>} */
+        private final Marshaler<T> mNestedTypeMarshaler;
+
+        @SuppressWarnings("unchecked")
+        protected MarshalerRange(TypeReference<Range<T>> typeReference,
+                int nativeType) {
+            super(MarshalQueryableRange.this, typeReference, nativeType);
+
+            mClass = typeReference.getRawType();
+
+            /*
+             * Lookup the actual type argument, e.g. Range<Integer> --> Integer
+             * and then get the marshaler for that managed type.
+             */
+            ParameterizedType paramType;
+            try {
+                paramType = (ParameterizedType) typeReference.getType();
+            } catch (ClassCastException e) {
+                throw new AssertionError("Raw use of Range is not supported", e);
+            }
+            Type actualTypeArgument = paramType.getActualTypeArguments()[0];
+
+            TypeReference<?> actualTypeArgToken =
+                    TypeReference.createSpecializedTypeReference(actualTypeArgument);
+
+            mNestedTypeMarshaler = (Marshaler<T>)MarshalRegistry.getMarshaler(
+                    actualTypeArgToken, mNativeType);
+            try {
+                mConstructor = (Constructor<Range<T>>)mClass.getConstructor(
+                        Comparable.class, Comparable.class);
+            } catch (NoSuchMethodException e) {
+                throw new AssertionError(e);
+            }
+        }
+
+        @Override
+        public void marshal(Range<T> value, ByteBuffer buffer) {
+            mNestedTypeMarshaler.marshal(value.getLower(), buffer);
+            mNestedTypeMarshaler.marshal(value.getUpper(), buffer);
+        }
+
+        @Override
+        public Range<T> unmarshal(ByteBuffer buffer) {
+            T lower = mNestedTypeMarshaler.unmarshal(buffer);
+            T upper = mNestedTypeMarshaler.unmarshal(buffer);
+
+            try {
+                return mConstructor.newInstance(lower, upper);
+            } catch (InstantiationException e) {
+                throw new AssertionError(e);
+            } catch (IllegalAccessException e) {
+                throw new AssertionError(e);
+            } catch (IllegalArgumentException e) {
+                throw new AssertionError(e);
+            } catch (InvocationTargetException e) {
+                throw new AssertionError(e);
+            }
+        }
+
+        @Override
+        public int getNativeSize() {
+            int nestedSize = mNestedTypeMarshaler.getNativeSize();
+
+            if (nestedSize != NATIVE_SIZE_DYNAMIC) {
+                return nestedSize * RANGE_COUNT;
+            } else {
+                return NATIVE_SIZE_DYNAMIC;
+            }
+        }
+
+        @Override
+        public int calculateMarshalSize(Range<T> value) {
+            int nativeSize = getNativeSize();
+
+            if (nativeSize != NATIVE_SIZE_DYNAMIC) {
+                return nativeSize;
+            } else {
+                int lowerSize = mNestedTypeMarshaler.calculateMarshalSize(value.getLower());
+                int upperSize = mNestedTypeMarshaler.calculateMarshalSize(value.getUpper());
+
+                return lowerSize + upperSize;
+            }
+        }
+    }
+
+    @Override
+    public Marshaler<Range<T>> createMarshaler(TypeReference<Range<T>> managedType,
+            int nativeType) {
+        return new MarshalerRange(managedType, nativeType);
+    }
+
+    @Override
+    public boolean isTypeMappingSupported(TypeReference<Range<T>> managedType, int nativeType) {
+        return (Range.class.equals(managedType.getRawType()));
+    }
+
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRect.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRect.java
new file mode 100644
index 0000000..de20a1f
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRect.java
@@ -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.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import android.graphics.Rect;
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+
+import java.nio.ByteBuffer;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+/**
+ * Marshal {@link Rect} to/from {@link #TYPE_INT32}
+ */
+public class MarshalQueryableRect implements MarshalQueryable<Rect> {
+    private static final int SIZE = SIZEOF_INT32 * 4;
+
+    private class MarshalerRect extends Marshaler<Rect> {
+        protected MarshalerRect(TypeReference<Rect> typeReference,
+                int nativeType) {
+            super(MarshalQueryableRect.this, typeReference, nativeType);
+        }
+
+        @Override
+        public void marshal(Rect value, ByteBuffer buffer) {
+            buffer.putInt(value.left);
+            buffer.putInt(value.top);
+            buffer.putInt(value.width());
+            buffer.putInt(value.height());
+        }
+
+        @Override
+        public Rect unmarshal(ByteBuffer buffer) {
+            int left = buffer.getInt();
+            int top = buffer.getInt();
+            int width = buffer.getInt();
+            int height = buffer.getInt();
+
+            int right = left + width;
+            int bottom = top + height;
+
+            return new Rect(left, top, right, bottom);
+        }
+
+        @Override
+        public int getNativeSize() {
+            return SIZE;
+        }
+    }
+
+    @Override
+    public Marshaler<Rect> createMarshaler(TypeReference<Rect> managedType, int nativeType) {
+        return new MarshalerRect(managedType, nativeType);
+    }
+
+    @Override
+    public boolean isTypeMappingSupported(TypeReference<Rect> managedType, int nativeType) {
+        return nativeType == TYPE_INT32 && (Rect.class.equals(managedType.getType()));
+    }
+
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableReprocessFormatsMap.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableReprocessFormatsMap.java
new file mode 100644
index 0000000..3025cb4
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableReprocessFormatsMap.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.marshal.impl;
+
+import android.hardware.camera2.ReprocessFormatsMap;
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+
+/**
+ * Marshaler for {@code android.scaler.availableInputOutputFormatsMap} custom class
+ * {@link ReprocessFormatsMap}
+ */
+public class MarshalQueryableReprocessFormatsMap
+        implements MarshalQueryable<ReprocessFormatsMap> {
+
+    private class MarshalerReprocessFormatsMap extends Marshaler<ReprocessFormatsMap> {
+        protected MarshalerReprocessFormatsMap(
+                TypeReference<ReprocessFormatsMap> typeReference, int nativeType) {
+            super(MarshalQueryableReprocessFormatsMap.this, typeReference, nativeType);
+        }
+
+        @Override
+        public void marshal(ReprocessFormatsMap value, ByteBuffer buffer) {
+            /*
+             * // writing (static example, DNG+ZSL)
+             * int32_t[] contents = {
+             *   RAW_OPAQUE, 3, RAW16, YUV_420_888, BLOB,
+             *   RAW16, 2, YUV_420_888, BLOB,
+             *   ...,
+             *   INPUT_FORMAT, OUTPUT_FORMAT_COUNT, [OUTPUT_0, OUTPUT_1, ..., OUTPUT_FORMAT_COUNT-1]
+             * };
+             */
+            int[] inputs = value.getInputs();
+            for (int input : inputs) {
+                // INPUT_FORMAT
+                buffer.putInt(input);
+
+                int[] outputs = value.getOutputs(input);
+                // OUTPUT_FORMAT_COUNT
+                buffer.putInt(outputs.length);
+
+                // [OUTPUT_0, OUTPUT_1, ..., OUTPUT_FORMAT_COUNT-1]
+                for (int output : outputs) {
+                    buffer.putInt(output);
+                }
+            }
+        }
+
+        @Override
+        public ReprocessFormatsMap unmarshal(ByteBuffer buffer) {
+            int len = buffer.remaining() / SIZEOF_INT32;
+            if (buffer.remaining() % SIZEOF_INT32 != 0) {
+                throw new AssertionError("ReprocessFormatsMap was not TYPE_INT32");
+            }
+
+            int[] entries = new int[len];
+
+            IntBuffer intBuffer = buffer.asIntBuffer();
+            intBuffer.get(entries);
+
+            // TODO: consider moving rest of parsing code from ReprocessFormatsMap to here
+
+            return new ReprocessFormatsMap(entries);
+        }
+
+        @Override
+        public int getNativeSize() {
+            return NATIVE_SIZE_DYNAMIC;
+        }
+
+        @Override
+        public int calculateMarshalSize(ReprocessFormatsMap value) {
+            /*
+             * // writing (static example, DNG+ZSL)
+             * int32_t[] contents = {
+             *   RAW_OPAQUE, 3, RAW16, YUV_420_888, BLOB,
+             *   RAW16, 2, YUV_420_888, BLOB,
+             *   ...,
+             *   INPUT_FORMAT, OUTPUT_FORMAT_COUNT, [OUTPUT_0, OUTPUT_1, ..., OUTPUT_FORMAT_COUNT-1]
+             * };
+             */
+            int length = 0;
+
+            int[] inputs = value.getInputs();
+            for (int input : inputs) {
+
+                length += 1; // INPUT_FORMAT
+                length += 1; // OUTPUT_FORMAT_COUNT
+
+                int[] outputs = value.getOutputs(input);
+                length += outputs.length; // [OUTPUT_0, OUTPUT_1, ..., OUTPUT_FORMAT_COUNT-1]
+            }
+
+            return length * SIZEOF_INT32;
+        }
+    }
+
+    @Override
+    public Marshaler<ReprocessFormatsMap> createMarshaler(
+            TypeReference<ReprocessFormatsMap> managedType, int nativeType) {
+        return new MarshalerReprocessFormatsMap(managedType, nativeType);
+    }
+
+    @Override
+    public boolean isTypeMappingSupported(TypeReference<ReprocessFormatsMap> managedType,
+            int nativeType) {
+        return nativeType == TYPE_INT32 && managedType.getType().equals(ReprocessFormatsMap.class);
+    }
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java
new file mode 100644
index 0000000..93c0e92
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.RggbChannelVector;
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+
+import java.nio.ByteBuffer;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+/**
+ * Marshal {@link RggbChannelVector} to/from {@link #TYPE_FLOAT} {@code x 4}
+ */
+public class MarshalQueryableRggbChannelVector implements MarshalQueryable<RggbChannelVector> {
+    private static final int SIZE = SIZEOF_FLOAT * RggbChannelVector.COUNT;
+
+    private class MarshalerRggbChannelVector extends Marshaler<RggbChannelVector> {
+        protected MarshalerRggbChannelVector(TypeReference<RggbChannelVector> typeReference,
+                int nativeType) {
+            super(MarshalQueryableRggbChannelVector.this, typeReference, nativeType);
+        }
+
+        @Override
+        public void marshal(RggbChannelVector value, ByteBuffer buffer) {
+            for (int i = 0; i < RggbChannelVector.COUNT; ++i) {
+                buffer.putFloat(value.getComponent(i));
+            }
+        }
+
+        @Override
+        public RggbChannelVector unmarshal(ByteBuffer buffer) {
+            float red = buffer.getFloat();
+            float gEven = buffer.getFloat();
+            float gOdd = buffer.getFloat();
+            float blue = buffer.getFloat();
+
+            return new RggbChannelVector(red, gEven, gOdd, blue);
+        }
+
+        @Override
+        public int getNativeSize() {
+            return SIZE;
+        }
+    }
+
+    @Override
+    public Marshaler<RggbChannelVector> createMarshaler(
+            TypeReference<RggbChannelVector> managedType, int nativeType) {
+        return new MarshalerRggbChannelVector(managedType, nativeType);
+    }
+
+    @Override
+    public boolean isTypeMappingSupported(
+            TypeReference<RggbChannelVector> managedType, int nativeType) {
+        return nativeType == TYPE_FLOAT && (RggbChannelVector.class.equals(managedType.getType()));
+    }
+
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java
new file mode 100644
index 0000000..6a73bee
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.marshal.impl;
+
+import android.hardware.camera2.Size;
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Marshal {@link Size} to/from {@code TYPE_INT32}
+ */
+public class MarshalQueryableSize implements MarshalQueryable<Size> {
+    private static final int SIZE = SIZEOF_INT32 * 2;
+
+    private class MarshalerSize extends Marshaler<Size> {
+        protected MarshalerSize(TypeReference<Size> typeReference, int nativeType) {
+            super(MarshalQueryableSize.this, typeReference, nativeType);
+        }
+
+        @Override
+        public void marshal(Size value, ByteBuffer buffer) {
+            buffer.putInt(value.getWidth());
+            buffer.putInt(value.getHeight());
+        }
+
+        @Override
+        public Size unmarshal(ByteBuffer buffer) {
+            int width = buffer.getInt();
+            int height = buffer.getInt();
+
+            return new Size(width, height);
+        }
+
+        @Override
+        public int getNativeSize() {
+            return SIZE;
+        }
+    }
+
+    @Override
+    public Marshaler<Size> createMarshaler(TypeReference<Size> managedType, int nativeType) {
+        return new MarshalerSize(managedType, nativeType);
+    }
+
+    @Override
+    public boolean isTypeMappingSupported(TypeReference<Size> managedType, int nativeType) {
+        return nativeType == TYPE_INT32 && (Size.class.equals(managedType.getType()));
+    }
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSizeF.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSizeF.java
new file mode 100644
index 0000000..b60a46d
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSizeF.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+import android.util.SizeF;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Marshal {@link SizeF} to/from {@code TYPE_FLOAT}
+ */
+public class MarshalQueryableSizeF implements MarshalQueryable<SizeF> {
+
+    private static final int SIZE = SIZEOF_FLOAT * 2;
+
+    private class MarshalerSizeF extends Marshaler<SizeF> {
+
+        protected MarshalerSizeF(TypeReference<SizeF> typeReference, int nativeType) {
+            super(MarshalQueryableSizeF.this, typeReference, nativeType);
+        }
+
+        @Override
+        public void marshal(SizeF value, ByteBuffer buffer) {
+            buffer.putFloat(value.getWidth());
+            buffer.putFloat(value.getHeight());
+        }
+
+        @Override
+        public SizeF unmarshal(ByteBuffer buffer) {
+            float width = buffer.getFloat();
+            float height = buffer.getFloat();
+
+            return new SizeF(width, height);
+        }
+
+        @Override
+        public int getNativeSize() {
+            return SIZE;
+        }
+    }
+
+    @Override
+    public Marshaler<SizeF> createMarshaler(
+            TypeReference<SizeF> managedType, int nativeType) {
+        return new MarshalerSizeF(managedType, nativeType);
+    }
+
+    @Override
+    public boolean isTypeMappingSupported(TypeReference<SizeF> managedType, int nativeType) {
+        return nativeType == TYPE_FLOAT && (SizeF.class.equals(managedType.getType()));
+    }
+}
+
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfiguration.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfiguration.java
new file mode 100644
index 0000000..6a4e821
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfiguration.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.StreamConfiguration;
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Marshaler for {@code android.scaler.availableStreamConfigurations} custom class
+ * {@link StreamConfiguration}
+ *
+ * <p>Data is stored as {@code (format, width, height, input?)} tuples (int32).</p>
+ */
+public class MarshalQueryableStreamConfiguration
+        implements MarshalQueryable<StreamConfiguration> {
+    private static final int SIZE = SIZEOF_INT32 * 4;
+
+    private class MarshalerStreamConfiguration extends Marshaler<StreamConfiguration> {
+        protected MarshalerStreamConfiguration(TypeReference<StreamConfiguration> typeReference,
+                int nativeType) {
+            super(MarshalQueryableStreamConfiguration.this, typeReference, nativeType);
+        }
+
+        @Override
+        public void marshal(StreamConfiguration value, ByteBuffer buffer) {
+            buffer.putInt(value.getFormat());
+            buffer.putInt(value.getWidth());
+            buffer.putInt(value.getHeight());
+            buffer.putInt(value.isInput() ? 1 : 0);
+        }
+
+        @Override
+        public StreamConfiguration unmarshal(ByteBuffer buffer) {
+            int format = buffer.getInt();
+            int width = buffer.getInt();
+            int height = buffer.getInt();
+            boolean input = buffer.getInt() != 0;
+
+            return new StreamConfiguration(format, width, height, input);
+        }
+
+        @Override
+        public int getNativeSize() {
+            return SIZE;
+        }
+
+    }
+
+    @Override
+    public Marshaler<StreamConfiguration> createMarshaler(
+            TypeReference<StreamConfiguration> managedType, int nativeType) {
+        return new MarshalerStreamConfiguration(managedType, nativeType);
+    }
+
+    @Override
+    public boolean isTypeMappingSupported(TypeReference<StreamConfiguration> managedType,
+            int nativeType) {
+        return nativeType == TYPE_INT32 && managedType.getType().equals(StreamConfiguration.class);
+    }
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfigurationDuration.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfigurationDuration.java
new file mode 100644
index 0000000..c3d564e
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfigurationDuration.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.marshal.impl;
+
+import android.hardware.camera2.StreamConfigurationDuration;
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Marshaler for custom class {@link StreamConfigurationDuration} for min-frame and stall durations.
+ *
+ * <p>
+ * Data is stored as {@code (format, width, height, durationNs)} tuples (int64).
+ * </p>
+ */
+public class MarshalQueryableStreamConfigurationDuration
+        implements MarshalQueryable<StreamConfigurationDuration> {
+
+    private static final int SIZE = SIZEOF_INT64 * 4;
+    /**
+     * Values and-ed with this will do an unsigned int to signed long conversion;
+     * in other words the sign bit from the int will not be extended.
+     * */
+    private static final long MASK_UNSIGNED_INT = 0x00000000ffffffffL;
+
+    private class MarshalerStreamConfigurationDuration
+        extends Marshaler<StreamConfigurationDuration> {
+
+        protected MarshalerStreamConfigurationDuration(
+                TypeReference<StreamConfigurationDuration> typeReference, int nativeType) {
+            super(MarshalQueryableStreamConfigurationDuration.this, typeReference, nativeType);
+        }
+
+        @Override
+        public void marshal(StreamConfigurationDuration value, ByteBuffer buffer) {
+            buffer.putLong(value.getFormat() & MASK_UNSIGNED_INT); // unsigned int -> long
+            buffer.putLong(value.getWidth());
+            buffer.putLong(value.getHeight());
+            buffer.putLong(value.getDuration());
+        }
+
+        @Override
+        public StreamConfigurationDuration unmarshal(ByteBuffer buffer) {
+            int format = (int)buffer.getLong();
+            int width = (int)buffer.getLong();
+            int height = (int)buffer.getLong();
+            long durationNs = buffer.getLong();
+
+            return new StreamConfigurationDuration(format, width, height, durationNs);
+        }
+
+        @Override
+        public int getNativeSize() {
+            return SIZE;
+        }
+    }
+
+    @Override
+    public Marshaler<StreamConfigurationDuration> createMarshaler(
+            TypeReference<StreamConfigurationDuration> managedType, int nativeType) {
+        return new MarshalerStreamConfigurationDuration(managedType, nativeType);
+    }
+
+    @Override
+    public boolean isTypeMappingSupported(TypeReference<StreamConfigurationDuration> managedType,
+            int nativeType) {
+        return nativeType == TYPE_INT64 &&
+                (StreamConfigurationDuration.class.equals(managedType.getType()));
+    }
+
+}
\ No newline at end of file
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableString.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableString.java
new file mode 100644
index 0000000..bf518bb
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableString.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.marshal.impl;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+import android.util.Log;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+
+/**
+ * Marshal {@link String} to/from {@link #TYPE_BYTE}.
+ */
+public class MarshalQueryableString implements MarshalQueryable<String> {
+
+    private static final String TAG = MarshalQueryableString.class.getSimpleName();
+    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+
+    private static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
+    private static final byte NUL = (byte)'\0'; // used as string terminator
+
+    private class MarshalerString extends Marshaler<String> {
+
+        protected MarshalerString(TypeReference<String> typeReference, int nativeType) {
+            super(MarshalQueryableString.this, typeReference, nativeType);
+        }
+
+        @Override
+        public void marshal(String value, ByteBuffer buffer) {
+            byte[] arr = value.getBytes(UTF8_CHARSET);
+
+            buffer.put(arr);
+            buffer.put(NUL); // metadata strings are NUL-terminated
+        }
+
+        @Override
+        public int calculateMarshalSize(String value) {
+            byte[] arr = value.getBytes(UTF8_CHARSET);
+
+            return arr.length + 1; // metadata strings are NUL-terminated
+        }
+
+        @Override
+        public String unmarshal(ByteBuffer buffer) {
+            buffer.mark(); // save the current position
+
+            boolean foundNull = false;
+            int stringLength = 0;
+            while (buffer.hasRemaining()) {
+                if (buffer.get() == NUL) {
+                    foundNull = true;
+                    break;
+                }
+
+                stringLength++;
+            }
+
+            if (VERBOSE) {
+                Log.v(TAG,
+                        "unmarshal - scanned " + stringLength + " characters; found null? "
+                                + foundNull);
+            }
+
+            if (!foundNull) {
+                throw new UnsupportedOperationException("Strings must be null-terminated");
+            }
+
+            buffer.reset(); // go back to the previously marked position
+
+            byte[] strBytes = new byte[stringLength + 1];
+            buffer.get(strBytes, /*dstOffset*/0, stringLength + 1); // including null character
+
+            // not including null character
+            return new String(strBytes, /*offset*/0, stringLength, UTF8_CHARSET);
+        }
+
+        @Override
+        public int getNativeSize() {
+            return NATIVE_SIZE_DYNAMIC;
+        }
+    }
+
+    @Override
+    public Marshaler<String> createMarshaler(
+            TypeReference<String> managedType, int nativeType) {
+        return new MarshalerString(managedType, nativeType);
+    }
+
+    @Override
+    public boolean isTypeMappingSupported(TypeReference<String> managedType, int nativeType) {
+        return nativeType == TYPE_BYTE && String.class.equals(managedType.getType());
+    }
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/package.html b/core/java/android/hardware/camera2/marshal/impl/package.html
new file mode 100644
index 0000000..783d0a1
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/package.html
@@ -0,0 +1,3 @@
+<body>
+{@hide}
+</body>
diff --git a/core/java/android/hardware/camera2/marshal/package.html b/core/java/android/hardware/camera2/marshal/package.html
new file mode 100644
index 0000000..783d0a1
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/package.html
@@ -0,0 +1,3 @@
+<body>
+{@hide}
+</body>
diff --git a/core/java/android/hardware/camera2/utils/HashCodeHelpers.java b/core/java/android/hardware/camera2/utils/HashCodeHelpers.java
new file mode 100644
index 0000000..b980549
--- /dev/null
+++ b/core/java/android/hardware/camera2/utils/HashCodeHelpers.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.utils;
+
+/**
+ * Provide hashing functions using the Modified Bernstein hash
+ */
+public final class HashCodeHelpers {
+
+    /**
+     * Hash every element uniformly using the Modified Bernstein hash.
+     *
+     * <p>Useful to implement a {@link Object#hashCode} for uniformly distributed data.</p>
+     *
+     * @param array a non-{@code null} array of integers
+     *
+     * @return the numeric hash code
+     */
+    public static int hashCode(int[] array) {
+        if (array == null) {
+            return 0;
+        }
+
+        /*
+         *  Note that we use 31 here instead of 33 since it's preferred in Effective Java
+         *  and used elsewhere in the runtime (e.g. Arrays#hashCode)
+         *
+         *  That being said 33 and 31 are nearly identical in terms of their usefulness
+         *  according to http://svn.apache.org/repos/asf/apr/apr/trunk/tables/apr_hash.c
+         */
+        int h = 1;
+        for (int x : array) {
+            // Strength reduction; in case the compiler has illusions about divisions being faster
+            h = ((h << 5) - h) ^ x; // (h * 31) XOR x
+        }
+
+        return h;
+    }
+
+    /**
+     * Hash every element uniformly using the Modified Bernstein hash.
+     *
+     * <p>Useful to implement a {@link Object#hashCode} for uniformly distributed data.</p>
+     *
+     * @param array a non-{@code null} array of floats
+     *
+     * @return the numeric hash code
+     */
+    public static int hashCode(float[] array) {
+        if (array == null) {
+            return 0;
+        }
+
+        int h = 1;
+        for (float f : array) {
+            int x = Float.floatToIntBits(f);
+            h = ((h << 5) - h) ^ x; // (h * 31) XOR x
+        }
+
+        return h;
+    }
+
+    /**
+     * Hash every element uniformly using the Modified Bernstein hash.
+     *
+     * <p>Useful to implement a {@link Object#hashCode} for uniformly distributed data.</p>
+     *
+     * @param array a non-{@code null} array of objects
+     *
+     * @return the numeric hash code
+     */
+    public static <T> int hashCode(T[] array) {
+        if (array == null) {
+            return 0;
+        }
+
+        int h = 1;
+        for (T o : array) {
+            int x = (o == null) ? 0 : o.hashCode();
+            h = ((h << 5) - h) ^ x; // (h * 31) XOR x
+        }
+
+        return h;
+    }
+
+    public static <T> int hashCode(T a) {
+        return (a == null) ? 0 : a.hashCode();
+    }
+
+    public static <T> int hashCode(T a, T b) {
+        int h = hashCode(a);
+
+        int x = (b == null) ? 0 : b.hashCode();
+        h = ((h << 5) - h) ^ x; // (h * 31) XOR x
+
+        return h;
+    }
+
+    public static <T> int hashCode(T a, T b, T c) {
+        int h = hashCode(a, b);
+
+        int x = (a == null) ? 0 : a.hashCode();
+        h = ((h << 5) - h) ^ x; // (h * 31) XOR x
+
+        return h;
+    }
+
+    public static int hashCode(int x) {
+        return hashCode(new int[] { x } );
+    }
+
+    public static int hashCode(int x, int y) {
+        return hashCode(new int[] { x, y } );
+    }
+
+    public static int hashCode(int x, int y, int z) {
+        return hashCode(new int[] { x, y, z } );
+    }
+
+    public static int hashCode(int x, int y, int z, int w) {
+        return hashCode(new int[] { x, y, z, w } );
+    }
+
+    public static int hashCode(int x, int y, int z, int w, int t) {
+        return hashCode(new int[] { x, y, z, w, t } );
+    }
+
+
+}
diff --git a/core/java/android/hardware/camera2/utils/TypeReference.java b/core/java/android/hardware/camera2/utils/TypeReference.java
new file mode 100644
index 0000000..d0c919c
--- /dev/null
+++ b/core/java/android/hardware/camera2/utils/TypeReference.java
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.utils;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+
+import static com.android.internal.util.Preconditions.*;
+
+/**
+ * Super type token; allows capturing generic types at runtime by forcing them to be reified.
+ *
+ * <p>Usage example: <pre>{@code
+ *      // using anonymous classes (preferred)
+ *      TypeReference&lt;Integer> intToken = new TypeReference&lt;Integer>() {{ }};
+ *
+ *      // using named classes
+ *      class IntTypeReference extends TypeReference&lt;Integer> {...}
+ *      TypeReference&lt;Integer> intToken = new IntTypeReference();
+ * }</p></pre>
+ *
+ * <p>Unlike the reference implementation, this bans nested TypeVariables; that is all
+ * dynamic types must equal to the static types.</p>
+ *
+ * <p>See <a href="http://gafter.blogspot.com/2007/05/limitation-of-super-type-tokens.html">
+ * http://gafter.blogspot.com/2007/05/limitation-of-super-type-tokens.html</a>
+ * for more details.</p>
+ */
+public abstract class TypeReference<T> {
+    private final Type mType;
+
+    /**
+     * Create a new type reference for {@code T}.
+     *
+     * @throws IllegalArgumentException if {@code T}'s actual type contains a type variable
+     *
+     * @see TypeReference
+     */
+    protected TypeReference() {
+        ParameterizedType thisType = (ParameterizedType)getClass().getGenericSuperclass();
+
+        // extract the "T" from TypeReference<T>
+        mType = thisType.getActualTypeArguments()[0];
+
+        /*
+         * Prohibit type references with type variables such as
+         *
+         *    class GenericListToken<T> extends TypeReference<List<T>>
+         *
+         * Since the "T" there is not known without an instance of T, type equality would
+         * consider *all* Lists equal regardless of T. Allowing this would defeat
+         * some of the type safety of a type reference.
+         */
+        if (containsTypeVariable(mType)) {
+            throw new IllegalArgumentException(
+                    "Including a type variable in a type reference is not allowed");
+        }
+    }
+
+    /**
+     * Return the dynamic {@link Type} corresponding to the captured type {@code T}.
+     */
+    public Type getType() {
+        return mType;
+    }
+
+    private TypeReference(Type type) {
+        mType = type;
+
+        if (containsTypeVariable(mType)) {
+            throw new IllegalArgumentException(
+                    "Including a type variable in a type reference is not allowed");
+        }
+    }
+
+    private static class SpecializedTypeReference<T> extends TypeReference<T> {
+        public SpecializedTypeReference(Class<T> klass) {
+            super(klass);
+        }
+    }
+
+    @SuppressWarnings("rawtypes")
+    private static class SpecializedBaseTypeReference extends TypeReference {
+        public SpecializedBaseTypeReference(Type type) {
+            super(type);
+        }
+    }
+
+    /**
+     * Create a specialized type reference from a dynamic class instance,
+     * bypassing the standard compile-time checks.
+     *
+     * <p>As with a regular type reference, the {@code klass} must not contain
+     * any type variables.</p>
+     *
+     * @param klass a non-{@code null} {@link Class} instance
+     *
+     * @return a type reference which captures {@code T} at runtime
+     *
+     * @throws IllegalArgumentException if {@code T} had any type variables
+     */
+    public static <T> TypeReference<T> createSpecializedTypeReference(Class<T> klass) {
+        return new SpecializedTypeReference<T>(klass);
+    }
+
+    /**
+     * Create a specialized type reference from a dynamic {@link Type} instance,
+     * bypassing the standard compile-time checks.
+     *
+     * <p>As with a regular type reference, the {@code type} must not contain
+     * any type variables.</p>
+     *
+     * @param type a non-{@code null} {@link Type} instance
+     *
+     * @return a type reference which captures {@code T} at runtime
+     *
+     * @throws IllegalArgumentException if {@code type} had any type variables
+     */
+    public static TypeReference<?> createSpecializedTypeReference(Type type) {
+        return new SpecializedBaseTypeReference(type);
+    }
+
+    /**
+     * Returns the raw type of T.
+     *
+     * <p><ul>
+     * <li>If T is a Class itself, T itself is returned.
+     * <li>If T is a ParameterizedType, the raw type of the parameterized type is returned.
+     * <li>If T is a GenericArrayType, the returned type is the corresponding array class.
+     * For example: {@code List<Integer>[]} => {@code List[]}.
+     * <li>If T is a type variable or a wildcard type, the raw type of the first upper bound is
+     * returned. For example: {@code <X extends Foo>} => {@code Foo}.
+     * </ul>
+     *
+     * @return the raw type of {@code T}
+     */
+    @SuppressWarnings("unchecked")
+    public final Class<? super T> getRawType() {
+        return (Class<? super T>)getRawType(mType);
+    }
+
+    private static final Class<?> getRawType(Type type) {
+        if (type == null) {
+            throw new NullPointerException("type must not be null");
+        }
+
+        if (type instanceof Class<?>) {
+            return (Class<?>)type;
+        } else if (type instanceof ParameterizedType) {
+            return (Class<?>)(((ParameterizedType)type).getRawType());
+        } else if (type instanceof GenericArrayType) {
+            return getArrayClass(getRawType(((GenericArrayType)type).getGenericComponentType()));
+        } else if (type instanceof WildcardType) {
+            // Should be at most 1 upper bound, but treat it like an array for simplicity
+            return getRawType(((WildcardType) type).getUpperBounds());
+        } else if (type instanceof TypeVariable) {
+            throw new AssertionError("Type variables are not allowed in type references");
+        } else {
+            // Impossible
+            throw new AssertionError("Unhandled branch to get raw type for type " + type);
+        }
+    }
+
+    private static final Class<?> getRawType(Type[] types) {
+        if (types == null) {
+            return null;
+        }
+
+        for (Type type : types) {
+            Class<?> klass = getRawType(type);
+            if (klass !=  null) {
+                return klass;
+            }
+        }
+
+        return null;
+    }
+
+    private static final Class<?> getArrayClass(Class<?> componentType) {
+        return Array.newInstance(componentType, 0).getClass();
+    }
+
+    /**
+     * Get the component type, e.g. {@code T} from {@code T[]}.
+     *
+     * @return component type, or {@code null} if {@code T} is not an array
+     */
+    public TypeReference<?> getComponentType() {
+        Type componentType = getComponentType(mType);
+
+        return (componentType != null) ?
+                createSpecializedTypeReference(componentType) :
+                null;
+    }
+
+    private static Type getComponentType(Type type) {
+        checkNotNull(type, "type must not be null");
+
+        if (type instanceof Class<?>) {
+            return ((Class<?>) type).getComponentType();
+        } else if (type instanceof ParameterizedType) {
+            return null;
+        } else if (type instanceof GenericArrayType) {
+            return ((GenericArrayType)type).getGenericComponentType();
+        } else if (type instanceof WildcardType) {
+            // Should be at most 1 upper bound, but treat it like an array for simplicity
+            throw new UnsupportedOperationException("TODO: support wild card components");
+        } else if (type instanceof TypeVariable) {
+            throw new AssertionError("Type variables are not allowed in type references");
+        } else {
+            // Impossible
+            throw new AssertionError("Unhandled branch to get component type for type " + type);
+        }
+    }
+
+    /**
+     * Compare two objects for equality.
+     *
+     * <p>A TypeReference is only equal to another TypeReference if their captured type {@code T}
+     * is also equal.</p>
+     */
+    @Override
+    public boolean equals(Object o) {
+        // Note that this comparison could inaccurately return true when comparing types
+        // with nested type variables; therefore we ban type variables in the constructor.
+        return o instanceof TypeReference<?> && mType.equals(((TypeReference<?>)o).mType);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return mType.hashCode();
+    }
+
+    /**
+     * Check if the {@code type} contains a {@link TypeVariable} recursively.
+     *
+     * <p>Intuitively, a type variable is a type in a type expression that refers to a generic
+     * type which is not known at the definition of the expression (commonly seen when
+     * type parameters are used, e.g. {@code class Foo<T>}).</p>
+     *
+     * <p>See <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.4">
+     * http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.4</a>
+     * for a more formal definition of a type variable</p>.
+     *
+     * @param type a type object ({@code null} is allowed)
+     * @return {@code true} if there were nested type variables; {@code false} otherwise
+     */
+    public static boolean containsTypeVariable(Type type) {
+        if (type == null) {
+            // Trivially false
+            return false;
+        } else if (type instanceof TypeVariable<?>) {
+            /*
+             * T -> trivially true
+             */
+            return true;
+        } else if (type instanceof Class<?>) {
+            /*
+             * class Foo -> no type variable
+             * class Foo<T> - has a type variable
+             *
+             * This also covers the case of class Foo<T> extends ... / implements ...
+             * since everything on the right hand side would either include a type variable T
+             * or have no type variables.
+             */
+            Class<?> klass = (Class<?>)type;
+
+            // Empty array => class is not generic
+            if (klass.getTypeParameters().length != 0) {
+                return true;
+            } else {
+                // Does the outer class(es) contain any type variables?
+
+                /*
+                 * class Outer<T> {
+                 *   class Inner {
+                 *      T field;
+                 *   }
+                 * }
+                 *
+                 * In this case 'Inner' has no type parameters itself, but it still has a type
+                 * variable as part of the type definition.
+                 */
+                return containsTypeVariable(klass.getDeclaringClass());
+            }
+        } else if (type instanceof ParameterizedType) {
+            /*
+             * This is the "Foo<T1, T2, T3, ... Tn>" in the scope of a
+             *
+             *      // no type variables here, T1-Tn are known at this definition
+             *      class X extends Foo<T1, T2, T3, ... Tn>
+             *
+             *      // T1 is a type variable, T2-Tn are known at this definition
+             *      class X<T1> extends Foo<T1, T2, T3, ... Tn>
+             */
+            ParameterizedType p = (ParameterizedType) type;
+
+            // This needs to be recursively checked
+            for (Type arg : p.getActualTypeArguments()) {
+                if (containsTypeVariable(arg)) {
+                    return true;
+                }
+            }
+
+            return false;
+        } else if (type instanceof WildcardType) {
+            WildcardType wild = (WildcardType) type;
+
+            /*
+             * This is is the "?" inside of a
+             *
+             *       Foo<?> --> unbounded; trivially no type variables
+             *       Foo<? super T> --> lower bound; does T have a type variable?
+             *       Foo<? extends T> --> upper bound; does T have a type variable?
+             */
+
+            /*
+             *  According to JLS 4.5.1
+             *  (http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.5.1):
+             *
+             *  - More than 1 lower/upper bound is illegal
+             *  - Both a lower and upper bound is illegal
+             *
+             *  However, we use this 'array OR array' approach for readability
+             */
+            return containsTypeVariable(wild.getLowerBounds()) ||
+                    containsTypeVariable(wild.getUpperBounds());
+        }
+
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("TypeReference<");
+        toString(getType(), builder);
+        builder.append(">");
+
+        return builder.toString();
+    }
+
+    private static void toString(Type type, StringBuilder out) {
+        if (type == null) {
+            return;
+        } else if (type instanceof TypeVariable<?>) {
+            // T
+            out.append(((TypeVariable<?>)type).getName());
+        } else if (type instanceof Class<?>) {
+            Class<?> klass = (Class<?>)type;
+
+            out.append(klass.getName());
+            toString(klass.getTypeParameters(), out);
+        } else if (type instanceof ParameterizedType) {
+             // "Foo<T1, T2, T3, ... Tn>"
+            ParameterizedType p = (ParameterizedType) type;
+
+            out.append(((Class<?>)p.getRawType()).getName());
+            toString(p.getActualTypeArguments(), out);
+        } else if (type instanceof GenericArrayType) {
+            GenericArrayType gat = (GenericArrayType)type;
+
+            toString(gat.getGenericComponentType(), out);
+            out.append("[]");
+        } else { // WildcardType, BoundedType
+            // TODO:
+            out.append(type.toString());
+        }
+    }
+
+    private static void toString(Type[] types, StringBuilder out) {
+        if (types == null) {
+            return;
+        } else if (types.length == 0) {
+            return;
+        }
+
+        out.append("<");
+
+        for (int i = 0; i < types.length; ++i) {
+            toString(types[i], out);
+            if (i != types.length - 1) {
+                out.append(", ");
+            }
+        }
+
+        out.append(">");
+    }
+
+    /**
+     * Check if any of the elements in this array contained a type variable.
+     *
+     * <p>Empty and null arrays trivially have no type variables.</p>
+     *
+     * @param typeArray an array ({@code null} is ok) of types
+     * @return true if any elements contained a type variable; false otherwise
+     */
+    private static boolean containsTypeVariable(Type[] typeArray) {
+        if (typeArray == null) {
+            return false;
+        }
+
+        for (Type type : typeArray) {
+            if (containsTypeVariable(type)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index cec90cd..e58c54d 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -156,6 +156,9 @@
         // If true, enables automatic brightness control.
         public boolean useAutoBrightness;
 
+        //If true, scales the brightness to half of desired.
+        public boolean lowPowerMode;
+
         // If true, prevents the screen from completely turning on if it is currently off.
         // The display does not enter a "ready" state if this flag is true and screen on is
         // blocked.  The window manager policy blocks screen on while it prepares the keyguard to
@@ -203,6 +206,7 @@
             screenAutoBrightnessAdjustment = other.screenAutoBrightnessAdjustment;
             useAutoBrightness = other.useAutoBrightness;
             blockScreenOn = other.blockScreenOn;
+            lowPowerMode = other.lowPowerMode;
         }
 
         @Override
@@ -218,7 +222,8 @@
                     && screenBrightness == other.screenBrightness
                     && screenAutoBrightnessAdjustment == other.screenAutoBrightnessAdjustment
                     && useAutoBrightness == other.useAutoBrightness
-                    && blockScreenOn == other.blockScreenOn;
+                    && blockScreenOn == other.blockScreenOn
+                    && lowPowerMode == other.lowPowerMode;
         }
 
         @Override
@@ -233,7 +238,8 @@
                     + ", screenBrightness=" + screenBrightness
                     + ", screenAutoBrightnessAdjustment=" + screenAutoBrightnessAdjustment
                     + ", useAutoBrightness=" + useAutoBrightness
-                    + ", blockScreenOn=" + blockScreenOn;
+                    + ", blockScreenOn=" + blockScreenOn
+                    + ", lowPowerMode=" + lowPowerMode;
         }
     }
 
diff --git a/core/java/android/hardware/hdmi/HdmiCec.java b/core/java/android/hardware/hdmi/HdmiCec.java
index 8578a32..7213c78 100644
--- a/core/java/android/hardware/hdmi/HdmiCec.java
+++ b/core/java/android/hardware/hdmi/HdmiCec.java
@@ -85,7 +85,7 @@
     public static final int ADDR_RESERVED_2 = 13;
 
     /** Logical address for TV other than the one assigned with {@link #ADDR_TV} */
-    public static final int ADDR_FREE_USE = 14;
+    public static final int ADDR_SPECIFIC_USE = 14;
 
     /** Logical address for devices to which address cannot be allocated */
     public static final int ADDR_UNREGISTERED = 15;
@@ -160,6 +160,8 @@
     public static final int MESSAGE_SET_EXTERNAL_TIMER = 0xA2;
     public static final int MESSAGE_ABORT = 0xFF;
 
+    public static final int UNKNOWN_VENDOR_ID = 0xFFFFFF;
+
     public static final int POWER_STATUS_UNKNOWN = -1;
     public static final int POWER_STATUS_ON = 0;
     public static final int POWER_STATUS_STANDBY = 1;
@@ -179,6 +181,7 @@
         DEVICE_RECORDER,  // ADDR_RECORDER_3
         DEVICE_TUNER,  // ADDR_TUNER_4
         DEVICE_PLAYBACK,  // ADDR_PLAYBACK_3
+        DEVICE_TV,  // ADDR_SPECIFIC_USE
     };
 
     private static final String[] DEFAULT_NAMES = {
@@ -194,6 +197,7 @@
         "Recorder_3",
         "Tuner_4",
         "Playback_3",
+        "Secondary_TV",
     };
 
     private HdmiCec() { }  // Prevents instantiation.
@@ -221,9 +225,7 @@
      * @return true if the given address is valid
      */
     public static boolean isValidAddress(int address) {
-        // TODO: We leave out the address 'free use(14)' for now. Check this later
-        //       again to make sure it is a valid address for communication.
-        return (ADDR_TV <= address && address <= ADDR_PLAYBACK_3);
+        return (ADDR_TV <= address && address <= ADDR_SPECIFIC_USE);
     }
 
     /**
diff --git a/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
new file mode 100644
index 0000000..9698445
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.hdmi;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A class to encapsulate device information for HDMI-CEC. This container
+ * include basic information such as logical address, physical address and
+ * device type, and additional information like vendor id and osd name.
+ */
+public final class HdmiCecDeviceInfo implements Parcelable {
+    // Logical address, phsical address, device type, vendor id and display name
+    // are immutable value.
+    private final int mLogicalAddress;
+    private final int mPhysicalAddress;
+    private final int mDeviceType;
+    private final int mVendorId;
+    private final String mDisplayName;
+
+
+    /**
+     * A helper class to deserialize {@link HdmiCecDeviceInfo} for a parcel.
+     */
+    public static final Parcelable.Creator<HdmiCecDeviceInfo> CREATOR =
+            new Parcelable.Creator<HdmiCecDeviceInfo>() {
+                @Override
+                public HdmiCecDeviceInfo createFromParcel(Parcel source) {
+                    int logicalAddress = source.readInt();
+                    int physicalAddress = source.readInt();
+                    int deviceType = source.readInt();
+                    int vendorId = source.readInt();
+                    String displayName = source.readString();
+                    return new HdmiCecDeviceInfo(logicalAddress, physicalAddress, deviceType,
+                            vendorId, displayName);
+                }
+
+                @Override
+                public HdmiCecDeviceInfo[] newArray(int size) {
+                    return new HdmiCecDeviceInfo[size];
+                }
+            };
+
+    /**
+     * Constructor.
+     *
+     * @param logicalAddress logical address of HDMI-Cec device.
+     *                       For more details, refer {@link HdmiCec}
+     * @param physicalAddress physical address of HDMI-Cec device
+     * @param deviceType type of device. For more details, refer {@link HdmiCec}
+     * @param vendorId vendor id of device. It's used for vendor specific command
+     * @param displayName name of device
+     * @hide
+     */
+    public HdmiCecDeviceInfo(int logicalAddress, int physicalAddress, int deviceType,
+            int vendorId, String displayName) {
+        mLogicalAddress = logicalAddress;
+        mPhysicalAddress = physicalAddress;
+        mDeviceType = deviceType;
+        mDisplayName = displayName;
+        mVendorId = vendorId;
+    }
+
+    /**
+     * Return the logical address of the device. It can have 0-15 values.
+     * For more details, refer constants between {@link HdmiCec#ADDR_TV}
+     * and {@link HdmiCec#ADDR_UNREGISTERED}.
+     */
+    public int getLogicalAddress() {
+        return mLogicalAddress;
+    }
+
+    /**
+     * Return the physical address of the device.
+     */
+    public int getPhysicalAddress() {
+        return mPhysicalAddress;
+    }
+
+    /**
+     * Return type of the device. For more details, refer constants between
+     * {@link HdmiCec#DEVICE_TV} and {@link HdmiCec#DEVICE_INACTIVE}.
+     */
+    public int getDeviceType() {
+        return mDeviceType;
+    }
+
+    /**
+     * Return display (OSD) name of the device.
+     */
+    public String getDisplayName() {
+        return mDisplayName;
+    }
+
+    /**
+     * Return vendor id of the device. Vendor id is used to distinguish devices
+     * built by other manufactures. This is required for vendor-specific command
+     * on CEC standard.
+     */
+    public int getVendorId() {
+        return mVendorId;
+    }
+
+    /**
+     * Describe the kinds of special objects contained in this Parcelable's
+     * marshalled representation.
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Serialize this object into a {@link Parcel}.
+     *
+     * @param dest The Parcel in which the object should be written.
+     * @param flags Additional flags about how the object should be written.
+     *        May be 0 or {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE}.
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mLogicalAddress);
+        dest.writeInt(mPhysicalAddress);
+        dest.writeInt(mDeviceType);
+        dest.writeInt(mVendorId);
+        dest.writeString(mDisplayName);
+    }
+
+    @Override
+    public String toString() {
+        StringBuffer s = new StringBuffer();
+        s.append("logical_address: ").append(mLogicalAddress).append(", ");
+        s.append("physical_address: ").append(mPhysicalAddress).append(", ");
+        s.append("device_type: ").append(mDeviceType).append(", ");
+        s.append("vendor_id: ").append(mVendorId).append(", ");
+        s.append("display_name: ").append(mDisplayName);
+        return s.toString();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof HdmiCecDeviceInfo)) {
+            return false;
+        }
+
+        HdmiCecDeviceInfo other = (HdmiCecDeviceInfo) obj;
+        return mLogicalAddress == other.mLogicalAddress
+                && mPhysicalAddress == other.mPhysicalAddress
+                && mDeviceType == other.mDeviceType
+                && mVendorId == other.mVendorId
+                && mDisplayName.equals(other.mDisplayName);
+    }
+}
diff --git a/core/java/android/hardware/hdmi/HdmiCecMessage.java b/core/java/android/hardware/hdmi/HdmiCecMessage.java
index be94d97..ddaf870 100644
--- a/core/java/android/hardware/hdmi/HdmiCecMessage.java
+++ b/core/java/android/hardware/hdmi/HdmiCecMessage.java
@@ -19,6 +19,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import libcore.util.EmptyArray;
+
 import java.util.Arrays;
 
 /**
@@ -28,6 +30,8 @@
  */
 public final class HdmiCecMessage implements Parcelable {
 
+    public static final byte[] EMPTY_PARAM = EmptyArray.BYTE;
+
     private static final int MAX_MESSAGE_LENGTH = 16;
 
     private final int mSource;
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index 8437228..ed223d1 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -36,6 +36,7 @@
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.InputMethodSession;
+import android.view.inputmethod.CursorAnchorInfo;
 
 class IInputMethodSessionWrapper extends IInputMethodSession.Stub
         implements HandlerCaller.Callback {
@@ -46,6 +47,7 @@
     private static final int DO_UPDATE_EXTRACTED_TEXT = 67;
     private static final int DO_UPDATE_SELECTION = 90;
     private static final int DO_UPDATE_CURSOR = 95;
+    private static final int DO_UPDATE_CURSOR_ANCHOR_INFO = 99;
     private static final int DO_APP_PRIVATE_COMMAND = 100;
     private static final int DO_TOGGLE_SOFT_INPUT = 105;
     private static final int DO_FINISH_SESSION = 110;
@@ -108,6 +110,10 @@
                 mInputMethodSession.updateCursor((Rect)msg.obj);
                 return;
             }
+            case DO_UPDATE_CURSOR_ANCHOR_INFO: {
+                mInputMethodSession.updateCursorAnchorInfo((CursorAnchorInfo)msg.obj);
+                return;
+            }
             case DO_APP_PRIVATE_COMMAND: {
                 SomeArgs args = (SomeArgs)msg.obj;
                 mInputMethodSession.appPrivateCommand((String)args.arg1,
@@ -181,6 +187,12 @@
     }
 
     @Override
+    public void updateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) {
+        mCaller.executeOrSendMessage(
+                mCaller.obtainMessageO(DO_UPDATE_CURSOR_ANCHOR_INFO, cursorAnchorInfo));
+    }
+
+    @Override
     public void appPrivateCommand(String action, Bundle data) {
         mCaller.executeOrSendMessage(
                 mCaller.obtainMessageOO(DO_APP_PRIVATE_COMMAND, action, data));
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 505ef9c..4bccaf1 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -51,6 +51,7 @@
 import android.view.WindowManager.BadTokenException;
 import android.view.animation.AnimationUtils;
 import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.CursorAnchorInfo;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
@@ -545,6 +546,17 @@
         public void toggleSoftInput(int showFlags, int hideFlags) {
             InputMethodService.this.onToggleSoftInput(showFlags, hideFlags);
         }
+
+        /**
+         * Call {@link InputMethodService#onUpdateCursorAnchorInfo
+         * InputMethodService.onUpdateCursorAnchorInfo()}.
+         */
+        public void updateCursorAnchorInfo(CursorAnchorInfo info) {
+            if (!isEnabled()) {
+                return;
+            }
+            InputMethodService.this.onUpdateCursorAnchorInfo(info);
+        }
     }
     
     /**
@@ -666,7 +678,8 @@
         mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
         mInflater = (LayoutInflater)getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
-        mWindow = new SoftInputWindow(this, mTheme, mDispatcherState);
+        mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
+                false);
         if (mHardwareAccelerated) {
             mWindow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
         }
@@ -1716,6 +1729,17 @@
     }
 
     /**
+     * Called when the application has reported a new location of its text insertion point and
+     * characters in the composition string.  This is only called if explicitly requested by the
+     * input method. The default implementation does nothing.
+     * @param cursorAnchorInfo The positional information of the text insertion point and the
+     * composition string.
+     */
+    public void onUpdateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) {
+        // Intentionally empty
+    }
+
+    /**
      * Update the cursor/anthor monitor mode.
      */
     public void setCursorAnchorMonitorMode(int monitorMode) {
diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java
index df1afee..a9bace1 100644
--- a/core/java/android/inputmethodservice/SoftInputWindow.java
+++ b/core/java/android/inputmethodservice/SoftInputWindow.java
@@ -30,11 +30,20 @@
  * method window.  It will be displayed along the edge of the screen, moving
  * the application user interface away from it so that the focused item is
  * always visible.
+ * @hide
  */
-class SoftInputWindow extends Dialog {
+public class SoftInputWindow extends Dialog {
+    final String mName;
+    final Callback mCallback;
+    final KeyEvent.Callback mKeyEventCallback;
     final KeyEvent.DispatcherState mDispatcherState;
+    final boolean mTakesFocus;
     private final Rect mBounds = new Rect();
-    
+
+    public interface Callback {
+        public void onBackPressed();
+    }
+
     public void setToken(IBinder token) {
         WindowManager.LayoutParams lp = getWindow().getAttributes();
         lp.token = token;
@@ -53,10 +62,15 @@
      *        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 SoftInputWindow(Context context, int theme,
-            KeyEvent.DispatcherState dispatcherState) {
+    public SoftInputWindow(Context context, String name, int theme, Callback callback,
+            KeyEvent.Callback keyEventCallback, KeyEvent.DispatcherState dispatcherState,
+            boolean takesFocus) {
         super(context, theme);
+        mName = name;
+        mCallback = callback;
+        mKeyEventCallback = keyEventCallback;
         mDispatcherState = dispatcherState;
+        mTakesFocus = takesFocus;
         initDockWindow();
     }
 
@@ -148,11 +162,47 @@
         }
     }
 
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (mKeyEventCallback != null && mKeyEventCallback.onKeyDown(keyCode, event)) {
+            return true;
+        }
+        return super.onKeyDown(keyCode, event);
+    }
+
+    public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+        if (mKeyEventCallback != null && mKeyEventCallback.onKeyLongPress(keyCode, event)) {
+            return true;
+        }
+        return super.onKeyLongPress(keyCode, event);
+    }
+
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (mKeyEventCallback != null && mKeyEventCallback.onKeyUp(keyCode, event)) {
+            return true;
+        }
+        return super.onKeyUp(keyCode, event);
+    }
+
+    public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
+        if (mKeyEventCallback != null && mKeyEventCallback.onKeyMultiple(keyCode, count, event)) {
+            return true;
+        }
+        return super.onKeyMultiple(keyCode, count, event);
+    }
+
+    public void onBackPressed() {
+        if (mCallback != null) {
+            mCallback.onBackPressed();
+        } else {
+            super.onBackPressed();
+        }
+    }
+
     private void initDockWindow() {
         WindowManager.LayoutParams lp = getWindow().getAttributes();
 
         lp.type = WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-        lp.setTitle("InputMethod");
+        lp.setTitle(mName);
 
         lp.gravity = Gravity.BOTTOM;
         lp.width = -1;
@@ -161,11 +211,19 @@
         //lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
 
         getWindow().setAttributes(lp);
-        getWindow().setFlags(
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
-                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
+
+        int windowSetFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+        int windowModFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
-                WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+                WindowManager.LayoutParams.FLAG_DIM_BEHIND;
+
+        if (!mTakesFocus) {
+            windowSetFlags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        } else {
+            windowSetFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+            windowModFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+        }
+
+        getWindow().setFlags(windowSetFlags, windowModFlags);
     }
 }
diff --git a/core/java/android/net/BaseNetworkStateTracker.java b/core/java/android/net/BaseNetworkStateTracker.java
index 804f8ee..79db389 100644
--- a/core/java/android/net/BaseNetworkStateTracker.java
+++ b/core/java/android/net/BaseNetworkStateTracker.java
@@ -44,7 +44,8 @@
 
     protected NetworkInfo mNetworkInfo;
     protected LinkProperties mLinkProperties;
-    protected LinkCapabilities mLinkCapabilities;
+    protected NetworkCapabilities mNetworkCapabilities;
+    protected Network mNetwork = new Network(ConnectivityManager.INVALID_NET_ID);
 
     private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
     private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
@@ -54,7 +55,7 @@
         mNetworkInfo = new NetworkInfo(
                 networkType, -1, ConnectivityManager.getNetworkTypeName(networkType), null);
         mLinkProperties = new LinkProperties();
-        mLinkCapabilities = new LinkCapabilities();
+        mNetworkCapabilities = new NetworkCapabilities();
     }
 
     protected BaseNetworkStateTracker() {
@@ -98,8 +99,8 @@
     }
 
     @Override
-    public LinkCapabilities getLinkCapabilities() {
-        return new LinkCapabilities(mLinkCapabilities);
+    public NetworkCapabilities getNetworkCapabilities() {
+        return new NetworkCapabilities(mNetworkCapabilities);
     }
 
     @Override
@@ -201,4 +202,14 @@
     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 3da00b1..a414421 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -13,26 +13,35 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package android.net;
 
 import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.os.Binder;
 import android.os.Build.VERSION_CODES;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.INetworkActivityListener;
 import android.os.INetworkManagementService;
+import android.os.Looper;
+import android.os.Message;
 import android.os.Messenger;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.provider.Settings;
 import android.util.ArrayMap;
+import android.util.Log;
 
 import java.net.InetAddress;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.HashMap;
+
+import com.android.internal.util.Protocol;
 
 /**
  * Class that answers queries about the state of network connectivity. It also
@@ -408,6 +417,11 @@
      */
     public static final int CONNECTIVITY_CHANGE_DELAY_DEFAULT = 3000;
 
+    /**
+     * @hide
+     */
+    public final static int INVALID_NET_ID = 0;
+
     private final IConnectivityManager mService;
 
     private final String mPackageName;
@@ -529,26 +543,21 @@
     /**
      * Specifies the preferred network type.  When the device has more
      * than one type available the preferred network type will be used.
-     * Note that this made sense when we only had 2 network types,
-     * but with more and more default networks we need an array to list
-     * their ordering.  This will be deprecated soon.
      *
      * @param preference the network type to prefer over all others.  It is
      *         unspecified what happens to the old preferred network in the
      *         overall ordering.
      */
     public void setNetworkPreference(int preference) {
-        try {
-            mService.setNetworkPreference(preference);
-        } catch (RemoteException e) {
-        }
+        // TODO - deprecate with:
+        // @deprecated Functionality has been removed as it no longer makes sense,
+        //         with many more than two networks - we'd need an array to express
+        //         preference.  Instead we use dynamic network properties of
+        //         the networks to describe their precedence.
     }
 
     /**
      * Retrieves the current preferred network type.
-     * Note that this made sense when we only had 2 network types,
-     * but with more and more default networks we need an array to list
-     * their ordering.  This will be deprecated soon.
      *
      * @return an integer representing the preferred network type
      *
@@ -556,11 +565,12 @@
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      */
     public int getNetworkPreference() {
-        try {
-            return mService.getNetworkPreference();
-        } catch (RemoteException e) {
-            return -1;
-        }
+        // TODO - deprecate with:
+        // @deprecated Functionality has been removed as it no longer makes sense,
+        //         with many more than two networks - we'd need an array to express
+        //         preference.  Instead we use dynamic network properties of
+        //         the networks to describe their precedence.
+        return -1;
     }
 
     /**
@@ -700,7 +710,25 @@
      */
     public LinkProperties getLinkProperties(int networkType) {
         try {
-            return mService.getLinkProperties(networkType);
+            return mService.getLinkPropertiesForType(networkType);
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /** {@hide} */
+    public LinkProperties getLinkProperties(Network network) {
+        try {
+            return mService.getLinkProperties(network);
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /** {@hide} */
+    public NetworkCapabilities getNetworkCapabilities(Network network) {
+        try {
+            return mService.getNetworkCapabilities(network);
         } catch (RemoteException e) {
             return null;
         }
@@ -718,13 +746,14 @@
      * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      * {@hide}
      */
-    public boolean setRadios(boolean turnOn) {
-        try {
-            return mService.setRadios(turnOn);
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
+// TODO - check for any callers and remove
+//    public boolean setRadios(boolean turnOn) {
+//        try {
+//            return mService.setRadios(turnOn);
+//        } catch (RemoteException e) {
+//            return false;
+//        }
+//    }
 
     /**
      * Tells a given networkType to set its radio power state as directed.
@@ -738,13 +767,14 @@
      * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      * {@hide}
      */
-    public boolean setRadio(int networkType, boolean turnOn) {
-        try {
-            return mService.setRadio(networkType, turnOn);
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
+// TODO - check for any callers and remove
+//    public boolean setRadio(int networkType, boolean turnOn) {
+//        try {
+//            return mService.setRadio(networkType, turnOn);
+//        } catch (RemoteException e) {
+//            return false;
+//        }
+//    }
 
     /**
      * Tells the underlying networking system that the caller wants to
@@ -1302,19 +1332,34 @@
     }
 
     /**
+     * Report a problem network to the framework.  This will cause the framework
+     * to evaluate the situation and try to fix any problems.  Note that false
+     * may be subsequently ignored.
+     *
+     * @param network The Network the application was attempting to use or null
+     *                to indicate the current default network.
+     * {@hide}
+     */
+    public void reportBadNetwork(Network network) {
+        try {
+            mService.reportBadNetwork(network);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Set a network-independent global http proxy.  This is not normally what you want
      * for typical HTTP proxies - they are general network dependent.  However if you're
      * doing something unusual like general internal filtering this may be useful.  On
      * a private network where the proxy is not accessible, you may break HTTP using this.
      *
-     * @param p The a {@link ProxyProperties} object defining the new global
+     * @param p The a {@link ProxyInfo} object defining the new global
      *        HTTP proxy.  A {@code null} value will clear the global HTTP proxy.
      *
      * <p>This method requires the call to hold the permission
-     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
-     * {@hide}
+     * android.Manifest.permission#CONNECTIVITY_INTERNAL.
      */
-    public void setGlobalProxy(ProxyProperties p) {
+    public void setGlobalProxy(ProxyInfo p) {
         try {
             mService.setGlobalProxy(p);
         } catch (RemoteException e) {
@@ -1324,14 +1369,13 @@
     /**
      * Retrieve any network-independent global HTTP proxy.
      *
-     * @return {@link ProxyProperties} for the current global HTTP proxy or {@code null}
+     * @return {@link ProxyInfo} for the current global HTTP proxy or {@code null}
      *        if no global HTTP proxy is set.
      *
      * <p>This method requires the call to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
-     * {@hide}
      */
-    public ProxyProperties getGlobalProxy() {
+    public ProxyInfo getGlobalProxy() {
         try {
             return mService.getGlobalProxy();
         } catch (RemoteException e) {
@@ -1343,14 +1387,14 @@
      * Get the HTTP proxy settings for the current default network.  Note that
      * if a global proxy is set, it will override any per-network setting.
      *
-     * @return the {@link ProxyProperties} for the current HTTP proxy, or {@code null} if no
+     * @return the {@link ProxyInfo} for the current HTTP proxy, or {@code null} if no
      *        HTTP proxy is active.
      *
      * <p>This method requires the call to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
-    public ProxyProperties getProxy() {
+    public ProxyInfo getProxy() {
         try {
             return mService.getProxy();
         } catch (RemoteException e) {
@@ -1584,4 +1628,440 @@
         } catch (RemoteException e) {
         }
     }
+
+    /** {@hide} */
+    public void registerNetworkFactory(Messenger messenger) {
+        try {
+            mService.registerNetworkFactory(messenger);
+        } catch (RemoteException e) { }
+    }
+
+    /** {@hide} */
+    public void registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
+            NetworkCapabilities nc, int score) {
+        try {
+            mService.registerNetworkAgent(messenger, ni, lp, nc, score);
+        } catch (RemoteException e) { }
+    }
+
+    /**
+     * Interface for NetworkRequest callbacks.  Used for notifications about network
+     * changes.
+     * @hide
+     */
+    public static class NetworkCallbacks {
+        /** @hide */
+        public static final int PRECHECK     = 1;
+        /** @hide */
+        public static final int AVAILABLE    = 2;
+        /** @hide */
+        public static final int LOSING       = 3;
+        /** @hide */
+        public static final int LOST         = 4;
+        /** @hide */
+        public static final int UNAVAIL      = 5;
+        /** @hide */
+        public static final int CAP_CHANGED  = 6;
+        /** @hide */
+        public static final int PROP_CHANGED = 7;
+        /** @hide */
+        public static final int CANCELED     = 8;
+
+        /**
+         * @hide
+         * Called whenever the framework connects to a network that it may use to
+         * satisfy this request
+         */
+        public void onPreCheck(NetworkRequest networkRequest, Network network) {}
+
+        /**
+         * Called when the framework connects and has validated the new network.
+         */
+        public void onAvailable(NetworkRequest networkRequest, Network network) {}
+
+        /**
+         * Called when the framework is losing the network.  Often paired with an
+         * onAvailable call with the new replacement network for graceful handover.
+         * This may not be called if we have a hard loss (loss without warning).
+         * This may be followed by either an onLost call or an onAvailable call for this
+         * network depending on if we lose or regain it.
+         */
+        public void onLosing(NetworkRequest networkRequest, Network network, int maxSecToLive) {}
+
+        /**
+         * Called when the framework has a hard loss of the network or when the
+         * graceful failure ends.  Note applications should only request this callback
+         * if the application is willing to track the Available and Lost callbacks
+         * together, else the application may think it has no network when it
+         * really does (A Avail, B Avail, A Lost..  still have B).
+         */
+        public void onLost(NetworkRequest networkRequest, Network network) {}
+
+        /**
+         * Called if no network is found in the given timeout time.  If no timeout is given,
+         * this will not be called.
+         */
+        public void onUnavailable(NetworkRequest networkRequest) {}
+
+        /**
+         * Called when the network the framework connected to for this request
+         * changes capabilities but still satisfies the stated need.
+         */
+        public void onNetworkCapabilitiesChanged(NetworkRequest networkRequest, Network network,
+                NetworkCapabilities networkCapabilities) {}
+
+        /**
+         * Called when the network the framework connected to for this request
+         * changes LinkProperties.
+         */
+        public void onLinkPropertiesChanged(NetworkRequest networkRequest, Network network,
+                LinkProperties linkProperties) {}
+
+        /**
+         * Called when a releaseNetworkRequest call concludes and the registered callbacks will
+         * no longer be used.
+         */
+        public void onReleased(NetworkRequest networkRequest) {}
+    }
+
+    private static final int BASE = Protocol.BASE_CONNECTIVITY_MANAGER;
+    /** @hide obj = pair(NetworkRequest, Network) */
+    public static final int CALLBACK_PRECHECK           = BASE + 1;
+    /** @hide obj = pair(NetworkRequest, Network) */
+    public static final int CALLBACK_AVAILABLE          = BASE + 2;
+    /** @hide obj = pair(NetworkRequest, Network), arg1 = ttl */
+    public static final int CALLBACK_LOSING             = BASE + 3;
+    /** @hide obj = pair(NetworkRequest, Network) */
+    public static final int CALLBACK_LOST               = BASE + 4;
+    /** @hide obj = NetworkRequest */
+    public static final int CALLBACK_UNAVAIL            = BASE + 5;
+    /** @hide obj = pair(NetworkRequest, Network) */
+    public static final int CALLBACK_CAP_CHANGED        = BASE + 6;
+    /** @hide obj = pair(NetworkRequest, Network) */
+    public static final int CALLBACK_IP_CHANGED         = BASE + 7;
+    /** @hide obj = NetworkRequest */
+    public static final int CALLBACK_RELEASED           = BASE + 8;
+    /** @hide */
+    public static final int CALLBACK_EXIT               = BASE + 9;
+
+    private static class CallbackHandler extends Handler {
+        private final HashMap<NetworkRequest, NetworkCallbacks>mCallbackMap;
+        private final AtomicInteger mRefCount;
+        private static final String TAG = "ConnectivityManager.CallbackHandler";
+        private final ConnectivityManager mCm;
+
+        CallbackHandler(Looper looper, HashMap<NetworkRequest, NetworkCallbacks>callbackMap,
+                AtomicInteger refCount, ConnectivityManager cm) {
+            super(looper);
+            mCallbackMap = callbackMap;
+            mRefCount = refCount;
+            mCm = cm;
+        }
+
+        @Override
+        public void handleMessage(Message message) {
+            Log.d(TAG, "CM callback handler got msg " + message.what);
+            switch (message.what) {
+                case CALLBACK_PRECHECK: {
+                    NetworkRequest request = getNetworkRequest(message);
+                    NetworkCallbacks callbacks = getCallbacks(request);
+                    if (callbacks != null) {
+                        callbacks.onPreCheck(request, getNetwork(message));
+                    } else {
+                        Log.e(TAG, "callback not found for PRECHECK message");
+                    }
+                    break;
+                }
+                case CALLBACK_AVAILABLE: {
+                    NetworkRequest request = getNetworkRequest(message);
+                    NetworkCallbacks callbacks = getCallbacks(request);
+                    if (callbacks != null) {
+                        callbacks.onAvailable(request, getNetwork(message));
+                    } else {
+                        Log.e(TAG, "callback not found for AVAILABLE message");
+                    }
+                    break;
+                }
+                case CALLBACK_LOSING: {
+                    NetworkRequest request = getNetworkRequest(message);
+                    NetworkCallbacks callbacks = getCallbacks(request);
+                    if (callbacks != null) {
+                        callbacks.onLosing(request, getNetwork(message), message.arg1);
+                    } else {
+                        Log.e(TAG, "callback not found for LOSING message");
+                    }
+                    break;
+                }
+                case CALLBACK_LOST: {
+                    NetworkRequest request = getNetworkRequest(message);
+                    NetworkCallbacks callbacks = getCallbacks(request);
+                    if (callbacks != null) {
+                        callbacks.onLost(request, getNetwork(message));
+                    } else {
+                        Log.e(TAG, "callback not found for LOST message");
+                    }
+                    break;
+                }
+                case CALLBACK_UNAVAIL: {
+                    NetworkRequest req = (NetworkRequest)message.obj;
+                    NetworkCallbacks callbacks = null;
+                    synchronized(mCallbackMap) {
+                        callbacks = mCallbackMap.get(req);
+                    }
+                    if (callbacks != null) {
+                        callbacks.onUnavailable(req);
+                    } else {
+                        Log.e(TAG, "callback not found for UNAVAIL message");
+                    }
+                    break;
+                }
+                case CALLBACK_CAP_CHANGED: {
+                    NetworkRequest request = getNetworkRequest(message);
+                    NetworkCallbacks callbacks = getCallbacks(request);
+                    if (callbacks != null) {
+                        Network network = getNetwork(message);
+                        NetworkCapabilities cap = mCm.getNetworkCapabilities(network);
+
+                        callbacks.onNetworkCapabilitiesChanged(request, network, cap);
+                    } else {
+                        Log.e(TAG, "callback not found for CHANGED message");
+                    }
+                    break;
+                }
+                case CALLBACK_IP_CHANGED: {
+                    NetworkRequest request = getNetworkRequest(message);
+                    NetworkCallbacks callbacks = getCallbacks(request);
+                    if (callbacks != null) {
+                        Network network = getNetwork(message);
+                        LinkProperties lp = mCm.getLinkProperties(network);
+
+                        callbacks.onLinkPropertiesChanged(request, network, lp);
+                    } else {
+                        Log.e(TAG, "callback not found for CHANGED message");
+                    }
+                    break;
+                }
+                case CALLBACK_RELEASED: {
+                    NetworkRequest req = (NetworkRequest)message.obj;
+                    NetworkCallbacks callbacks = null;
+                    synchronized(mCallbackMap) {
+                        callbacks = mCallbackMap.remove(req);
+                    }
+                    if (callbacks != null) {
+                        callbacks.onReleased(req);
+                    } else {
+                        Log.e(TAG, "callback not found for CANCELED message");
+                    }
+                    synchronized(mRefCount) {
+                        if (mRefCount.decrementAndGet() == 0) {
+                            getLooper().quit();
+                        }
+                    }
+                    break;
+                }
+                case CALLBACK_EXIT: {
+                    Log.d(TAG, "Listener quiting");
+                    getLooper().quit();
+                    break;
+                }
+            }
+        }
+
+        private NetworkRequest getNetworkRequest(Message msg) {
+            return (NetworkRequest)(msg.obj);
+        }
+        private NetworkCallbacks getCallbacks(NetworkRequest req) {
+            synchronized(mCallbackMap) {
+                return mCallbackMap.get(req);
+            }
+        }
+        private Network getNetwork(Message msg) {
+            return new Network(msg.arg2);
+        }
+        private NetworkCallbacks removeCallbacks(Message msg) {
+            NetworkRequest req = (NetworkRequest)msg.obj;
+            synchronized(mCallbackMap) {
+                return mCallbackMap.remove(req);
+            }
+        }
+    }
+
+    private void addCallbackListener() {
+        synchronized(sCallbackRefCount) {
+            if (sCallbackRefCount.incrementAndGet() == 1) {
+                // TODO - switch this over to a ManagerThread or expire it when done
+                HandlerThread callbackThread = new HandlerThread("ConnectivityManager");
+                callbackThread.start();
+                sCallbackHandler = new CallbackHandler(callbackThread.getLooper(),
+                        sNetworkCallbacks, sCallbackRefCount, this);
+            }
+        }
+    }
+
+    private void removeCallbackListener() {
+        synchronized(sCallbackRefCount) {
+            if (sCallbackRefCount.decrementAndGet() == 0) {
+                sCallbackHandler.obtainMessage(CALLBACK_EXIT).sendToTarget();
+                sCallbackHandler = null;
+            }
+        }
+    }
+
+    static final HashMap<NetworkRequest, NetworkCallbacks> sNetworkCallbacks =
+            new HashMap<NetworkRequest, NetworkCallbacks>();
+    static final AtomicInteger sCallbackRefCount = new AtomicInteger(0);
+    static CallbackHandler sCallbackHandler = null;
+
+    private final static int LISTEN  = 1;
+    private final static int REQUEST = 2;
+
+    private NetworkRequest somethingForNetwork(NetworkCapabilities need,
+            NetworkCallbacks networkCallbacks, int timeoutSec, int action) {
+        NetworkRequest networkRequest = null;
+        if (networkCallbacks == null) throw new IllegalArgumentException("null NetworkCallbacks");
+        if (need == null) throw new IllegalArgumentException("null NetworkCapabilities");
+        try {
+            addCallbackListener();
+            if (action == LISTEN) {
+                networkRequest = mService.listenForNetwork(need, new Messenger(sCallbackHandler),
+                        new Binder());
+            } else {
+                networkRequest = mService.requestNetwork(need, new Messenger(sCallbackHandler),
+                        timeoutSec, new Binder());
+            }
+            if (networkRequest != null) {
+                synchronized(sNetworkCallbacks) {
+                    sNetworkCallbacks.put(networkRequest, networkCallbacks);
+                }
+            }
+        } catch (RemoteException e) {}
+        if (networkRequest == null) removeCallbackListener();
+        return networkRequest;
+    }
+
+    /**
+     * Request a network to satisfy a set of {@link NetworkCapabilities}.
+     *
+     * This {@link NetworkRequest} will live until released via
+     * {@link releaseNetworkRequest} or the calling application exits.
+     * Status of the request can be follwed by listening to the various
+     * callbacks described in {@link NetworkCallbacks}.  The {@link Network}
+     * can be used by using the {@link bindSocketToNetwork},
+     * {@link bindApplicationToNetwork} and {@link getAddrInfoOnNetwork} functions.
+     *
+     * @param need {@link NetworkCapabilities} required by this request.
+     * @param networkCallbacks The callbacks to be utilized for this request.  Note
+     *                         the callbacks can be shared by multiple requests and
+     *                         the NetworkRequest token utilized to determine to which
+     *                         request the callback relates.
+     * @return A {@link NetworkRequest} object identifying the request.
+     * @hide
+     */
+    public NetworkRequest requestNetwork(NetworkCapabilities need,
+            NetworkCallbacks networkCallbacks) {
+        return somethingForNetwork(need, networkCallbacks, 0, REQUEST);
+    }
+
+    /**
+     * Request a network to satisfy a set of {@link NetworkCapabilities}, limited
+     * by a timeout.
+     *
+     * This function behaves identically, but if a suitable network is not found
+     * within the given time (in Seconds) the {@link NetworkCallbacks#unavailable}
+     * callback is called.  The request must still be released normally by
+     * calling {@link releaseNetworkRequest}.
+     * @param need {@link NetworkCapabilities} required by this request.
+     * @param networkCallbacks The callbacks to be utilized for this request.  Note
+     *                         the callbacks can be shared by multiple requests and
+     *                         the NetworkRequest token utilized to determine to which
+     *                         request the callback relates.
+     * @param timeoutSec The time in seconds to attempt looking for a suitable network
+     *                   before {@link NetworkCallbacks#unavailable} is called.
+     * @return A {@link NetworkRequest} object identifying the request.
+     * @hide
+     */
+    public NetworkRequest requestNetwork(NetworkCapabilities need,
+            NetworkCallbacks networkCallbacks, int timeoutSec) {
+        return somethingForNetwork(need, networkCallbacks, timeoutSec, REQUEST);
+    }
+
+    /**
+     * The maximum number of seconds the framework will look for a suitable network
+     * during a timeout-equiped call to {@link requestNetwork}.
+     * {@hide}
+     */
+    public final static int MAX_NETWORK_REQUEST_TIMEOUT_SEC = 100 * 60;
+
+    /**
+     * Request a network to satisfy a set of {@link NetworkCapabilities}.
+     *
+     * This function behavies identically, but instead of {@link NetworkCallbacks}
+     * a {@link PendingIntent} is used.  This means the request may outlive the
+     * calling application and get called back when a suitable network is found.
+     * <p>
+     * The operation is an Intent broadcast that goes to a broadcast receiver that
+     * you registered with {@link Context#registerReceiver} or through the
+     * &lt;receiver&gt; tag in an AndroidManifest.xml file
+     * <p>
+     * The operation Intent is delivered with two extras, a {@link Network} typed
+     * extra called {@link EXTRA_NETWORK_REQUEST_NETWORK} and a {@link NetworkCapabilities}
+     * typed extra called {@link EXTRA_NETWORK_REQUEST_NETWORK_CAPABILTIES} containing
+     * the original requests parameters.  It is important to create a new,
+     * {@link NetworkCallbacks} based request before completing the processing of the
+     * Intent to reserve the network or it will be released shortly after the Intent
+     * is processed.
+     * <p>
+     * If there is already an request for this Intent registered (with the equality of
+     * two Intents defined by {@link Intent#filterEquals}), then it will be removed and
+     * replace by this one, effectively releasing the previous {@link NetworkRequest}.
+     * <p>
+     * The request may be released normally by calling {@link releaseNetworkRequest}.
+     *
+     * @param need {@link NetworkCapabilties} required by this request.
+     * @param operation Action to perform when the network is available (corresponds
+     *                  to the {@link NetworkCallbacks#onAvailable} call.  Typically
+     *                  comes from {@link PendingIntent#getBroadcast}.
+     * @return A {@link NetworkRequest} object identifying the request.
+     * @hide
+     */
+    public NetworkRequest requestNetwork(NetworkCapabilities need, PendingIntent operation) {
+        try {
+            return mService.pendingRequestForNetwork(need, operation);
+        } catch (RemoteException e) {}
+        return null;
+    }
+
+    /**
+     * Registers to receive notifications about all networks which satisfy the given
+     * {@link NetworkCapabilities}.  The callbacks will continue to be called until
+     * either the application exits or the request is released using
+     * {@link releaseNetworkRequest}.
+     *
+     * @param need {@link NetworkCapabilities} required by this request.
+     * @param networkCallbacks The {@link NetworkCallbacks} to be called as suitable
+     *                         networks change state.
+     * @return A {@link NetworkRequest} object identifying the request.
+     * @hide
+     */
+    public NetworkRequest listenForNetwork(NetworkCapabilities need,
+            NetworkCallbacks networkCallbacks) {
+        return somethingForNetwork(need, networkCallbacks, 0, LISTEN);
+    }
+
+    /**
+     * Releases a {NetworkRequest} generated either through a {@link requestNetwork}
+     * or a {@link listenForNetwork} call.  The {@link NetworkCallbacks} given in the
+     * earlier call may continue receiving calls until the {@link NetworkCallbacks#onReleased}
+     * function is called, signifiying the end of the request.
+     *
+     * @param networkRequest The {@link NetworkRequest} generated by an earlier call to
+     *                       {@link requestNetwork} or {@link listenForNetwork}.
+     * @hide
+     */
+    public void releaseNetworkRequest(NetworkRequest networkRequest) {
+        if (networkRequest == null) throw new IllegalArgumentException("null NetworkRequest");
+        try {
+            mService.releaseNetworkRequest(networkRequest);
+        } catch (RemoteException e) {}
+    }
 }
diff --git a/core/java/android/net/ConnectivityServiceProtocol.java b/core/java/android/net/ConnectivityServiceProtocol.java
new file mode 100644
index 0000000..74096b4
--- /dev/null
+++ b/core/java/android/net/ConnectivityServiceProtocol.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 static com.android.internal.util.Protocol.BASE_CONNECTIVITY_SERVICE;
+
+/**
+ * Describes the Internal protocols used to communicate with ConnectivityService.
+ * @hide
+ */
+public class ConnectivityServiceProtocol {
+
+    private static final int BASE = BASE_CONNECTIVITY_SERVICE;
+
+    private ConnectivityServiceProtocol() {}
+
+    /**
+     * This is a contract between ConnectivityService and various bearers.
+     * A NetworkFactory is an abstract entity that creates NetworkAgent objects.
+     * The bearers register with ConnectivityService using
+     * ConnectivityManager.registerNetworkFactory, where they pass in a Messenger
+     * to be used to deliver the following Messages.
+     */
+    public static class NetworkFactoryProtocol {
+        private NetworkFactoryProtocol() {}
+        /**
+         * Pass a network request to the bearer.  If the bearer believes it can
+         * satisfy the request it should connect to the network and create a
+         * NetworkAgent.  Once the NetworkAgent is fully functional it will
+         * register itself with ConnectivityService using registerNetworkAgent.
+         * If the bearer cannot immediately satisfy the request (no network,
+         * user disabled the radio, lower-scored network) it should remember
+         * any NetworkRequests it may be able to satisfy in the future.  It may
+         * disregard any that it will never be able to service, for example
+         * those requiring a different bearer.
+         * msg.obj = NetworkRequest
+         * msg.arg1 = score - the score of the any network currently satisfying this
+         *            request.  If this bearer knows in advance it cannot
+         *            exceed this score it should not try to connect, holding the request
+         *            for the future.
+         *            Note that subsequent events may give a different (lower
+         *            or higher) score for this request, transmitted to each
+         *            NetworkFactory through additional CMD_REQUEST_NETWORK msgs
+         *            with the same NetworkRequest but an updated score.
+         *            Also, network conditions may change for this bearer
+         *            allowing for a better score in the future.
+         */
+        public static final int CMD_REQUEST_NETWORK = BASE;
+
+        /**
+         * Cancel a network request
+         * msg.obj = NetworkRequest
+         */
+        public static final int CMD_CANCEL_REQUEST = BASE + 1;
+    }
+}
diff --git a/core/java/android/net/DummyDataStateTracker.java b/core/java/android/net/DummyDataStateTracker.java
index a5d059e..eff9f9f 100644
--- a/core/java/android/net/DummyDataStateTracker.java
+++ b/core/java/android/net/DummyDataStateTracker.java
@@ -190,13 +190,6 @@
         return new LinkProperties(mLinkProperties);
     }
 
-    /**
-     * @see android.net.NetworkStateTracker#getLinkCapabilities()
-     */
-    public LinkCapabilities getLinkCapabilities() {
-        return new LinkCapabilities(mLinkCapabilities);
-    }
-
     public void setDependencyMet(boolean met) {
         // not supported on this network
     }
diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java
index 10b5d0b..c1afc9b 100644
--- a/core/java/android/net/EthernetDataTracker.java
+++ b/core/java/android/net/EthernetDataTracker.java
@@ -103,7 +103,7 @@
     private EthernetDataTracker() {
         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORKTYPE, "");
         mLinkProperties = new LinkProperties();
-        mLinkCapabilities = new LinkCapabilities();
+        mNetworkCapabilities = new NetworkCapabilities();
     }
 
     private void interfaceUpdated() {
@@ -372,16 +372,6 @@
         return new LinkProperties(mLinkProperties);
     }
 
-   /**
-     * A capability is an Integer/String pair, the capabilities
-     * are defined in the class LinkSocket#Key.
-     *
-     * @return a copy of this connections capabilities, may be empty but never null.
-     */
-    public LinkCapabilities getLinkCapabilities() {
-        return new LinkCapabilities(mLinkCapabilities);
-    }
-
     /**
      * Fetch default gateway address for the network
      */
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 381a817..885b8b6 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -16,12 +16,16 @@
 
 package android.net;
 
+import android.app.PendingIntent;
 import android.net.LinkQualityInfo;
 import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkQuotaInfo;
+import android.net.NetworkRequest;
 import android.net.NetworkState;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
 import android.os.IBinder;
 import android.os.Messenger;
 import android.os.ParcelFileDescriptor;
@@ -41,10 +45,6 @@
     // Keep this in sync with framework/native/services/connectivitymanager/ConnectivityManager.h
     void markSocketAsUser(in ParcelFileDescriptor socket, int uid);
 
-    void setNetworkPreference(int pref);
-
-    int getNetworkPreference();
-
     NetworkInfo getActiveNetworkInfo();
     NetworkInfo getActiveNetworkInfoForUid(int uid);
     NetworkInfo getNetworkInfo(int networkType);
@@ -55,17 +55,16 @@
     boolean isNetworkSupported(int networkType);
 
     LinkProperties getActiveLinkProperties();
-    LinkProperties getLinkProperties(int networkType);
+    LinkProperties getLinkPropertiesForType(int networkType);
+    LinkProperties getLinkProperties(in Network network);
+
+    NetworkCapabilities getNetworkCapabilities(in Network network);
 
     NetworkState[] getAllNetworkState();
 
     NetworkQuotaInfo getActiveNetworkQuotaInfo();
     boolean isActiveNetworkMetered();
 
-    boolean setRadios(boolean onOff);
-
-    boolean setRadio(int networkType, boolean turnOn);
-
     int startUsingNetworkFeature(int networkType, in String feature,
             in IBinder binder);
 
@@ -107,11 +106,13 @@
 
     void reportInetCondition(int networkType, int percentage);
 
-    ProxyProperties getGlobalProxy();
+    void reportBadNetwork(in Network network);
 
-    void setGlobalProxy(in ProxyProperties p);
+    ProxyInfo getGlobalProxy();
 
-    ProxyProperties getProxy();
+    void setGlobalProxy(in ProxyInfo p);
+
+    ProxyInfo getProxy();
 
     void setDataDependency(int networkType, boolean met);
 
@@ -147,7 +148,27 @@
 
     LinkQualityInfo[] getAllLinkQualityInfo();
 
-    void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, in String url);
+    void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo,
+            in String url);
 
     void setAirplaneMode(boolean enable);
+
+    void registerNetworkFactory(in Messenger messenger);
+
+    void registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp,
+            in NetworkCapabilities nc, int score);
+
+    NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities,
+            in Messenger messenger, int timeoutSec, in IBinder binder);
+
+    NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities,
+            in PendingIntent operation);
+
+    NetworkRequest listenForNetwork(in NetworkCapabilities networkCapabilities,
+            in Messenger messenger, in IBinder binder);
+
+    void pendingListenForNetwork(in NetworkCapabilities networkCapabilities,
+            in PendingIntent operation);
+
+    void releaseNetworkRequest(in NetworkRequest networkRequest);
 }
diff --git a/core/java/android/net/INetworkScoreCache.aidl b/core/java/android/net/INetworkScoreCache.aidl
new file mode 100644
index 0000000..35601ce
--- /dev/null
+++ b/core/java/android/net/INetworkScoreCache.aidl
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.ScoredNetwork;
+
+/**
+ * A service which stores a subset of scored networks from the active network scorer.
+ *
+ * <p>To be implemented by network subsystems (e.g. Wi-Fi). NetworkScoreService will propagate
+ * scores down to each subsystem depending on the network type. Implementations may register for
+ * a given network type by calling NetworkScoreManager.registerNetworkSubsystem.
+ *
+ * <p>A proper implementation should throw SecurityException whenever the caller is not privileged.
+ * It may request scores by calling NetworkScoreManager#requestScores(NetworkKey[]); a call to
+ * updateScores may follow but may not depending on the active scorer's implementation, and in
+ * general this method may be called at any time.
+ *
+ * <p>Implementations should also override dump() so that "adb shell dumpsys network_score" includes
+ * the current scores for each network for debugging purposes.
+ * @hide
+ */
+interface INetworkScoreCache
+{
+    void updateScores(in List<ScoredNetwork> networks);
+
+    void clearScores();
+}
+
diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl
index a72d9a0..626bd2a 100644
--- a/core/java/android/net/INetworkScoreService.aidl
+++ b/core/java/android/net/INetworkScoreService.aidl
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.net.INetworkScoreCache;
 import android.net.ScoredNetwork;
 
 /**
@@ -34,8 +35,7 @@
     /**
      * Clear all scores.
      * @return whether the clear was successful.
-     * @throws SecurityException if the caller is neither the current active scorer nor the scorer
-     * manager.
+     * @throws SecurityException if the caller is neither the current active scorer nor the system.
      */
     boolean clearScores();
 
@@ -43,7 +43,19 @@
      * Set the active scorer and clear existing scores.
      * @param packageName the package name of the new scorer to use.
      * @return true if the operation succeeded, or false if the new package is not a valid scorer.
-     * @throws SecurityException if the caller is not the scorer manager.
+     * @throws SecurityException if the caller is not the system.
      */
     boolean setActiveScorer(in String packageName);
+
+    /**
+     * Register a network subsystem for scoring.
+     *
+     * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
+     * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
+     * @throws SecurityException if the caller is not the system.
+     * @throws IllegalArgumentException if a score cache is already registed for this type.
+     * @hide
+     */
+    void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache);
+
 }
diff --git a/core/java/android/net/LinkCapabilities.aidl b/core/java/android/net/LinkCapabilities.aidl
deleted file mode 100644
index df72599..0000000
--- a/core/java/android/net/LinkCapabilities.aidl
+++ /dev/null
@@ -1,21 +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;
-
-parcelable LinkCapabilities;
-
diff --git a/core/java/android/net/LinkCapabilities.java b/core/java/android/net/LinkCapabilities.java
deleted file mode 100644
index fb444ea..0000000
--- a/core/java/android/net/LinkCapabilities.java
+++ /dev/null
@@ -1,362 +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;
-
-import android.os.Parcelable;
-import android.os.Parcel;
-import android.util.Log;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-/**
- * A class representing the capabilities of a link
- *
- * @hide
- */
-public class LinkCapabilities implements Parcelable {
-    private static final String TAG = "LinkCapabilities";
-    private static final boolean DBG = false;
-
-    /** The Map of Keys to Values */
-    private HashMap<Integer, String> mCapabilities;
-
-
-    /**
-     * The set of keys defined for a links capabilities.
-     *
-     * Keys starting with RW are read + write, i.e. the application
-     * can request for a certain requirement corresponding to that key.
-     * Keys starting with RO are read only, i.e. the the application
-     * can read the value of that key from the socket but cannot request
-     * a corresponding requirement.
-     *
-     * TODO: Provide a documentation technique for concisely and precisely
-     * define the syntax for each value string associated with a key.
-     */
-    public static final class Key {
-        /** No constructor */
-        private Key() {}
-
-        /**
-         * An integer representing the network type.
-         * @see ConnectivityManager
-         */
-        public final static int RO_NETWORK_TYPE = 1;
-
-        /**
-         * Desired minimum forward link (download) bandwidth for the
-         * in kilobits per second (kbps). Values should be strings such
-         * "50", "100", "1500", etc.
-         */
-        public final static int RW_DESIRED_FWD_BW = 2;
-
-        /**
-         * Required minimum forward link (download) bandwidth, in
-         * per second (kbps), below which the socket cannot function.
-         * Values should be strings such as "50", "100", "1500", etc.
-         */
-        public final static int RW_REQUIRED_FWD_BW = 3;
-
-        /**
-         * Available forward link (download) bandwidth for the socket.
-         * This value is in kilobits per second (kbps).
-         * Values will be strings such as "50", "100", "1500", etc.
-         */
-        public final static int RO_AVAILABLE_FWD_BW = 4;
-
-        /**
-         * Desired minimum reverse link (upload) bandwidth for the socket
-         * in kilobits per second (kbps).
-         * Values should be strings such as "50", "100", "1500", etc.
-         * <p>
-         * This key is set via the needs map.
-         */
-        public final static int RW_DESIRED_REV_BW = 5;
-
-        /**
-         * Required minimum reverse link (upload) bandwidth, in kilobits
-         * per second (kbps), below which the socket cannot function.
-         * If a rate is not specified, the default rate of kbps will be
-         * Values should be strings such as "50", "100", "1500", etc.
-         */
-        public final static int RW_REQUIRED_REV_BW = 6;
-
-        /**
-         * Available reverse link (upload) bandwidth for the socket.
-         * This value is in kilobits per second (kbps).
-         * Values will be strings such as "50", "100", "1500", etc.
-         */
-        public final static int RO_AVAILABLE_REV_BW = 7;
-
-        /**
-         * Maximum latency for the socket, in milliseconds, above which
-         * socket cannot function.
-         * Values should be strings such as "50", "300", "500", etc.
-         */
-        public final static int RW_MAX_ALLOWED_LATENCY = 8;
-
-        /**
-         * Interface that the socket is bound to. This can be a virtual
-         * interface (e.g. VPN or Mobile IP) or a physical interface
-         * (e.g. wlan0 or rmnet0).
-         * Values will be strings such as "wlan0", "rmnet0"
-         */
-        public final static int RO_BOUND_INTERFACE = 9;
-
-        /**
-         * Physical interface that the socket is routed on.
-         * This can be different from BOUND_INTERFACE in cases such as
-         * VPN or Mobile IP. The physical interface may change over time
-         * if seamless mobility is supported.
-         * Values will be strings such as "wlan0", "rmnet0"
-         */
-        public final static int RO_PHYSICAL_INTERFACE = 10;
-    }
-
-    /**
-     * Role informs the LinkSocket about the data usage patterns of your
-     * application.
-     * <P>
-     * {@code Role.DEFAULT} is the default role, and is used whenever
-     * a role isn't set.
-     */
-    public static final class Role {
-        /** No constructor */
-        private Role() {}
-
-        // examples only, discuss which roles should be defined, and then
-        // code these to match
-
-        /** Default Role */
-        public static final String DEFAULT = "default";
-        /** Bulk down load */
-        public static final String BULK_DOWNLOAD = "bulk.download";
-        /** Bulk upload */
-        public static final String BULK_UPLOAD = "bulk.upload";
-
-        /** VoIP Application at 24kbps */
-        public static final String VOIP_24KBPS = "voip.24k";
-        /** VoIP Application at 32kbps */
-        public static final String VOIP_32KBPS = "voip.32k";
-
-        /** Video Streaming at 480p */
-        public static final String VIDEO_STREAMING_480P = "video.streaming.480p";
-        /** Video Streaming at 720p */
-        public static final String VIDEO_STREAMING_720I = "video.streaming.720i";
-
-        /** Video Chat Application at 360p */
-        public static final String VIDEO_CHAT_360P = "video.chat.360p";
-        /** Video Chat Application at 480p */
-        public static final String VIDEO_CHAT_480P = "video.chat.480i";
-    }
-
-    /**
-     * Constructor
-     */
-    public LinkCapabilities() {
-        mCapabilities = new HashMap<Integer, String>();
-    }
-
-    /**
-     * Copy constructor.
-     *
-     * @param source
-     */
-    public LinkCapabilities(LinkCapabilities source) {
-        if (source != null) {
-            mCapabilities = new HashMap<Integer, String>(source.mCapabilities);
-        } else {
-            mCapabilities = new HashMap<Integer, String>();
-        }
-    }
-
-    /**
-     * Create the {@code LinkCapabilities} with values depending on role type.
-     * @param applicationRole a {@code LinkSocket.Role}
-     * @return the {@code LinkCapabilities} associated with the applicationRole, empty if none
-     */
-    public static LinkCapabilities createNeedsMap(String applicationRole) {
-        if (DBG) log("createNeededCapabilities(applicationRole) EX");
-        return new LinkCapabilities();
-    }
-
-    /**
-     * Remove all capabilities
-     */
-    public void clear() {
-        mCapabilities.clear();
-    }
-
-    /**
-     * Returns whether this map is empty.
-     */
-    public boolean isEmpty() {
-        return mCapabilities.isEmpty();
-    }
-
-    /**
-     * Returns the number of elements in this map.
-     *
-     * @return the number of elements in this map.
-     */
-    public int size() {
-        return mCapabilities.size();
-    }
-
-    /**
-     * Given the key return the capability string
-     *
-     * @param key
-     * @return the capability string
-     */
-    public String get(int key) {
-        return mCapabilities.get(key);
-    }
-
-    /**
-     * Store the key/value capability pair
-     *
-     * @param key
-     * @param value
-     */
-    public void put(int key, String value) {
-        mCapabilities.put(key, value);
-    }
-
-    /**
-     * Returns whether this map contains the specified key.
-     *
-     * @param key to search for.
-     * @return {@code true} if this map contains the specified key,
-     *         {@code false} otherwise.
-     */
-    public boolean containsKey(int key) {
-        return mCapabilities.containsKey(key);
-    }
-
-    /**
-     * Returns whether this map contains the specified value.
-     *
-     * @param value to search for.
-     * @return {@code true} if this map contains the specified value,
-     *         {@code false} otherwise.
-     */
-    public boolean containsValue(String value) {
-        return mCapabilities.containsValue(value);
-    }
-
-    /**
-     * Returns a set containing all of the mappings in this map. Each mapping is
-     * an instance of {@link Map.Entry}. As the set is backed by this map,
-     * changes in one will be reflected in the other.
-     *
-     * @return a set of the mappings.
-     */
-    public Set<Entry<Integer, String>> entrySet() {
-        return mCapabilities.entrySet();
-    }
-
-    /**
-     * @return the set of the keys.
-     */
-    public Set<Integer> keySet() {
-        return mCapabilities.keySet();
-    }
-
-    /**
-     * @return the set of values
-     */
-    public Collection<String> values() {
-        return mCapabilities.values();
-    }
-
-    /**
-     * Implement the Parcelable interface
-     * @hide
-     */
-    public int describeContents() {
-        return 0;
-    }
-
-    /**
-     * Convert to string for debugging
-     */
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("{");
-        boolean firstTime = true;
-        for (Entry<Integer, String> entry : mCapabilities.entrySet()) {
-            if (firstTime) {
-                firstTime = false;
-            } else {
-                sb.append(",");
-            }
-            sb.append(entry.getKey());
-            sb.append(":\"");
-            sb.append(entry.getValue());
-            sb.append("\"");
-        }
-        sb.append("}");
-        return sb.toString();
-    }
-
-    /**
-     * Implement the Parcelable interface.
-     * @hide
-     */
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mCapabilities.size());
-        for (Entry<Integer, String> entry : mCapabilities.entrySet()) {
-            dest.writeInt(entry.getKey().intValue());
-            dest.writeString(entry.getValue());
-        }
-    }
-
-    /**
-     * Implement the Parcelable interface.
-     * @hide
-     */
-    public static final Creator<LinkCapabilities> CREATOR =
-        new Creator<LinkCapabilities>() {
-            public LinkCapabilities createFromParcel(Parcel in) {
-                LinkCapabilities capabilities = new LinkCapabilities();
-                int size = in.readInt();
-                while (size-- != 0) {
-                    int key = in.readInt();
-                    String value = in.readString();
-                    capabilities.mCapabilities.put(key, value);
-                }
-                return capabilities;
-            }
-
-            public LinkCapabilities[] newArray(int size) {
-                return new LinkCapabilities[size];
-            }
-        };
-
-    /**
-     * Debug logging
-     */
-    protected static void log(String s) {
-        Log.d(TAG, s);
-    }
-}
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 4dfd3d9..0a09fcb 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -16,7 +16,7 @@
 
 package android.net;
 
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
 import android.os.Parcelable;
 import android.os.Parcel;
 import android.text.TextUtils;
@@ -65,7 +65,7 @@
     private ArrayList<InetAddress> mDnses = new ArrayList<InetAddress>();
     private String mDomains;
     private ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
-    private ProxyProperties mHttpProxy;
+    private ProxyInfo mHttpProxy;
     private int mMtu;
 
     // Stores the properties of links that are "stacked" above this link.
@@ -101,7 +101,7 @@
             mDomains = source.getDomains();
             for (RouteInfo r : source.getRoutes()) mRoutes.add(r);
             mHttpProxy = (source.getHttpProxy() == null)  ?
-                    null : new ProxyProperties(source.getHttpProxy());
+                    null : new ProxyInfo(source.getHttpProxy());
             for (LinkProperties l: source.mStackedLinks.values()) {
                 addStackedLink(l);
             }
@@ -295,10 +295,10 @@
         return routes;
     }
 
-    public void setHttpProxy(ProxyProperties proxy) {
+    public void setHttpProxy(ProxyInfo proxy) {
         mHttpProxy = proxy;
     }
-    public ProxyProperties getHttpProxy() {
+    public ProxyInfo getHttpProxy() {
         return mHttpProxy;
     }
 
@@ -642,6 +642,35 @@
         return result;
     }
 
+    /**
+     * Compares all interface names in this LinkProperties with another
+     * LinkProperties, examining both the the base link and all stacked links.
+     *
+     * @param target a LinkProperties with the new list of interface names
+     * @return the differences between the interface names.
+     * @hide
+     */
+    public CompareResult<String> compareAllInterfaceNames(LinkProperties target) {
+        /*
+         * Duplicate the interface names into removed, we will be removing
+         * interface names which are common between this and target
+         * leaving the interface names that are different. And interface names which
+         * are in target but not in this are placed in added.
+         */
+        CompareResult<String> result = new CompareResult<String>();
+
+        result.removed = getAllInterfaceNames();
+        result.added.clear();
+        if (target != null) {
+            for (String r : target.getAllInterfaceNames()) {
+                if (! result.removed.remove(r)) {
+                    result.added.add(r);
+                }
+            }
+        }
+        return result;
+    }
+
 
     @Override
     /**
@@ -720,7 +749,7 @@
                     netProp.addRoute((RouteInfo)in.readParcelable(null));
                 }
                 if (in.readByte() == 1) {
-                    netProp.setHttpProxy((ProxyProperties)in.readParcelable(null));
+                    netProp.setHttpProxy((ProxyInfo)in.readParcelable(null));
                 }
                 ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>();
                 in.readList(stackedLinks, LinkProperties.class.getClassLoader());
diff --git a/core/java/android/net/LinkSocket.java b/core/java/android/net/LinkSocket.java
deleted file mode 100644
index 5aa6451..0000000
--- a/core/java/android/net/LinkSocket.java
+++ /dev/null
@@ -1,276 +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;
-
-import android.net.LinkCapabilities;
-import android.net.LinkProperties;
-import android.net.LinkSocketNotifier;
-
-import android.util.Log;
-
-import java.io.IOException;
-import java.net.Socket;
-import java.net.SocketAddress;
-import java.net.SocketTimeoutException;
-import java.net.UnknownHostException;
-import java.util.HashSet;
-import java.util.Set;
-
-/** @hide */
-public class LinkSocket extends Socket {
-    private final static String TAG = "LinkSocket";
-    private final static boolean DBG = true;
-
-    /**
-     * Default constructor
-     */
-    public LinkSocket() {
-        if (DBG) log("LinkSocket() EX");
-    }
-
-    /**
-     * Creates a new unconnected socket.
-     * @param notifier a reference to a class that implements {@code LinkSocketNotifier}
-     */
-    public LinkSocket(LinkSocketNotifier notifier) {
-        if (DBG) log("LinkSocket(notifier) EX");
-    }
-
-    /**
-     * Creates a new unconnected socket usign the given proxy type.
-     * @param notifier a reference to a class that implements {@code LinkSocketNotifier}
-     * @param proxy the specified proxy for this socket
-     * @throws IllegalArgumentException if the argument proxy is null or of an invalid type.
-     * @throws SecurityException if a security manager exists and it denies the permission
-     *                           to connect to the given proxy.
-     */
-    public LinkSocket(LinkSocketNotifier notifier, Proxy proxy) {
-        if (DBG) log("LinkSocket(notifier, proxy) EX");
-    }
-
-    /**
-     * @return the {@code LinkProperties} for the socket
-     */
-    public LinkProperties getLinkProperties() {
-        if (DBG) log("LinkProperties() EX");
-        return new LinkProperties();
-    }
-
-    /**
-     * Set the {@code LinkCapabilies} needed for this socket.  If the socket is already connected
-     * or is a duplicate socket the request is ignored and {@code false} will
-     * be returned. A needs map can be created via the {@code createNeedsMap} static
-     * method.
-     * @param needs the needs of the socket
-     * @return {@code true} if needs are successfully set, {@code false} otherwise
-     */
-    public boolean setNeededCapabilities(LinkCapabilities needs) {
-        if (DBG) log("setNeeds() EX");
-        return false;
-    }
-
-    /**
-     * @return the LinkCapabilites set by setNeededCapabilities, empty if none has been set
-     */
-    public LinkCapabilities getNeededCapabilities() {
-        if (DBG) log("getNeeds() EX");
-        return null;
-    }
-
-    /**
-     * @return all of the {@code LinkCapabilities} of the link used by this socket
-     */
-    public LinkCapabilities getCapabilities() {
-        if (DBG) log("getCapabilities() EX");
-        return null;
-    }
-
-    /**
-     * Returns this LinkSockets set of capabilities, filtered according to
-     * the given {@code Set}.  Capabilities in the Set but not available from
-     * the link will not be reported in the results.  Capabilities of the link
-     * but not listed in the Set will also not be reported in the results.
-     * @param capabilities {@code Set} of capabilities requested
-     * @return the filtered {@code LinkCapabilities} of this LinkSocket, may be empty
-     */
-    public LinkCapabilities getCapabilities(Set<Integer> capabilities) {
-        if (DBG) log("getCapabilities(capabilities) EX");
-        return new LinkCapabilities();
-    }
-
-    /**
-     * Provide the set of capabilities the application is interested in tracking
-     * for this LinkSocket.
-     * @param capabilities a {@code Set} of capabilities to track
-     */
-    public void setTrackedCapabilities(Set<Integer> capabilities) {
-        if (DBG) log("setTrackedCapabilities(capabilities) EX");
-    }
-
-    /**
-     * @return the {@code LinkCapabilities} that are tracked, empty if none has been set.
-     */
-    public Set<Integer> getTrackedCapabilities() {
-        if (DBG) log("getTrackedCapabilities(capabilities) EX");
-        return new HashSet<Integer>();
-    }
-
-    /**
-     * Connects this socket to the given remote host address and port specified
-     * by dstName and dstPort.
-     * @param dstName the address of the remote host to connect to
-     * @param dstPort the port to connect to on the remote host
-     * @param timeout the timeout value in milliseconds or 0 for infinite timeout
-     * @throws UnknownHostException if the given dstName is invalid
-     * @throws IOException if the socket is already connected or an error occurs
-     *                     while connecting
-     * @throws SocketTimeoutException if the timeout fires
-     */
-    public void connect(String dstName, int dstPort, int timeout)
-            throws UnknownHostException, IOException, SocketTimeoutException {
-        if (DBG) log("connect(dstName, dstPort, timeout) EX");
-    }
-
-    /**
-     * Connects this socket to the given remote host address and port specified
-     * by dstName and dstPort.
-     * @param dstName the address of the remote host to connect to
-     * @param dstPort the port to connect to on the remote host
-     * @throws UnknownHostException if the given dstName is invalid
-     * @throws IOException if the socket is already connected or an error occurs
-     *                     while connecting
-     */
-    public void connect(String dstName, int dstPort)
-            throws UnknownHostException, IOException {
-        if (DBG) log("connect(dstName, dstPort, timeout) EX");
-    }
-
-    /**
-     * Connects this socket to the given remote host address and port specified
-     * by the SocketAddress with the specified timeout.
-     * @deprecated Use {@code connect(String dstName, int dstPort, int timeout)}
-     *             instead.  Using this method may result in reduced functionality.
-     * @param remoteAddr the address and port of the remote host to connect to
-     * @throws IllegalArgumentException if the given SocketAddress is invalid
-     * @throws IOException if the socket is already connected or an error occurs
-     *                     while connecting
-     * @throws SocketTimeoutException if the timeout expires
-     */
-    @Override
-    @Deprecated
-    public void connect(SocketAddress remoteAddr, int timeout)
-            throws IOException, SocketTimeoutException {
-        if (DBG) log("connect(remoteAddr, timeout) EX DEPRECATED");
-    }
-
-    /**
-     * Connects this socket to the given remote host address and port specified
-     * by the SocketAddress.
-     * TODO add comment on all these that the network selection happens during connect
-     * and may take 30 seconds
-     * @deprecated Use {@code connect(String dstName, int dstPort)}
-     *             Using this method may result in reduced functionality.
-     * @param remoteAddr the address and port of the remote host to connect to.
-     * @throws IllegalArgumentException if the SocketAddress is invalid or not supported.
-     * @throws IOException if the socket is already connected or an error occurs
-     *                     while connecting
-     */
-    @Override
-    @Deprecated
-    public void connect(SocketAddress remoteAddr) throws IOException {
-        if (DBG) log("connect(remoteAddr) EX DEPRECATED");
-    }
-
-    /**
-     * Connect a duplicate socket socket to the same remote host address and port
-     * as the original with a timeout parameter.
-     * @param timeout the timeout value in milliseconds or 0 for infinite timeout
-     * @throws IOException if the socket is already connected or an error occurs
-     *                     while connecting
-     */
-    public void connect(int timeout) throws IOException {
-        if (DBG) log("connect(timeout) EX");
-    }
-
-    /**
-     * Connect a duplicate socket socket to the same remote host address and port
-     * as the original.
-     * @throws IOException if the socket is already connected or an error occurs
-     *                     while connecting
-     */
-    public void connect() throws IOException {
-        if (DBG) log("connect() EX");
-    }
-
-    /**
-     * Closes the socket.  It is not possible to reconnect or rebind to this
-     * socket thereafter which means a new socket instance has to be created.
-     * @throws IOException if an error occurs while closing the socket
-     */
-    @Override
-    public synchronized void close() throws IOException {
-        if (DBG) log("close() EX");
-    }
-
-    /**
-     * Request that a new LinkSocket be created using a different radio
-     * (such as WiFi or 3G) than the current LinkSocket.  If a different
-     * radio is available a call back will be made via {@code onBetterLinkAvail}.
-     * If unable to find a better radio, application will be notified via
-     * {@code onNewLinkUnavailable}
-     * @see LinkSocketNotifier#onBetterLinkAvailable(LinkSocket, LinkSocket)
-     * @param linkRequestReason reason for requesting a new link.
-     */
-    public void requestNewLink(LinkRequestReason linkRequestReason) {
-        if (DBG) log("requestNewLink(linkRequestReason) EX");
-    }
-
-    /**
-     * @deprecated LinkSocket will automatically pick the optimum interface
-     *             to bind to
-     * @param localAddr the specific address and port on the local machine
-     *                  to bind to
-     * @throws IOException always as this method is deprecated for LinkSocket
-     */
-    @Override
-    @Deprecated
-    public void bind(SocketAddress localAddr) throws UnsupportedOperationException {
-        if (DBG) log("bind(localAddr) EX throws IOException");
-        throw new UnsupportedOperationException("bind is deprecated for LinkSocket");
-    }
-
-    /**
-     * Reason codes an application can specify when requesting for a new link.
-     * TODO: need better documentation
-     */
-    public static final class LinkRequestReason {
-        /** No constructor */
-        private LinkRequestReason() {}
-
-        /** This link is working properly */
-        public static final int LINK_PROBLEM_NONE = 0;
-        /** This link has an unknown issue */
-        public static final int LINK_PROBLEM_UNKNOWN = 1;
-    }
-
-    /**
-     * Debug logging
-     */
-    protected static void log(String s) {
-        Log.d(TAG, s);
-    }
-}
diff --git a/core/java/android/net/LinkSocketNotifier.java b/core/java/android/net/LinkSocketNotifier.java
deleted file mode 100644
index e2429d8..0000000
--- a/core/java/android/net/LinkSocketNotifier.java
+++ /dev/null
@@ -1,86 +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;
-
-/**
- * Interface used to get feedback about a {@link android.net.LinkSocket}.  Instance is optionally
- * passed when a LinkSocket is constructed.  Multiple LinkSockets may use the same notifier.
- * @hide
- */
-public interface LinkSocketNotifier {
-    /**
-     * This callback function will be called if a better link
-     * becomes available.
-     * TODO - this shouldn't be checked for all cases - what's the conditional
-     *        flag?
-     * If the duplicate socket is accepted, the original will be marked invalid
-     * and additional use will throw exceptions.
-     * @param original the original LinkSocket
-     * @param duplicate the new LinkSocket that better meets the application
-     *                  requirements
-     * @return {@code true} if the application intends to use this link
-     *
-     * REM
-     * TODO - how agressive should we be?
-     * At a minimum CS tracks which LS have this turned on and tracks the requirements
-     * When a new link becomes available, automatically check if any of the LinkSockets
-     *   will care.
-     * If found, grab a refcount on the link so it doesn't go away and send notification
-     * Optionally, periodically setup connection on available networks to check for better links
-     * Maybe pass this info into the LinkFactories so condition changes can be acted on more quickly
-     */
-    public boolean onBetterLinkAvailable(LinkSocket original, LinkSocket duplicate);
-
-    /**
-     * This callback function will be called when a LinkSocket no longer has
-     * an active link.
-     * @param socket the LinkSocket that lost its link
-     *
-     * REM
-     * NetworkStateTracker tells us it is disconnected
-     * CS checks the table for LS on that link
-     * CS calls each callback (need to work out p2p cross process callback)
-     */
-    public void onLinkLost(LinkSocket socket);
-
-    /**
-     * This callback function will be called when an application calls
-     * requestNewLink on a LinkSocket but the LinkSocket is unable to find
-     * a suitable new link.
-     * @param socket the LinkSocket for which a new link was not found
-     * TODO - why the diff between initial request (sync) and requestNewLink?
-     *
-     * REM
-     * CS process of trying to find a new link must track the LS that started it
-     * on failure, call callback
-     */
-    public void onNewLinkUnavailable(LinkSocket socket);
-
-    /**
-     * This callback function will be called when any of the notification-marked
-     * capabilities of the LinkSocket (e.g. upstream bandwidth) have changed.
-     * @param socket the linkSocet for which capabilities have changed
-     * @param changedCapabilities the set of capabilities that the application
-     *                            is interested in and have changed (with new values)
-     *
-     * REM
-     * Maybe pass the interesting capabilities into the Links.
-     * Get notified of every capability change
-     * check for LinkSockets on that Link that are interested in that Capability - call them
-     */
-    public void onCapabilitiesChanged(LinkSocket socket, LinkCapabilities changedCapabilities);
-}
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 30b61c5..535bbe2 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -66,7 +66,6 @@
     private Handler mTarget;
     private Context mContext;
     private LinkProperties mLinkProperties;
-    private LinkCapabilities mLinkCapabilities;
     private boolean mPrivateDnsRouteSet = false;
     private boolean mDefaultRouteSet = false;
 
@@ -200,11 +199,11 @@
         }
         mLinkProperties.setMtu(mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_mobile_mtu));
-        mLinkCapabilities = intent.getParcelableExtra(
-                PhoneConstants.DATA_LINK_CAPABILITIES_KEY);
-        if (mLinkCapabilities == null) {
-            loge("CONNECTED event did not supply link capabilities.");
-            mLinkCapabilities = new LinkCapabilities();
+        mNetworkCapabilities = intent.getParcelableExtra(
+                PhoneConstants.DATA_NETWORK_CAPABILITIES_KEY);
+        if (mNetworkCapabilities == null) {
+            loge("CONNECTED event did not supply network capabilities.");
+            mNetworkCapabilities = new NetworkCapabilities();
         }
     }
 
@@ -316,10 +315,10 @@
                             Slog.d(TAG, "LinkProperties = " );
                         }
 
-                        if (mLinkCapabilities != null) {
-                            Slog.d(TAG, "LinkCapabilities = " + mLinkCapabilities);
+                        if (mNetworkCapabilities != null) {
+                            Slog.d(TAG, mNetworkCapabilities.toString());
                         } else {
-                            Slog.d(TAG, "LinkCapabilities = " );
+                            Slog.d(TAG, "NetworkCapabilities = " );
                         }
                     }
 
@@ -750,14 +749,6 @@
         return new LinkProperties(mLinkProperties);
     }
 
-    /**
-     * @see android.net.NetworkStateTracker#getLinkCapabilities()
-     */
-    @Override
-    public LinkCapabilities getLinkCapabilities() {
-        return new LinkCapabilities(mLinkCapabilities);
-    }
-
     public void supplyMessenger(Messenger messenger) {
         if (VDBG) log(mApnType + " got supplyMessenger");
         AsyncChannel ac = new AsyncChannel();
diff --git a/core/java/android/net/Network.aidl b/core/java/android/net/Network.aidl
new file mode 100644
index 0000000..73ba1af
--- /dev/null
+++ b/core/java/android/net/Network.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright (C) 2014 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES 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;
+
+parcelable Network;
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
new file mode 100644
index 0000000..ac1289b
--- /dev/null
+++ b/core/java/android/net/Network.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * Identifies the Network.
+ * @hide
+ */
+public class Network implements Parcelable {
+
+    public final int netId;
+
+    public Network(int netId) {
+        this.netId = netId;
+    }
+
+    public Network(Network that) {
+        this.netId = that.netId;
+    }
+
+    /**
+     * Operates the same as {@code InetAddress.getAllByName} except that host
+     * resolution is done on this network.
+     *
+     * @param host the hostname or literal IP string to be resolved.
+     * @return the array of addresses associated with the specified host.
+     * @throws UnknownHostException if the address lookup fails.
+     */
+    public InetAddress[] getAllByName(String host) throws UnknownHostException {
+        return InetAddress.getAllByNameOnNet(host, netId);
+    }
+
+    /**
+     * Operates the same as {@code InetAddress.getByName} except that host
+     * resolution is done on this network.
+     *
+     * @param host
+     *            the hostName to be resolved to an address or {@code null}.
+     * @return the {@code InetAddress} instance representing the host.
+     * @throws UnknownHostException
+     *             if the address lookup fails.
+     */
+    public InetAddress getByName(String host) throws UnknownHostException {
+        return InetAddress.getByNameOnNet(host, netId);
+    }
+
+    // implement the Parcelable interface
+    public int describeContents() {
+        return 0;
+    }
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(netId);
+    }
+
+    public static final Creator<Network> CREATOR =
+        new Creator<Network>() {
+            public Network createFromParcel(Parcel in) {
+                int netId = in.readInt();
+
+                return new Network(netId);
+            }
+
+            public Network[] newArray(int size) {
+                return new Network[size];
+            }
+    };
+}
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
new file mode 100644
index 0000000..4b85398
--- /dev/null
+++ b/core/java/android/net/NetworkAgent.java
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.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;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * A Utility class for handling NetworkRequests.
+ *
+ * Created by bearer-specific code to handle tracking requests, scores,
+ * network data and handle communicating with ConnectivityService.  Two
+ * abstract methods: connect and disconnect are used to act on the
+ * underlying bearer code.  Connect is called when we have a NetworkRequest
+ * and our score is better than the current handling network's score, while
+ * disconnect is used when ConnectivityService requests a disconnect.
+ *
+ * A bearer may have more than one NetworkAgent if it can simultaneously
+ * support separate networks (IMS / Internet / MMS Apns on cellular, or
+ * perhaps connections with different SSID or P2P for Wi-Fi).  The bearer
+ * code should pass its NetworkAgents the NetworkRequests each NetworkAgent
+ * can handle, demultiplexing for different network types.  The bearer code
+ * can also filter out requests it can never handle.
+ *
+ * Each NetworkAgent needs to be given a score and NetworkCapabilities for
+ * their potential network.  While disconnected, the NetworkAgent will check
+ * each time its score changes or a NetworkRequest changes to see if
+ * the NetworkAgent can provide a higher scored network for a NetworkRequest
+ * that the NetworkAgent's NetworkCapabilties can satisfy.  This condition will
+ * trigger a connect request via connect().  After connection, connection data
+ * should be given to the NetworkAgent by the bearer, including LinkProperties
+ * NetworkCapabilties and NetworkInfo.  After that the NetworkAgent will register
+ * with ConnectivityService and forward the data on.
+ * @hide
+ */
+public abstract class NetworkAgent extends Handler {
+    private final SparseArray<NetworkRequestAndScore> mNetworkRequests = new SparseArray<>();
+    private boolean mConnectionRequested = false;
+
+    private AsyncChannel mAsyncChannel;
+    private final String LOG_TAG;
+    private static final boolean DBG = true;
+    // TODO - this class shouldn't cache data or it runs the risk of getting out of sync
+    // Make the API require each of these when any is updated so we have the data we need,
+    // without caching.
+    private LinkProperties mLinkProperties;
+    private NetworkInfo mNetworkInfo;
+    private NetworkCapabilities mNetworkCapabilities;
+    private int mNetworkScore;
+    private boolean mRegistered = false;
+    private final Context mContext;
+    private AtomicBoolean mHasRequests = new AtomicBoolean(false);
+
+    // TODO - add a name member for logging purposes.
+
+    protected final Object mLockObj = new Object();
+
+
+    private static final int BASE = Protocol.BASE_NETWORK_AGENT;
+
+    /**
+     * Sent by self to queue up a new/modified request.
+     * obj = NetworkRequestAndScore
+     */
+    private static final int CMD_ADD_REQUEST = BASE + 1;
+
+    /**
+     * Sent by self to queue up the removal of a request.
+     * obj = NetworkRequest
+     */
+    private static final int CMD_REMOVE_REQUEST = BASE + 2;
+
+    /**
+     * Sent by ConnectivityService to the NetworkAgent to inform it of
+     * suspected connectivity problems on its network.  The NetworkAgent
+     * should take steps to verify and correct connectivity.
+     */
+    public static final int CMD_SUSPECT_BAD = BASE + 3;
+
+    /**
+     * Sent by the NetworkAgent (note the EVENT vs CMD prefix) to
+     * ConnectivityService to pass the current NetworkInfo (connection state).
+     * Sent when the NetworkInfo changes, mainly due to change of state.
+     * obj = NetworkInfo
+     */
+    public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 4;
+
+    /**
+     * Sent by the NetworkAgent to ConnectivityService to pass the current
+     * NetworkCapabilties.
+     * obj = NetworkCapabilities
+     */
+    public static final int EVENT_NETWORK_CAPABILITIES_CHANGED = BASE + 5;
+
+    /**
+     * Sent by the NetworkAgent to ConnectivityService to pass the current
+     * NetworkProperties.
+     * obj = NetworkProperties
+     */
+    public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 6;
+
+    /**
+     * Sent by the NetworkAgent to ConnectivityService to pass the current
+     * network score.
+     * arg1 = network score int
+     */
+    public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 7;
+
+    public NetworkAgent(Looper looper, Context context, String logTag) {
+        super(looper);
+        LOG_TAG = logTag;
+        mContext = context;
+    }
+
+    /**
+     * When conditions are right, register with ConnectivityService.
+     * Connditions include having a well defined network and a request
+     * that justifies it.  The NetworkAgent will remain registered until
+     * disconnected.
+     * TODO - this should have all data passed in rather than caching
+     */
+    private void registerSelf() {
+        synchronized(mLockObj) {
+            if (!mRegistered && mConnectionRequested &&
+                    mNetworkInfo != null && mNetworkInfo.isConnected() &&
+                    mNetworkCapabilities != null &&
+                    mLinkProperties != null &&
+                    mNetworkScore != 0) {
+                if (DBG) log("Registering NetworkAgent");
+                mRegistered = true;
+                ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
+                        Context.CONNECTIVITY_SERVICE);
+                cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(mNetworkInfo),
+                        new LinkProperties(mLinkProperties),
+                        new NetworkCapabilities(mNetworkCapabilities), mNetworkScore);
+            } else if (DBG && !mRegistered) {
+                String err = "Not registering due to ";
+                if (mConnectionRequested == false) err += "no Connect requested ";
+                if (mNetworkInfo == null) err += "null NetworkInfo ";
+                if (mNetworkInfo != null && mNetworkInfo.isConnected() == false) {
+                    err += "NetworkInfo disconnected ";
+                }
+                if (mLinkProperties == null) err += "null LinkProperties ";
+                if (mNetworkCapabilities == null) err += "null NetworkCapabilities ";
+                if (mNetworkScore == 0) err += "null NetworkScore";
+                log(err);
+            }
+        }
+    }
+
+    @Override
+    public void handleMessage(Message msg) {
+        switch (msg.what) {
+            case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
+                synchronized (mLockObj) {
+                    if (mAsyncChannel != null) {
+                        log("Received new connection while already connected!");
+                    } else {
+                        if (DBG) log("NetworkAgent fully connected");
+                        mAsyncChannel = new AsyncChannel();
+                        mAsyncChannel.connected(null, this, msg.replyTo);
+                        mAsyncChannel.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
+                                AsyncChannel.STATUS_SUCCESSFUL);
+                    }
+                }
+                break;
+            }
+            case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
+                if (DBG) log("CMD_CHANNEL_DISCONNECT");
+                if (mAsyncChannel != null) mAsyncChannel.disconnect();
+                break;
+            }
+            case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
+                if (DBG) log("NetworkAgent channel lost");
+                disconnect();
+                clear();
+                break;
+            }
+            case CMD_SUSPECT_BAD: {
+                log("Unhandled Message " + msg);
+                break;
+            }
+            case CMD_ADD_REQUEST: {
+                handleAddRequest(msg);
+                break;
+            }
+            case CMD_REMOVE_REQUEST: {
+                handleRemoveRequest(msg);
+                break;
+            }
+        }
+    }
+
+    private void clear() {
+        synchronized(mLockObj) {
+            mNetworkRequests.clear();
+            mHasRequests.set(false);
+            mConnectionRequested = false;
+            mAsyncChannel = null;
+            mRegistered = false;
+        }
+    }
+
+    private static class NetworkRequestAndScore {
+        NetworkRequest req;
+        int score;
+
+        NetworkRequestAndScore(NetworkRequest networkRequest, int score) {
+            req = networkRequest;
+            this.score = score;
+        }
+    }
+
+    private void handleAddRequest(Message msg) {
+        NetworkRequestAndScore n = (NetworkRequestAndScore)msg.obj;
+        // replaces old request, updating score
+        mNetworkRequests.put(n.req.requestId, n);
+        mHasRequests.set(true);
+        evalScores();
+    }
+
+    private void handleRemoveRequest(Message msg) {
+        NetworkRequest networkRequest = (NetworkRequest)msg.obj;
+
+        if (mNetworkRequests.get(networkRequest.requestId) != null) {
+            mNetworkRequests.remove(networkRequest.requestId);
+            if (mNetworkRequests.size() == 0) mHasRequests.set(false);
+            evalScores();
+        }
+    }
+
+    /**
+     * called to go through our list of requests and see if we're
+     * good enough to try connecting.
+     *
+     * Only does connects - we disconnect when requested via
+     * CMD_CHANNEL_DISCONNECTED, generated by either a loss of connection
+     * between modules (bearer or ConnectivityService dies) or more commonly
+     * when the NetworkInfo reports to ConnectivityService it is disconnected.
+     */
+    private void evalScores() {
+        if (mConnectionRequested) {
+            // already trying
+            return;
+        }
+        for (int i=0; i < mNetworkRequests.size(); i++) {
+            int score = mNetworkRequests.valueAt(i).score;
+            if (score < mNetworkScore) {
+                // have a request that has a lower scored network servicing it
+                // (or no network) than we could provide, so lets connect!
+                mConnectionRequested = true;
+                connect();
+                return;
+            }
+        }
+    }
+
+    public void addNetworkRequest(NetworkRequest networkRequest, int score) {
+        if (DBG) log("adding NetworkRequest " + networkRequest + " with score " + score);
+        sendMessage(obtainMessage(CMD_ADD_REQUEST,
+                new NetworkRequestAndScore(networkRequest, score)));
+    }
+
+    public void removeNetworkRequest(NetworkRequest networkRequest) {
+        if (DBG) log("removing NetworkRequest " + networkRequest);
+        sendMessage(obtainMessage(CMD_REMOVE_REQUEST, networkRequest));
+    }
+
+    /**
+     * Called by the bearer code when it has new LinkProperties data.
+     * If we're a registered NetworkAgent, this new data will get forwarded on,
+     * otherwise we store a copy in anticipation of registering.  This call
+     * may also prompt registration if it causes the NetworkAgent to meet
+     * the conditions (fully configured, connected, satisfys a request and
+     * has sufficient score).
+     */
+    public void sendLinkProperties(LinkProperties linkProperties) {
+        linkProperties = new LinkProperties(linkProperties);
+        synchronized(mLockObj) {
+            mLinkProperties = linkProperties;
+            if (mAsyncChannel != null) {
+                mAsyncChannel.sendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, linkProperties);
+            } else {
+                registerSelf();
+            }
+        }
+    }
+
+    /**
+     * Called by the bearer code when it has new NetworkInfo data.
+     * If we're a registered NetworkAgent, this new data will get forwarded on,
+     * otherwise we store a copy in anticipation of registering.  This call
+     * may also prompt registration if it causes the NetworkAgent to meet
+     * the conditions (fully configured, connected, satisfys a request and
+     * has sufficient score).
+     */
+    public void sendNetworkInfo(NetworkInfo networkInfo) {
+        networkInfo = new NetworkInfo(networkInfo);
+        synchronized(mLockObj) {
+            mNetworkInfo = networkInfo;
+            if (mAsyncChannel != null) {
+                mAsyncChannel.sendMessage(EVENT_NETWORK_INFO_CHANGED, networkInfo);
+            } else {
+                registerSelf();
+            }
+        }
+    }
+
+    /**
+     * Called by the bearer code when it has new NetworkCapabilities data.
+     * If we're a registered NetworkAgent, this new data will get forwarded on,
+     * otherwise we store a copy in anticipation of registering.  This call
+     * may also prompt registration if it causes the NetworkAgent to meet
+     * the conditions (fully configured, connected, satisfys a request and
+     * has sufficient score).
+     * Note that if these capabilities make the network non-useful,
+     * ConnectivityServce will tear this network down.
+     */
+    public void sendNetworkCapabilities(NetworkCapabilities networkCapabilities) {
+        networkCapabilities = new NetworkCapabilities(networkCapabilities);
+        synchronized(mLockObj) {
+            mNetworkCapabilities = networkCapabilities;
+            if (mAsyncChannel != null) {
+                mAsyncChannel.sendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, networkCapabilities);
+            } else {
+                registerSelf();
+            }
+        }
+    }
+
+    public NetworkCapabilities getNetworkCapabilities() {
+        synchronized(mLockObj) {
+            return new NetworkCapabilities(mNetworkCapabilities);
+        }
+    }
+
+    /**
+     * Called by the bearer code when it has a new score for this network.
+     * If we're a registered NetworkAgent, this new data will get forwarded on,
+     * otherwise we store a copy.
+     */
+    public synchronized void sendNetworkScore(int score) {
+        synchronized(mLockObj) {
+            mNetworkScore = score;
+            evalScores();
+            if (mAsyncChannel != null) {
+                mAsyncChannel.sendMessage(EVENT_NETWORK_SCORE_CHANGED, mNetworkScore);
+            } else {
+                registerSelf();
+            }
+        }
+    }
+
+    public boolean hasRequests() {
+        return mHasRequests.get();
+    }
+
+    public boolean isConnectionRequested() {
+        synchronized(mLockObj) {
+            return mConnectionRequested;
+        }
+    }
+
+
+    abstract protected void connect();
+    abstract protected void disconnect();
+
+    protected void log(String s) {
+        Log.d(LOG_TAG, "NetworkAgent: " + s);
+    }
+}
diff --git a/core/java/android/net/NetworkCapabilities.aidl b/core/java/android/net/NetworkCapabilities.aidl
new file mode 100644
index 0000000..cd7d71c
--- /dev/null
+++ b/core/java/android/net/NetworkCapabilities.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** Copyright (C) 2014 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+parcelable NetworkCapabilities;
+
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
new file mode 100644
index 0000000..8005e5c
--- /dev/null
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.lang.IllegalArgumentException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * A class representing the capabilities of a network
+ * @hide
+ */
+public final class NetworkCapabilities implements Parcelable {
+    private static final String TAG = "NetworkCapabilities";
+    private static final boolean DBG = false;
+
+
+    /**
+     * Represents the network's capabilities.  If any are specified they will be satisfied
+     * by any Network that matches all of them.
+     */
+    private long mNetworkCapabilities = (1 << NET_CAPABILITY_NOT_RESTRICTED);
+
+    /**
+     * Values for NetworkCapabilities.  Roughly matches/extends deprecated
+     * ConnectivityManager TYPE_*
+     */
+    public static final int NET_CAPABILITY_MMS            = 0;
+    public static final int NET_CAPABILITY_SUPL           = 1;
+    public static final int NET_CAPABILITY_DUN            = 2;
+    public static final int NET_CAPABILITY_FOTA           = 3;
+    public static final int NET_CAPABILITY_IMS            = 4;
+    public static final int NET_CAPABILITY_CBS            = 5;
+    public static final int NET_CAPABILITY_WIFI_P2P       = 6;
+    public static final int NET_CAPABILITY_IA             = 7;
+    public static final int NET_CAPABILITY_RCS            = 8;
+    public static final int NET_CAPABILITY_XCAP           = 9;
+    public static final int NET_CAPABILITY_EIMS           = 10;
+    public static final int NET_CAPABILITY_NOT_METERED    = 11;
+    public static final int NET_CAPABILITY_INTERNET       = 12;
+    /** Set by default */
+    public static final int NET_CAPABILITY_NOT_RESTRICTED = 13;
+
+    private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
+    private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_RESTRICTED;
+
+    public void addNetworkCapability(int networkCapability) {
+        if (networkCapability < MIN_NET_CAPABILITY ||
+                networkCapability > MAX_NET_CAPABILITY) {
+            throw new IllegalArgumentException("NetworkCapability out of range");
+        }
+        mNetworkCapabilities |= 1 << networkCapability;
+    }
+    public void removeNetworkCapability(int networkCapability) {
+        if (networkCapability < MIN_NET_CAPABILITY ||
+                networkCapability > MAX_NET_CAPABILITY) {
+            throw new IllegalArgumentException("NetworkCapability out of range");
+        }
+        mNetworkCapabilities &= ~(1 << networkCapability);
+    }
+    public Collection<Integer> getNetworkCapabilities() {
+        return enumerateBits(mNetworkCapabilities);
+    }
+    public boolean hasCapability(int networkCapability) {
+        if (networkCapability < MIN_NET_CAPABILITY ||
+                networkCapability > MAX_NET_CAPABILITY) {
+            return false;
+        }
+        return ((mNetworkCapabilities & (1 << networkCapability)) != 0);
+    }
+
+    private Collection<Integer> enumerateBits(long val) {
+        ArrayList<Integer> result = new ArrayList<Integer>();
+        int resource = 0;
+        while (val > 0) {
+            if ((val & 1) == 1) result.add(resource);
+            val = val >> 1;
+            resource++;
+        }
+        return result;
+    }
+
+    private void combineNetCapabilities(NetworkCapabilities nc) {
+        this.mNetworkCapabilities |= nc.mNetworkCapabilities;
+    }
+
+    private boolean satisfiedByNetCapabilities(NetworkCapabilities nc) {
+        return ((nc.mNetworkCapabilities & this.mNetworkCapabilities) == this.mNetworkCapabilities);
+    }
+
+    private boolean equalsNetCapabilities(NetworkCapabilities nc) {
+        return (nc.mNetworkCapabilities == this.mNetworkCapabilities);
+    }
+
+    /**
+     * Representing the transport type.  Apps should generally not care about transport.  A
+     * request for a fast internet connection could be satisfied by a number of different
+     * transports.  If any are specified here it will be satisfied a Network that matches
+     * any of them.  If a caller doesn't care about the transport it should not specify any.
+     */
+    private long mTransportTypes;
+
+    /**
+     * Values for TransportType
+     */
+    public static final int TRANSPORT_CELLULAR = 0;
+    public static final int TRANSPORT_WIFI = 1;
+    public static final int TRANSPORT_BLUETOOTH = 2;
+    public static final int TRANSPORT_ETHERNET = 3;
+
+    private static final int MIN_TRANSPORT = TRANSPORT_CELLULAR;
+    private static final int MAX_TRANSPORT = TRANSPORT_ETHERNET;
+
+    public void addTransportType(int transportType) {
+        if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
+            throw new IllegalArgumentException("TransportType out of range");
+        }
+        mTransportTypes |= 1 << transportType;
+    }
+    public void removeTransportType(int transportType) {
+        if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
+            throw new IllegalArgumentException("TransportType out of range");
+        }
+        mTransportTypes &= ~(1 << transportType);
+    }
+    public Collection<Integer> getTransportTypes() {
+        return enumerateBits(mTransportTypes);
+    }
+    public boolean hasTransport(int transportType) {
+        if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
+            return false;
+        }
+        return ((mTransportTypes & (1 << transportType)) != 0);
+    }
+
+    private void combineTransportTypes(NetworkCapabilities nc) {
+        this.mTransportTypes |= nc.mTransportTypes;
+    }
+    private boolean satisfiedByTransportTypes(NetworkCapabilities nc) {
+        return ((this.mTransportTypes == 0) ||
+                ((this.mTransportTypes & nc.mTransportTypes) != 0));
+    }
+    private boolean equalsTransportTypes(NetworkCapabilities nc) {
+        return (nc.mTransportTypes == this.mTransportTypes);
+    }
+
+    /**
+     * Passive link bandwidth.  This is a rough guide of the expected peak bandwidth
+     * for the first hop on the given transport.  It is not measured, but may take into account
+     * link parameters (Radio technology, allocated channels, etc).
+     */
+    private int mLinkUpBandwidthKbps;
+    private int mLinkDownBandwidthKbps;
+
+    public void setLinkUpstreamBandwidthKbps(int upKbps) {
+        mLinkUpBandwidthKbps = upKbps;
+    }
+    public int getLinkUpstreamBandwidthKbps() {
+        return mLinkUpBandwidthKbps;
+    }
+    public void setLinkDownstreamBandwidthKbps(int downKbps) {
+        mLinkDownBandwidthKbps = downKbps;
+    }
+    public int getLinkDownstreamBandwidthKbps() {
+        return mLinkDownBandwidthKbps;
+    }
+
+    private void combineLinkBandwidths(NetworkCapabilities nc) {
+        this.mLinkUpBandwidthKbps =
+                Math.max(this.mLinkUpBandwidthKbps, nc.mLinkUpBandwidthKbps);
+        this.mLinkDownBandwidthKbps =
+                Math.max(this.mLinkDownBandwidthKbps, nc.mLinkDownBandwidthKbps);
+    }
+    private boolean satisfiedByLinkBandwidths(NetworkCapabilities nc) {
+        return !(this.mLinkUpBandwidthKbps > nc.mLinkUpBandwidthKbps ||
+                this.mLinkDownBandwidthKbps > nc.mLinkDownBandwidthKbps);
+    }
+    private boolean equalsLinkBandwidths(NetworkCapabilities nc) {
+        return (this.mLinkUpBandwidthKbps == nc.mLinkUpBandwidthKbps &&
+                this.mLinkDownBandwidthKbps == nc.mLinkDownBandwidthKbps);
+    }
+
+    /**
+     * Combine a set of Capabilities to this one.  Useful for coming up with the complete set
+     * {@hide}
+     */
+    public void combineCapabilities(NetworkCapabilities nc) {
+        combineNetCapabilities(nc);
+        combineTransportTypes(nc);
+        combineLinkBandwidths(nc);
+    }
+
+    /**
+     * Check if our requirements are satisfied by the given Capabilities.
+     * {@hide}
+     */
+    public boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc) {
+        return (nc != null &&
+                satisfiedByNetCapabilities(nc) &&
+                satisfiedByTransportTypes(nc) &&
+                satisfiedByLinkBandwidths(nc));
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null || (obj instanceof NetworkCapabilities == false)) return false;
+        NetworkCapabilities that = (NetworkCapabilities)obj;
+        return (equalsNetCapabilities(that) &&
+                equalsTransportTypes(that) &&
+                equalsLinkBandwidths(that));
+    }
+
+    @Override
+    public int hashCode() {
+        return ((int)(mNetworkCapabilities & 0xFFFFFFFF) +
+                ((int)(mNetworkCapabilities >> 32) * 3) +
+                ((int)(mTransportTypes & 0xFFFFFFFF) * 5) +
+                ((int)(mTransportTypes >> 32) * 7) +
+                (mLinkUpBandwidthKbps * 11) +
+                (mLinkDownBandwidthKbps * 13));
+    }
+
+    public NetworkCapabilities() {
+    }
+
+    public NetworkCapabilities(NetworkCapabilities nc) {
+        if (nc != null) {
+            mNetworkCapabilities = nc.mNetworkCapabilities;
+            mTransportTypes = nc.mTransportTypes;
+            mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
+            mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
+        }
+    }
+
+    // Parcelable
+    public int describeContents() {
+        return 0;
+    }
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(mNetworkCapabilities);
+        dest.writeLong(mTransportTypes);
+        dest.writeInt(mLinkUpBandwidthKbps);
+        dest.writeInt(mLinkDownBandwidthKbps);
+    }
+    public static final Creator<NetworkCapabilities> CREATOR =
+        new Creator<NetworkCapabilities>() {
+            public NetworkCapabilities createFromParcel(Parcel in) {
+                NetworkCapabilities netCap = new NetworkCapabilities();
+
+                netCap.mNetworkCapabilities = in.readLong();
+                netCap.mTransportTypes = in.readLong();
+                netCap.mLinkUpBandwidthKbps = in.readInt();
+                netCap.mLinkDownBandwidthKbps = in.readInt();
+                return netCap;
+            }
+            public NetworkCapabilities[] newArray(int size) {
+                return new NetworkCapabilities[size];
+            }
+        };
+
+    public String toString() {
+        Collection<Integer> types = getTransportTypes();
+        String transports = (types.size() > 0 ? " Transports: " : "");
+        Iterator<Integer> i = types.iterator();
+        while (i.hasNext()) {
+            switch (i.next()) {
+                case TRANSPORT_CELLULAR:    transports += "CELLULAR"; break;
+                case TRANSPORT_WIFI:        transports += "WIFI"; break;
+                case TRANSPORT_BLUETOOTH:   transports += "BLUETOOTH"; break;
+                case TRANSPORT_ETHERNET:    transports += "ETHERNET"; break;
+            }
+            if (i.hasNext()) transports += "|";
+        }
+
+        types = getNetworkCapabilities();
+        String capabilities = (types.size() > 0 ? " Capabilities: " : "");
+        i = types.iterator();
+        while (i.hasNext()) {
+            switch (i.next().intValue()) {
+                case NET_CAPABILITY_MMS:            capabilities += "MMS"; break;
+                case NET_CAPABILITY_SUPL:           capabilities += "SUPL"; break;
+                case NET_CAPABILITY_DUN:            capabilities += "DUN"; break;
+                case NET_CAPABILITY_FOTA:           capabilities += "FOTA"; break;
+                case NET_CAPABILITY_IMS:            capabilities += "IMS"; break;
+                case NET_CAPABILITY_CBS:            capabilities += "CBS"; break;
+                case NET_CAPABILITY_WIFI_P2P:       capabilities += "WIFI_P2P"; break;
+                case NET_CAPABILITY_IA:             capabilities += "IA"; break;
+                case NET_CAPABILITY_RCS:            capabilities += "RCS"; break;
+                case NET_CAPABILITY_XCAP:           capabilities += "XCAP"; break;
+                case NET_CAPABILITY_EIMS:           capabilities += "EIMS"; break;
+                case NET_CAPABILITY_NOT_METERED:    capabilities += "NOT_METERED"; break;
+                case NET_CAPABILITY_INTERNET:       capabilities += "INTERNET"; break;
+                case NET_CAPABILITY_NOT_RESTRICTED: capabilities += "NOT_RESTRICTED"; break;
+            }
+            if (i.hasNext()) capabilities += "&";
+        }
+
+        String upBand = ((mLinkUpBandwidthKbps > 0) ? " LinkUpBandwidth>=" +
+                mLinkUpBandwidthKbps + "Kbps" : "");
+        String dnBand = ((mLinkDownBandwidthKbps > 0) ? " LinkDnBandwidth>=" +
+                mLinkDownBandwidthKbps + "Kbps" : "");
+
+        return "[" + transports + capabilities + upBand + dnBand + "]";
+    }
+}
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 53b1308..9e656ee 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -420,7 +420,7 @@
     @Override
     public String toString() {
         synchronized (this) {
-            StringBuilder builder = new StringBuilder("NetworkInfo: ");
+            StringBuilder builder = new StringBuilder("[");
             builder.append("type: ").append(getTypeName()).append("[").append(getSubtypeName()).
             append("], state: ").append(mState).append("/").append(mDetailedState).
             append(", reason: ").append(mReason == null ? "(unspecified)" : mReason).
@@ -429,7 +429,8 @@
             append(", failover: ").append(mIsFailover).
             append(", isAvailable: ").append(mIsAvailable).
             append(", isConnectedToProvisioningNetwork: ").
-                    append(mIsConnectedToProvisioningNetwork);
+            append(mIsConnectedToProvisioningNetwork).
+            append("]");
             return builder.toString();
         }
     }
diff --git a/core/java/android/net/NetworkRequest.aidl b/core/java/android/net/NetworkRequest.aidl
new file mode 100644
index 0000000..508defc
--- /dev/null
+++ b/core/java/android/net/NetworkRequest.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+
+parcelable NetworkRequest;
+
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
new file mode 100644
index 0000000..b3ae3f5
--- /dev/null
+++ b/core/java/android/net/NetworkRequest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.Parcel;
+import android.os.Parcelable;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @hide
+ */
+public class NetworkRequest implements Parcelable {
+    /**
+     * The NetworkCapabilities that define this request
+     */
+    public final NetworkCapabilities networkCapabilities;
+
+    /**
+     * Identifies the request.  NetworkRequests should only be constructed by
+     * the Framework and given out to applications as tokens to be used to identify
+     * the request.
+     * TODO - make sure this input is checked whenever a NR is passed in a public API
+     */
+    public final int requestId;
+
+    /**
+     * Set for legacy requests and the default.
+     * Causes CONNECTIVITY_ACTION broadcasts to be sent.
+     * @hide
+     */
+    public final boolean needsBroadcasts;
+
+    private static final AtomicInteger sNextRequestId = new AtomicInteger(1);
+
+    /**
+     * @hide
+     */
+    public NetworkRequest(NetworkCapabilities nc) {
+        this(nc, false, sNextRequestId.getAndIncrement());
+    }
+
+    /**
+     * @hide
+     */
+    public NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts) {
+        this(nc, needsBroadcasts, sNextRequestId.getAndIncrement());
+    }
+
+    /**
+     * @hide
+     */
+    private NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts, int rId) {
+        requestId = rId;
+        networkCapabilities = nc;
+        this.needsBroadcasts = needsBroadcasts;
+    }
+
+    public NetworkRequest(NetworkRequest that) {
+        networkCapabilities = new NetworkCapabilities(that.networkCapabilities);
+        requestId = that.requestId;
+        needsBroadcasts = that.needsBroadcasts;
+    }
+
+    // implement the Parcelable interface
+    public int describeContents() {
+        return 0;
+    }
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(networkCapabilities, flags);
+        dest.writeInt(needsBroadcasts ? 1 : 0);
+        dest.writeInt(requestId);
+    }
+    public static final Creator<NetworkRequest> CREATOR =
+        new Creator<NetworkRequest>() {
+            public NetworkRequest createFromParcel(Parcel in) {
+                NetworkCapabilities nc = (NetworkCapabilities)in.readParcelable(null);
+                boolean needsBroadcasts = (in.readInt() == 1);
+                int requestId = in.readInt();
+                NetworkRequest result = new NetworkRequest(nc, needsBroadcasts, requestId);
+                return result;
+            }
+            public NetworkRequest[] newArray(int size) {
+                return new NetworkRequest[size];
+            }
+        };
+
+    public String toString() {
+        return "NetworkRequest [ id=" + requestId + ", needsBroadcasts=" + needsBroadcasts +
+                ", " + networkCapabilities.toString() + " ]";
+    }
+
+    public boolean equals(Object obj) {
+        if (obj instanceof NetworkRequest == false) return false;
+        NetworkRequest that = (NetworkRequest)obj;
+        return (that.needsBroadcasts == this.needsBroadcasts &&
+                that.requestId == this.requestId &&
+                ((that.networkCapabilities == null && this.networkCapabilities == null) ||
+                 (that.networkCapabilities != null &&
+                  that.networkCapabilities.equals(this.networkCapabilities))));
+    }
+
+    public int hashCode() {
+        return requestId + (needsBroadcasts ? 1013 : 2026) +
+                (networkCapabilities.hashCode() * 1051);
+    }
+}
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 6dd56d9..352512e 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -19,6 +19,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.Context;
+import android.content.Intent;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -101,7 +102,7 @@
      * determine the current scorer and offer the user the ability to select a different scorer via
      * the {@link #ACTION_CHANGE_ACTIVE} intent.
      * @return the full package name of the current active scorer, or null if there is no active
-     *     scorer.
+     *         scorer.
      */
     public String getActiveScorerPackage() {
         return NetworkScorerAppManager.getActiveScorer(mContext);
@@ -151,8 +152,8 @@
      *
      * @return true if the operation succeeded, or false if the new package is not a valid scorer.
      * @throws SecurityException if the caller does not hold the
-     *      {@link android.Manifest.permission#BROADCAST_SCORE_NETWORKS} permission indicating that
-     *      it can manage scorer applications.
+     *         {@link android.Manifest.permission#BROADCAST_SCORE_NETWORKS} permission indicating
+     *         that it can manage scorer applications.
      * @hide
      */
     public boolean setActiveScorer(String packageName) throws SecurityException {
@@ -162,4 +163,44 @@
             return false;
         }
     }
+
+    /**
+     * Request scoring for networks.
+     *
+     * <p>Note that this is just a helper method to assemble the broadcast, and will run in the
+     * calling process.
+     *
+     * @return true if the broadcast was sent, or false if there is no active scorer.
+     * @throws SecurityException if the caller does not hold the
+     *         {@link android.Manifest.permission#BROADCAST_SCORE_NETWORKS} permission.
+     * @hide
+     */
+    public boolean requestScores(NetworkKey[] networks) throws SecurityException {
+        String activeScorer = getActiveScorerPackage();
+        if (activeScorer == null) {
+            return false;
+        }
+        Intent intent = new Intent(ACTION_SCORE_NETWORKS);
+        intent.setPackage(activeScorer);
+        intent.putExtra(EXTRA_NETWORKS_TO_SCORE, networks);
+        mContext.sendBroadcast(intent);
+        return true;
+    }
+
+    /**
+     * Register a network score cache.
+     *
+     * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
+     * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
+     * @throws SecurityException if the caller does not hold the
+     *         {@link android.Manifest.permission#BROADCAST_SCORE_NETWORKS} permission.
+     * @throws IllegalArgumentException if a score cache is already registered for this type.
+     * @hide
+     */
+    public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
+        try {
+            mService.registerNetworkScoreCache(networkType, scoreCache);
+        } catch (RemoteException e) {
+        }
+    }
 }
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index fbe1f82..2e0e9e4 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -28,21 +28,21 @@
 
     public final NetworkInfo networkInfo;
     public final LinkProperties linkProperties;
-    public final LinkCapabilities linkCapabilities;
+    public final NetworkCapabilities networkCapabilities;
     /** Currently only used by testing. */
     public final String subscriberId;
     public final String networkId;
 
     public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties,
-            LinkCapabilities linkCapabilities) {
-        this(networkInfo, linkProperties, linkCapabilities, null, null);
+            NetworkCapabilities networkCapabilities) {
+        this(networkInfo, linkProperties, networkCapabilities, null, null);
     }
 
     public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties,
-            LinkCapabilities linkCapabilities, String subscriberId, String networkId) {
+            NetworkCapabilities networkCapabilities, String subscriberId, String networkId) {
         this.networkInfo = networkInfo;
         this.linkProperties = linkProperties;
-        this.linkCapabilities = linkCapabilities;
+        this.networkCapabilities = networkCapabilities;
         this.subscriberId = subscriberId;
         this.networkId = networkId;
     }
@@ -50,7 +50,7 @@
     public NetworkState(Parcel in) {
         networkInfo = in.readParcelable(null);
         linkProperties = in.readParcelable(null);
-        linkCapabilities = in.readParcelable(null);
+        networkCapabilities = in.readParcelable(null);
         subscriberId = in.readString();
         networkId = in.readString();
     }
@@ -64,7 +64,7 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeParcelable(networkInfo, flags);
         out.writeParcelable(linkProperties, flags);
-        out.writeParcelable(linkCapabilities, flags);
+        out.writeParcelable(networkCapabilities, flags);
         out.writeString(subscriberId);
         out.writeString(networkId);
     }
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
index c49b1d1..35500cc 100644
--- a/core/java/android/net/NetworkStateTracker.java
+++ b/core/java/android/net/NetworkStateTracker.java
@@ -111,12 +111,9 @@
     public LinkProperties getLinkProperties();
 
     /**
-     * A capability is an Integer/String pair, the capabilities
-     * are defined in the class LinkSocket#Key.
-     *
      * @return a copy of this connections capabilities, may be empty but never null.
      */
-    public LinkCapabilities getLinkCapabilities();
+    public NetworkCapabilities getNetworkCapabilities();
 
     /**
      * Get interesting information about this network link
@@ -250,4 +247,14 @@
      */
     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/Proxy.java b/core/java/android/net/Proxy.java
index 033332c..6a78c29 100644
--- a/core/java/android/net/Proxy.java
+++ b/core/java/android/net/Proxy.java
@@ -19,6 +19,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.Context;
+import android.net.ProxyInfo;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -63,8 +64,11 @@
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
-    /** {@hide} **/
-    public static final String EXTRA_PROXY_INFO = "proxy";
+    /**
+     * Intent extra included with {@link #PROXY_CHANGE_ACTION} intents.
+     * It describes the new proxy being used (as a {@link ProxyInfo} object).
+     */
+    public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
 
     /** @hide */
     public static final int PROXY_VALID             = 0;
@@ -114,24 +118,14 @@
      */
     public static final java.net.Proxy getProxy(Context ctx, String url) {
         String host = "";
-        if (url != null) {
+        if ((url != null) && !isLocalHost(host)) {
             URI uri = URI.create(url);
-            host = uri.getHost();
-        }
+            ProxySelector proxySelector = ProxySelector.getDefault();
 
-        if (!isLocalHost(host)) {
-            if (sConnectivityManager == null) {
-                sConnectivityManager = (ConnectivityManager)ctx.getSystemService(
-                        Context.CONNECTIVITY_SERVICE);
-            }
-            if (sConnectivityManager == null) return java.net.Proxy.NO_PROXY;
+            List<java.net.Proxy> proxyList = proxySelector.select(uri);
 
-            ProxyProperties proxyProperties = sConnectivityManager.getProxy();
-
-            if (proxyProperties != null) {
-                if (!proxyProperties.isExcluded(host)) {
-                    return proxyProperties.makeProxy();
-                }
+            if (proxyList.size() > 0) {
+                return proxyList.get(0);
             }
         }
         return java.net.Proxy.NO_PROXY;
@@ -274,58 +268,16 @@
         return PROXY_VALID;
     }
 
-    static class AndroidProxySelectorRoutePlanner
-            extends org.apache.http.impl.conn.ProxySelectorRoutePlanner {
-
-        private Context mContext;
-
-        public AndroidProxySelectorRoutePlanner(SchemeRegistry schreg, ProxySelector prosel,
-                Context context) {
-            super(schreg, prosel);
-            mContext = context;
-        }
-
-        @Override
-        protected java.net.Proxy chooseProxy(List<java.net.Proxy> proxies, HttpHost target,
-                HttpRequest request, HttpContext context) {
-            return getProxy(mContext, target.getHostName());
-        }
-
-        @Override
-        protected HttpHost determineProxy(HttpHost target, HttpRequest request,
-                HttpContext context) {
-            return getPreferredHttpHost(mContext, target.getHostName());
-        }
-
-        @Override
-        public HttpRoute determineRoute(HttpHost target, HttpRequest request,
-                HttpContext context) {
-            HttpHost proxy = getPreferredHttpHost(mContext, target.getHostName());
-            if (proxy == null) {
-                return new HttpRoute(target);
-            } else {
-                return new HttpRoute(target, null, proxy, false);
-            }
-        }
-    }
-
     /** @hide */
-    public static final HttpRoutePlanner getAndroidProxySelectorRoutePlanner(Context context) {
-        AndroidProxySelectorRoutePlanner ret = new AndroidProxySelectorRoutePlanner(
-                new SchemeRegistry(), ProxySelector.getDefault(), context);
-        return ret;
-    }
-
-    /** @hide */
-    public static final void setHttpProxySystemProperty(ProxyProperties p) {
+    public static final void setHttpProxySystemProperty(ProxyInfo p) {
         String host = null;
         String port = null;
         String exclList = null;
-        String pacFileUrl = null;
+        Uri pacFileUrl = Uri.EMPTY;
         if (p != null) {
             host = p.getHost();
             port = Integer.toString(p.getPort());
-            exclList = p.getExclusionList();
+            exclList = p.getExclusionListAsString();
             pacFileUrl = p.getPacFileUrl();
         }
         setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
@@ -333,7 +285,7 @@
 
     /** @hide */
     public static final void setHttpProxySystemProperty(String host, String port, String exclList,
-            String pacFileUrl) {
+            Uri pacFileUrl) {
         if (exclList != null) exclList = exclList.replace(",", "|");
         if (false) Log.d(TAG, "setHttpProxySystemProperty :"+host+":"+port+" - "+exclList);
         if (host != null) {
@@ -357,7 +309,7 @@
             System.clearProperty("http.nonProxyHosts");
             System.clearProperty("https.nonProxyHosts");
         }
-        if (!TextUtils.isEmpty(pacFileUrl)) {
+        if (!Uri.EMPTY.equals(pacFileUrl)) {
             ProxySelector.setDefault(new PacProxySelector());
         } else {
             ProxySelector.setDefault(sDefaultProxySelector);
diff --git a/core/java/android/net/ProxyDataTracker.java b/core/java/android/net/ProxyDataTracker.java
index 461e8b8..4973b3d 100644
--- a/core/java/android/net/ProxyDataTracker.java
+++ b/core/java/android/net/ProxyDataTracker.java
@@ -104,7 +104,7 @@
     public ProxyDataTracker() {
         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_PROXY, 0, NETWORK_TYPE, "");
         mLinkProperties = new LinkProperties();
-        mLinkCapabilities = new LinkCapabilities();
+        mNetworkCapabilities = new NetworkCapabilities();
         mNetworkInfo.setIsAvailable(true);
         try {
           mLinkProperties.addDns(InetAddress.getByName(DNS1));
diff --git a/core/java/android/net/ProxyInfo.aidl b/core/java/android/net/ProxyInfo.aidl
new file mode 100644
index 0000000..2c91960
--- /dev/null
+++ b/core/java/android/net/ProxyInfo.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** 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;
+
+parcelable ProxyInfo;
+
diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java
new file mode 100644
index 0000000..ceedd98
--- /dev/null
+++ b/core/java/android/net/ProxyInfo.java
@@ -0,0 +1,369 @@
+/*
+ * 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;
+
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import org.apache.http.client.HttpClient;
+
+import java.net.InetSocketAddress;
+import java.net.URLConnection;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Describes a proxy configuration.
+ *
+ * Proxy configurations are already integrated within the Apache HTTP stack.
+ * So {@link URLConnection} and {@link HttpClient} will use them automatically.
+ *
+ * Other HTTP stacks will need to obtain the proxy info from
+ * {@link Proxy#PROXY_CHANGE_ACTION} broadcast as the extra {@link Proxy#EXTRA_PROXY_INFO}.
+ */
+public class ProxyInfo implements Parcelable {
+
+    private String mHost;
+    private int mPort;
+    private String mExclusionList;
+    private String[] mParsedExclusionList;
+
+    private Uri mPacFileUrl;
+    /**
+     *@hide
+     */
+    public static final String LOCAL_EXCL_LIST = "";
+    /**
+     *@hide
+     */
+    public static final int LOCAL_PORT = -1;
+    /**
+     *@hide
+     */
+    public static final String LOCAL_HOST = "localhost";
+
+    /**
+     * Constructs a {@link ProxyInfo} object that points at a Direct proxy
+     * on the specified host and port.
+     */
+    public static ProxyInfo buildDirectProxy(String host, int port) {
+        return new ProxyInfo(host, port, null);
+    }
+
+    /**
+     * Constructs a {@link ProxyInfo} object that points at a Direct proxy
+     * on the specified host and port.
+     *
+     * The proxy will not be used to access any host in exclusion list, exclList.
+     *
+     * @param exclList Hosts to exclude using the proxy on connections for.  These
+     *                 hosts can use wildcards such as *.example.com.
+     */
+    public static ProxyInfo buildDirectProxy(String host, int port, List<String> exclList) {
+        String[] array = exclList.toArray(new String[exclList.size()]);
+        return new ProxyInfo(host, port, TextUtils.join(",", array), array);
+    }
+
+    /**
+     * Construct a {@link ProxyInfo} that will download and run the PAC script
+     * at the specified URL.
+     */
+    public static ProxyInfo buildPacProxy(Uri pacUri) {
+        return new ProxyInfo(pacUri);
+    }
+
+    /**
+     * Create a ProxyProperties that points at a HTTP Proxy.
+     * @hide
+     */
+    public ProxyInfo(String host, int port, String exclList) {
+        mHost = host;
+        mPort = port;
+        setExclusionList(exclList);
+        mPacFileUrl = Uri.EMPTY;
+    }
+
+    /**
+     * Create a ProxyProperties that points at a PAC URL.
+     * @hide
+     */
+    public ProxyInfo(Uri pacFileUrl) {
+        mHost = LOCAL_HOST;
+        mPort = LOCAL_PORT;
+        setExclusionList(LOCAL_EXCL_LIST);
+        if (pacFileUrl == null) {
+            throw new NullPointerException();
+        }
+        mPacFileUrl = pacFileUrl;
+    }
+
+    /**
+     * Create a ProxyProperties that points at a PAC URL.
+     * @hide
+     */
+    public ProxyInfo(String pacFileUrl) {
+        mHost = LOCAL_HOST;
+        mPort = LOCAL_PORT;
+        setExclusionList(LOCAL_EXCL_LIST);
+        mPacFileUrl = Uri.parse(pacFileUrl);
+    }
+
+    /**
+     * Only used in PacManager after Local Proxy is bound.
+     * @hide
+     */
+    public ProxyInfo(Uri pacFileUrl, int localProxyPort) {
+        mHost = LOCAL_HOST;
+        mPort = localProxyPort;
+        setExclusionList(LOCAL_EXCL_LIST);
+        if (pacFileUrl == null) {
+            throw new NullPointerException();
+        }
+        mPacFileUrl = pacFileUrl;
+    }
+
+    private ProxyInfo(String host, int port, String exclList, String[] parsedExclList) {
+        mHost = host;
+        mPort = port;
+        mExclusionList = exclList;
+        mParsedExclusionList = parsedExclList;
+        mPacFileUrl = Uri.EMPTY;
+    }
+
+    // copy constructor instead of clone
+    /**
+     * @hide
+     */
+    public ProxyInfo(ProxyInfo source) {
+        if (source != null) {
+            mHost = source.getHost();
+            mPort = source.getPort();
+            mPacFileUrl = source.mPacFileUrl;
+            if (mPacFileUrl == null) {
+                mPacFileUrl = Uri.EMPTY;
+            }
+            mExclusionList = source.getExclusionListAsString();
+            mParsedExclusionList = source.mParsedExclusionList;
+        } else {
+            mPacFileUrl = Uri.EMPTY;
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public InetSocketAddress getSocketAddress() {
+        InetSocketAddress inetSocketAddress = null;
+        try {
+            inetSocketAddress = new InetSocketAddress(mHost, mPort);
+        } catch (IllegalArgumentException e) { }
+        return inetSocketAddress;
+    }
+
+    /**
+     * Returns the URL of the current PAC script or null if there is
+     * no PAC script.
+     */
+    public Uri getPacFileUrl() {
+        return mPacFileUrl;
+    }
+
+    /**
+     * When configured to use a Direct Proxy this returns the host
+     * of the proxy.
+     */
+    public String getHost() {
+        return mHost;
+    }
+
+    /**
+     * When configured to use a Direct Proxy this returns the port
+     * of the proxy
+     */
+    public int getPort() {
+        return mPort;
+    }
+
+    /**
+     * When configured to use a Direct Proxy this returns the list
+     * of hosts for which the proxy is ignored.
+     */
+    public String[] getExclusionList() {
+        return mParsedExclusionList;
+    }
+
+    /**
+     * comma separated
+     * @hide
+     */
+    public String getExclusionListAsString() {
+        return mExclusionList;
+    }
+
+    // comma separated
+    private void setExclusionList(String exclusionList) {
+        mExclusionList = exclusionList;
+        if (mExclusionList == null) {
+            mParsedExclusionList = new String[0];
+        } else {
+            mParsedExclusionList = exclusionList.toLowerCase(Locale.ROOT).split(",");
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public boolean isValid() {
+        if (!Uri.EMPTY.equals(mPacFileUrl)) return true;
+        return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost,
+                                                mPort == 0 ? "" : Integer.toString(mPort),
+                                                mExclusionList == null ? "" : mExclusionList);
+    }
+
+    /**
+     * @hide
+     */
+    public java.net.Proxy makeProxy() {
+        java.net.Proxy proxy = java.net.Proxy.NO_PROXY;
+        if (mHost != null) {
+            try {
+                InetSocketAddress inetSocketAddress = new InetSocketAddress(mHost, mPort);
+                proxy = new java.net.Proxy(java.net.Proxy.Type.HTTP, inetSocketAddress);
+            } catch (IllegalArgumentException e) {
+            }
+        }
+        return proxy;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        if (!Uri.EMPTY.equals(mPacFileUrl)) {
+            sb.append("PAC Script: ");
+            sb.append(mPacFileUrl);
+        } else if (mHost != null) {
+            sb.append("[");
+            sb.append(mHost);
+            sb.append("] ");
+            sb.append(Integer.toString(mPort));
+            if (mExclusionList != null) {
+                    sb.append(" xl=").append(mExclusionList);
+            }
+        } else {
+            sb.append("[ProxyProperties.mHost == null]");
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof ProxyInfo)) return false;
+        ProxyInfo p = (ProxyInfo)o;
+        // If PAC URL is present in either then they must be equal.
+        // Other parameters will only be for fall back.
+        if (!Uri.EMPTY.equals(mPacFileUrl)) {
+            return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort;
+        }
+        if (!Uri.EMPTY.equals(p.mPacFileUrl)) {
+            return false;
+        }
+        if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) {
+            return false;
+        }
+        if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) {
+            return false;
+        }
+        if (mHost != null && p.mHost == null) return false;
+        if (mHost == null && p.mHost != null) return false;
+        if (mPort != p.mPort) return false;
+        return true;
+    }
+
+    /**
+     * Implement the Parcelable interface
+     * @hide
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    /*
+     * generate hashcode based on significant fields
+     */
+    public int hashCode() {
+        return ((null == mHost) ? 0 : mHost.hashCode())
+        + ((null == mExclusionList) ? 0 : mExclusionList.hashCode())
+        + mPort;
+    }
+
+    /**
+     * Implement the Parcelable interface.
+     * @hide
+     */
+    public void writeToParcel(Parcel dest, int flags) {
+        if (!Uri.EMPTY.equals(mPacFileUrl)) {
+            dest.writeByte((byte)1);
+            mPacFileUrl.writeToParcel(dest, 0);
+            dest.writeInt(mPort);
+            return;
+        } else {
+            dest.writeByte((byte)0);
+        }
+        if (mHost != null) {
+            dest.writeByte((byte)1);
+            dest.writeString(mHost);
+            dest.writeInt(mPort);
+        } else {
+            dest.writeByte((byte)0);
+        }
+        dest.writeString(mExclusionList);
+        dest.writeStringArray(mParsedExclusionList);
+    }
+
+    /**
+     * Implement the Parcelable interface.
+     * @hide
+     */
+    public static final Creator<ProxyInfo> CREATOR =
+        new Creator<ProxyInfo>() {
+            public ProxyInfo createFromParcel(Parcel in) {
+                String host = null;
+                int port = 0;
+                if (in.readByte() != 0) {
+                    Uri url = Uri.CREATOR.createFromParcel(in);
+                    int localPort = in.readInt();
+                    return new ProxyInfo(url, localPort);
+                }
+                if (in.readByte() != 0) {
+                    host = in.readString();
+                    port = in.readInt();
+                }
+                String exclList = in.readString();
+                String[] parsedExclList = in.readStringArray();
+                ProxyInfo proxyProperties =
+                        new ProxyInfo(host, port, exclList, parsedExclList);
+                return proxyProperties;
+            }
+
+            public ProxyInfo[] newArray(int size) {
+                return new ProxyInfo[size];
+            }
+        };
+}
diff --git a/core/java/android/net/ProxyProperties.aidl b/core/java/android/net/ProxyProperties.aidl
deleted file mode 100644
index 02ea15d..0000000
--- a/core/java/android/net/ProxyProperties.aidl
+++ /dev/null
@@ -1,21 +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;
-
-parcelable ProxyProperties;
-
diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java
deleted file mode 100644
index 50f45e8..0000000
--- a/core/java/android/net/ProxyProperties.java
+++ /dev/null
@@ -1,273 +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;
-
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-
-import java.net.InetSocketAddress;
-import java.util.Locale;
-
-/**
- * A container class for the http proxy info
- * @hide
- */
-public class ProxyProperties implements Parcelable {
-
-    private String mHost;
-    private int mPort;
-    private String mExclusionList;
-    private String[] mParsedExclusionList;
-
-    private String mPacFileUrl;
-    public static final String LOCAL_EXCL_LIST = "";
-    public static final int LOCAL_PORT = -1;
-    public static final String LOCAL_HOST = "localhost";
-
-    public ProxyProperties(String host, int port, String exclList) {
-        mHost = host;
-        mPort = port;
-        setExclusionList(exclList);
-    }
-
-    public ProxyProperties(String pacFileUrl) {
-        mHost = LOCAL_HOST;
-        mPort = LOCAL_PORT;
-        setExclusionList(LOCAL_EXCL_LIST);
-        mPacFileUrl = pacFileUrl;
-    }
-
-    // Only used in PacManager after Local Proxy is bound.
-    public ProxyProperties(String pacFileUrl, int localProxyPort) {
-        mHost = LOCAL_HOST;
-        mPort = localProxyPort;
-        setExclusionList(LOCAL_EXCL_LIST);
-        mPacFileUrl = pacFileUrl;
-    }
-
-    private ProxyProperties(String host, int port, String exclList, String[] parsedExclList) {
-        mHost = host;
-        mPort = port;
-        mExclusionList = exclList;
-        mParsedExclusionList = parsedExclList;
-        mPacFileUrl = null;
-    }
-
-    // copy constructor instead of clone
-    public ProxyProperties(ProxyProperties source) {
-        if (source != null) {
-            mHost = source.getHost();
-            mPort = source.getPort();
-            mPacFileUrl = source.getPacFileUrl();
-            mExclusionList = source.getExclusionList();
-            mParsedExclusionList = source.mParsedExclusionList;
-        }
-    }
-
-    public InetSocketAddress getSocketAddress() {
-        InetSocketAddress inetSocketAddress = null;
-        try {
-            inetSocketAddress = new InetSocketAddress(mHost, mPort);
-        } catch (IllegalArgumentException e) { }
-        return inetSocketAddress;
-    }
-
-    public String getPacFileUrl() {
-        return mPacFileUrl;
-    }
-
-    public String getHost() {
-        return mHost;
-    }
-
-    public int getPort() {
-        return mPort;
-    }
-
-    // comma separated
-    public String getExclusionList() {
-        return mExclusionList;
-    }
-
-    // comma separated
-    private void setExclusionList(String exclusionList) {
-        mExclusionList = exclusionList;
-        if (mExclusionList == null) {
-            mParsedExclusionList = new String[0];
-        } else {
-            String splitExclusionList[] = exclusionList.toLowerCase(Locale.ROOT).split(",");
-            mParsedExclusionList = new String[splitExclusionList.length * 2];
-            for (int i = 0; i < splitExclusionList.length; i++) {
-                String s = splitExclusionList[i].trim();
-                if (s.startsWith(".")) s = s.substring(1);
-                mParsedExclusionList[i*2] = s;
-                mParsedExclusionList[(i*2)+1] = "." + s;
-            }
-        }
-    }
-
-    public boolean isExcluded(String url) {
-        if (TextUtils.isEmpty(url) || mParsedExclusionList == null ||
-                mParsedExclusionList.length == 0) return false;
-
-        Uri u = Uri.parse(url);
-        String urlDomain = u.getHost();
-        if (urlDomain == null) return false;
-        for (int i = 0; i< mParsedExclusionList.length; i+=2) {
-            if (urlDomain.equals(mParsedExclusionList[i]) ||
-                    urlDomain.endsWith(mParsedExclusionList[i+1])) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public boolean isValid() {
-        if (!TextUtils.isEmpty(mPacFileUrl)) return true;
-        return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost,
-                                                mPort == 0 ? "" : Integer.toString(mPort),
-                                                mExclusionList == null ? "" : mExclusionList);
-    }
-
-    public java.net.Proxy makeProxy() {
-        java.net.Proxy proxy = java.net.Proxy.NO_PROXY;
-        if (mHost != null) {
-            try {
-                InetSocketAddress inetSocketAddress = new InetSocketAddress(mHost, mPort);
-                proxy = new java.net.Proxy(java.net.Proxy.Type.HTTP, inetSocketAddress);
-            } catch (IllegalArgumentException e) {
-            }
-        }
-        return proxy;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        if (mPacFileUrl != null) {
-            sb.append("PAC Script: ");
-            sb.append(mPacFileUrl);
-        } else if (mHost != null) {
-            sb.append("[");
-            sb.append(mHost);
-            sb.append("] ");
-            sb.append(Integer.toString(mPort));
-            if (mExclusionList != null) {
-                    sb.append(" xl=").append(mExclusionList);
-            }
-        } else {
-            sb.append("[ProxyProperties.mHost == null]");
-        }
-        return sb.toString();
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (!(o instanceof ProxyProperties)) return false;
-        ProxyProperties p = (ProxyProperties)o;
-        // If PAC URL is present in either then they must be equal.
-        // Other parameters will only be for fall back.
-        if (!TextUtils.isEmpty(mPacFileUrl)) {
-            return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort;
-        }
-        if (!TextUtils.isEmpty(p.getPacFileUrl())) {
-            return false;
-        }
-        if (mExclusionList != null && !mExclusionList.equals(p.getExclusionList())) return false;
-        if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) {
-            return false;
-        }
-        if (mHost != null && p.mHost == null) return false;
-        if (mHost == null && p.mHost != null) return false;
-        if (mPort != p.mPort) return false;
-        return true;
-    }
-
-    /**
-     * Implement the Parcelable interface
-     * @hide
-     */
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    /*
-     * generate hashcode based on significant fields
-     */
-    public int hashCode() {
-        return ((null == mHost) ? 0 : mHost.hashCode())
-        + ((null == mExclusionList) ? 0 : mExclusionList.hashCode())
-        + mPort;
-    }
-
-    /**
-     * Implement the Parcelable interface.
-     * @hide
-     */
-    public void writeToParcel(Parcel dest, int flags) {
-        if (mPacFileUrl != null) {
-            dest.writeByte((byte)1);
-            dest.writeString(mPacFileUrl);
-            dest.writeInt(mPort);
-            return;
-        } else {
-            dest.writeByte((byte)0);
-        }
-        if (mHost != null) {
-            dest.writeByte((byte)1);
-            dest.writeString(mHost);
-            dest.writeInt(mPort);
-        } else {
-            dest.writeByte((byte)0);
-        }
-        dest.writeString(mExclusionList);
-        dest.writeStringArray(mParsedExclusionList);
-    }
-
-    /**
-     * Implement the Parcelable interface.
-     * @hide
-     */
-    public static final Creator<ProxyProperties> CREATOR =
-        new Creator<ProxyProperties>() {
-            public ProxyProperties createFromParcel(Parcel in) {
-                String host = null;
-                int port = 0;
-                if (in.readByte() != 0) {
-                    String url = in.readString();
-                    int localPort = in.readInt();
-                    return new ProxyProperties(url, localPort);
-                }
-                if (in.readByte() != 0) {
-                    host = in.readString();
-                    port = in.readInt();
-                }
-                String exclList = in.readString();
-                String[] parsedExclList = in.readStringArray();
-                ProxyProperties proxyProperties =
-                        new ProxyProperties(host, port, exclList, parsedExclList);
-                return proxyProperties;
-            }
-
-            public ProxyProperties[] newArray(int size) {
-                return new ProxyProperties[size];
-            }
-        };
-}
diff --git a/core/java/android/net/RssiCurve.java b/core/java/android/net/RssiCurve.java
index 33e81c2..dd744d3 100644
--- a/core/java/android/net/RssiCurve.java
+++ b/core/java/android/net/RssiCurve.java
@@ -98,6 +98,27 @@
     }
 
     /**
+     * Lookup the score for a given RSSI value.
+     *
+     * @param rssi The RSSI to lookup. If the RSSI falls below the start of the curve, the score at
+     *         the start of the curve will be returned. If it falls after the end of the curve, the
+     *         score at the end of the curve will be returned.
+     * @return the score for the given RSSI.
+     */
+    public byte lookupScore(int rssi) {
+        int index = (rssi - start) / bucketWidth;
+
+        // Snap the index to the closest bucket if it falls outside the curve.
+        if (index < 0) {
+            index = 0;
+        } else if (index > rssiBuckets.length - 1) {
+            index = rssiBuckets.length - 1;
+        }
+
+        return rssiBuckets[index];
+    }
+
+    /**
      * Determine if two RSSI curves are defined in the same way.
      *
      * <p>Note that two curves can be equivalent but defined differently, e.g. if one bucket in one
diff --git a/core/java/android/nfc/INfcCardEmulation.aidl b/core/java/android/nfc/INfcCardEmulation.aidl
index ae9796b..521f4fd 100644
--- a/core/java/android/nfc/INfcCardEmulation.aidl
+++ b/core/java/android/nfc/INfcCardEmulation.aidl
@@ -34,4 +34,6 @@
     AidGroup getAidGroupForService(int userHandle, in ComponentName service, String category);
     boolean removeAidGroupForService(int userHandle, in ComponentName service, String category);
     List<ApduServiceInfo> getServices(int userHandle, in String category);
+    boolean setPreferredService(in ComponentName service);
+    boolean unsetPreferredService();
 }
diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java
index 2820f40..b0449224 100644
--- a/core/java/android/nfc/cardemulation/AidGroup.java
+++ b/core/java/android/nfc/cardemulation/AidGroup.java
@@ -12,10 +12,15 @@
 import android.util.Log;
 
 /**
- * The AidGroup class represents a group of ISO/IEC 7816-4
- * Application Identifiers (AIDs) for a specific application
- * category, along with a description resource describing
- * the group.
+ * The AidGroup class represents a group of Application Identifiers (AIDs).
+ *
+ * <p>An instance of this object can be used with
+ * {@link CardEmulation#registerAidGroupForService(android.content.ComponentName, AidGroup)}
+ * to tell the OS which AIDs are handled by your HCE- or SE-based service.
+ *
+ * <p>The format of AIDs is defined in the ISO/IEC 7816-4 specification. This class
+ * requires the AIDs to be input as a hexadecimal string, with an even amount of
+ * hexadecimal characters, e.g. "F014811481".
  */
 public final class AidGroup implements Parcelable {
     /**
@@ -33,7 +38,7 @@
      * Creates a new AidGroup object.
      *
      * @param aids The list of AIDs present in the group
-     * @param category The category of this group
+     * @param category The category of this group, e.g. {@link CardEmulation#CATEGORY_PAYMENT}
      */
     public AidGroup(ArrayList<String> aids, String category) {
         if (aids == null || aids.size() == 0) {
@@ -42,11 +47,12 @@
         if (aids.size() > MAX_NUM_AIDS) {
             throw new IllegalArgumentException("Too many AIDs in AID group.");
         }
-        if (!isValidCategory(category)) {
-            throw new IllegalArgumentException("Category specified is not valid.");
+        if (isValidCategory(category)) {
+            this.category = category;
+        } else {
+            this.category = CardEmulation.CATEGORY_OTHER;
         }
         this.aids = aids;
-        this.category = category;
         this.description = null;
     }
 
@@ -158,7 +164,7 @@
         }
     }
 
-    boolean isValidCategory(String category) {
+    static boolean isValidCategory(String category) {
         return CardEmulation.CATEGORY_PAYMENT.equals(category) ||
                 CardEmulation.CATEGORY_OTHER.equals(category);
     }
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 94f35ed..f379ee8 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -290,6 +290,20 @@
         return groups;
     }
 
+    /**
+     * Returns the category to which this service has attributed the AID that is passed in,
+     * or null if we don't know this AID.
+     */
+    public String getCategoryForAid(String aid) {
+        ArrayList<AidGroup> groups = getAidGroups();
+        for (AidGroup group : groups) {
+            if (group.aids.contains(aid)) {
+                return group.category;
+            }
+        }
+        return null;
+    }
+
     public boolean hasCategory(String category) {
         return (mStaticAidGroups.containsKey(category) || mDynamicAidGroups.containsKey(category));
     }
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index 41f039c..e24a22a 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.app.Activity;
 import android.app.ActivityThread;
 import android.content.ComponentName;
 import android.content.Context;
@@ -28,6 +29,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
 import android.util.Log;
 
 import java.util.HashMap;
@@ -248,6 +250,33 @@
     }
 
     /**
+     * Returns whether the user has allowed AIDs registered in the
+     * specified category to be handled by a service that is preferred
+     * by the foreground application, instead of by a pre-configured default.
+     *
+     * Foreground applications can set such preferences using the
+     * {@link #setPreferredService(Activity, ComponentName)} method.
+     *
+     * @param category The category, e.g. {@link #CATEGORY_PAYMENT}
+     * @return whether AIDs in the category can be handled by a service
+     *         specified by the foreground app.
+     */
+    public boolean categoryAllowsForegroundPreference(String category) {
+        if (CATEGORY_PAYMENT.equals(category)) {
+            boolean preferForeground = false;
+            try {
+                preferForeground = Settings.Secure.getInt(mContext.getContentResolver(),
+                        Settings.Secure.NFC_PAYMENT_FOREGROUND) != 0;
+            } catch (SettingNotFoundException e) {
+            }
+            return preferForeground;
+        } else {
+            // Allowed for all other categories
+            return true;
+        }
+    }
+
+    /**
      * Returns the service selection mode for the passed in category.
      * Valid return values are:
      * <p>{@link #SELECTION_MODE_PREFER_DEFAULT} the user has requested a default
@@ -269,7 +298,6 @@
                 return SELECTION_MODE_ALWAYS_ASK;
             }
         } else {
-            // All other categories are in "only ask if conflict" mode
             return SELECTION_MODE_ASK_IF_CONFLICT;
         }
     }
@@ -283,7 +311,7 @@
      * that AID group will be replaced with this one.
      *
      * <p>Note that you can only register AIDs for a service that
-     * is running under the same UID as you are. Typically
+     * is running under the same UID as the caller of this API. Typically
      * this means you need to call this from the same
      * package as the service itself, though UIDs can also
      * be shared between packages using shared UIDs.
@@ -352,7 +380,7 @@
      * method. It will *not* remove AID groups that were statically registered in
      * the manifest. If a dynamically registered AID group is removed using
      * this method, and a statically registered AID group for the same category
-     * exists in the manifest, that AID group will become active again.
+     * exists in the manifest, the static AID group will become active again.
      *
      * @param service The component name of the service
      * @param category The category of the AID group to be removed, e.g. {@link #CATEGORY_PAYMENT}
@@ -378,6 +406,96 @@
     }
 
     /**
+     * Allows a foreground application to specify which card emulation service
+     * should be preferred while a specific Activity is in the foreground.
+     *
+     * <p>The specified Activity must currently be in resumed state. A good
+     * paradigm is to call this method in your {@link Activity#onResume}, and to call
+     * {@link #unsetPreferredService(Activity)} in your {@link Activity#onPause}.
+     *
+     * <p>This method call will fail in two specific scenarios:
+     * <ul>
+     * <li> If the service registers one or more AIDs in the {@link #CATEGORY_PAYMENT}
+     * category, but the user has indicated that foreground apps are not allowed
+     * to override the default payment service.
+     * <li> If the service registers one or more AIDs in the {@link #CATEGORY_OTHER}
+     * category that are also handled by the default payment service, and the
+     * user has indicated that foreground apps are not allowed to override the
+     * default payment service.
+     * </ul>
+     *
+     * <p> Use {@link #categoryAllowsForegroundPreference(String)} to determine
+     * whether foreground apps can override the default payment service.
+     *
+     * <p>Note that this preference is not persisted by the OS, and hence must be
+     * called every time the Activity is resumed.
+     *
+     * @param activity The activity which prefers this service to be invoked
+     * @param service The service to be preferred while this activity is in the foreground
+     * @return whether the registration was successful
+     */
+    public boolean setPreferredService(Activity activity, ComponentName service) {
+        // Verify the activity is in the foreground before calling into NfcService
+        if (activity == null || service == null) {
+            throw new NullPointerException("activity or service or category is null");
+        }
+        if (!activity.isResumed()) {
+            throw new IllegalArgumentException("Activity must be resumed.");
+        }
+        try {
+            return sService.setPreferredService(service);
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return false;
+            }
+            try {
+                return sService.setPreferredService(service);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Unsets the preferred service for the specified Activity.
+     *
+     * <p>Note that the specified Activity must still be in resumed
+     * state at the time of this call. A good place to call this method
+     * is in your {@link Activity#onPause} implementation.
+     *
+     * @param activity The activity which the service was registered for
+     * @return true when successful
+     */
+    public boolean unsetPreferredService(Activity activity) {
+        if (activity == null) {
+            throw new NullPointerException("activity is null");
+        }
+        if (!activity.isResumed()) {
+            throw new IllegalArgumentException("Activity must be resumed.");
+        }
+        try {
+            return sService.unsetPreferredService();
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return false;
+            }
+            try {
+                return sService.unsetPreferredService();
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return false;
+            }
+        }
+    }
+
+    /**
      * @hide
      */
     public boolean setDefaultServiceForCategory(ComponentName service, String category) {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 9e9820f..4857533 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -21,6 +21,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Formatter;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -30,6 +31,8 @@
 import android.text.format.DateFormat;
 import android.util.Printer;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
 import android.util.TimeUtils;
 import com.android.internal.os.BatterySipper;
 import com.android.internal.os.BatteryStatsHelper;
@@ -135,7 +138,7 @@
     /**
      * Bump the version on this if the checkin format changes.
      */
-    private static final int BATTERY_STATS_CHECKIN_VERSION = 7;
+    private static final int BATTERY_STATS_CHECKIN_VERSION = 8;
     
     private static final long BYTES_PER_KB = 1024;
     private static final long BYTES_PER_MB = 1048576; // 1024^2
@@ -175,6 +178,8 @@
     private static final String POWER_USE_ITEM_DATA = "pwi";
     private static final String DISCHARGE_STEP_DATA = "dsd";
     private static final String CHARGE_STEP_DATA = "csd";
+    private static final String DISCHARGE_TIME_REMAIN_DATA = "dtr";
+    private static final String CHARGE_TIME_REMAIN_DATA = "ctr";
 
     private final StringBuilder mFormatBuilder = new StringBuilder(32);
     private final Formatter mFormatter = new Formatter(mFormatBuilder);
@@ -535,6 +540,7 @@
         public static final byte CMD_START = 4;
         public static final byte CMD_CURRENT_TIME = 5;
         public static final byte CMD_OVERFLOW = 6;
+        public static final byte CMD_RESET = 7;
 
         public byte cmd = CMD_NULL;
         
@@ -618,6 +624,8 @@
         public static final int EVENT_SYNC = 0x0004;
         // Number of event types.
         public static final int EVENT_COUNT = 0x0005;
+        // Mask to extract out only the type part of the event.
+        public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH);
 
         public static final int EVENT_PROC_START = EVENT_PROC | EVENT_FLAG_START;
         public static final int EVENT_PROC_FINISH = EVENT_PROC | EVENT_FLAG_FINISH;
@@ -682,7 +690,7 @@
                 dest.writeInt(eventCode);
                 eventTag.writeToParcel(dest, flags);
             }
-            if (cmd == CMD_CURRENT_TIME) {
+            if (cmd == CMD_CURRENT_TIME || cmd == CMD_RESET) {
                 dest.writeLong(currentTime);
             }
         }
@@ -720,7 +728,7 @@
                 eventCode = EVENT_NONE;
                 eventTag = null;
             }
-            if (cmd == CMD_CURRENT_TIME) {
+            if (cmd == CMD_CURRENT_TIME || cmd == CMD_RESET) {
                 currentTime = src.readLong();
             } else {
                 currentTime = 0;
@@ -831,7 +839,59 @@
             return true;
         }
     }
-    
+
+    public final static class HistoryEventTracker {
+        private final HashMap<String, SparseIntArray>[] mActiveEvents
+                = (HashMap<String, SparseIntArray>[]) new HashMap[HistoryItem.EVENT_COUNT];
+
+        public boolean updateState(int code, String name, int uid, int poolIdx) {
+            if ((code&HistoryItem.EVENT_FLAG_START) != 0) {
+                int idx = code&HistoryItem.EVENT_TYPE_MASK;
+                HashMap<String, SparseIntArray> active = mActiveEvents[idx];
+                if (active == null) {
+                    active = new HashMap<String, SparseIntArray>();
+                    mActiveEvents[idx] = active;
+                }
+                SparseIntArray uids = active.get(name);
+                if (uids == null) {
+                    uids = new SparseIntArray();
+                    active.put(name, uids);
+                }
+                if (uids.indexOfKey(uid) >= 0) {
+                    // Already set, nothing to do!
+                    return false;
+                }
+                uids.put(uid, poolIdx);
+            } else if ((code&HistoryItem.EVENT_FLAG_FINISH) != 0) {
+                int idx = code&HistoryItem.EVENT_TYPE_MASK;
+                HashMap<String, SparseIntArray> active = mActiveEvents[idx];
+                if (active == null) {
+                    // not currently active, nothing to do.
+                    return false;
+                }
+                SparseIntArray uids = active.get(name);
+                if (uids == null) {
+                    // not currently active, nothing to do.
+                    return false;
+                }
+                idx = uids.indexOfKey(uid);
+                if (idx < 0) {
+                    // not currently active, nothing to do.
+                    return false;
+                }
+                uids.removeAt(idx);
+                if (uids.size() <= 0) {
+                    active.remove(name);
+                }
+            }
+            return true;
+        }
+
+        public HashMap<String, SparseIntArray> getStateForEvent(int code) {
+            return mActiveEvents[code];
+        }
+    }
+
     public static final class BitDescription {
         public final int mask;
         public final int shift;
@@ -859,7 +919,7 @@
             this.shortValues = shortValues;
         }
     }
-    
+
     public abstract int getHistoryTotalSize();
 
     public abstract int getHistoryUsedSize();
@@ -909,6 +969,8 @@
      */
     public abstract int getScreenOnCount(int which);
 
+    public abstract long getInteractiveTime(long elapsedRealtimeUs, int which);
+
     public static final int SCREEN_BRIGHTNESS_DARK = 0;
     public static final int SCREEN_BRIGHTNESS_DIM = 1;
     public static final int SCREEN_BRIGHTNESS_MEDIUM = 2;
@@ -934,8 +996,6 @@
     public abstract long getScreenBrightnessTime(int brightnessBin,
             long elapsedRealtimeUs, int which);
 
-    public abstract int getInputEventCount(int which);
-    
     /**
      * Returns the time in microseconds that the phone has been on while the device was
      * running on battery.
@@ -1569,6 +1629,7 @@
         final long totalRealtime = computeRealtime(rawRealtime, which);
         final long totalUptime = computeUptime(rawUptime, which);
         final long screenOnTime = getScreenOnTime(rawRealtime, which);
+        final long interactiveTime = getInteractiveTime(rawRealtime, which);
         final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
         final long wifiOnTime = getWifiOnTime(rawRealtime, which);
         final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
@@ -1637,8 +1698,8 @@
                 wifiRunningTime / 1000, bluetoothOnTime / 1000,
                 mobileRxTotalBytes, mobileTxTotalBytes, wifiRxTotalBytes, wifiTxTotalBytes,
                 fullWakeLockTimeTotal, partialWakeLockTimeTotal,
-                getInputEventCount(which), getMobileRadioActiveTime(rawRealtime, which),
-                getMobileRadioActiveAdjustedTime(which));
+                0 /*legacy input event count*/, getMobileRadioActiveTime(rawRealtime, which),
+                getMobileRadioActiveAdjustedTime(which), interactiveTime / 1000);
         
         // Dump screen brightness stats
         Object[] args = new Object[NUM_SCREEN_BRIGHTNESS_BINS];
@@ -2011,6 +2072,7 @@
                 sb.append("realtime, ");
                 formatTimeMs(sb, totalUptime / 1000);
                 sb.append("uptime");
+        pw.println(sb.toString());
         if (batteryTimeRemaining >= 0) {
             sb.setLength(0);
             sb.append(prefix);
@@ -2029,16 +2091,25 @@
         pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss", getStartClockTime()).toString());
 
         final long screenOnTime = getScreenOnTime(rawRealtime, which);
+        final long interactiveTime = getInteractiveTime(rawRealtime, which);
         final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
         final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
         final long wifiOnTime = getWifiOnTime(rawRealtime, which);
         final long bluetoothOnTime = getBluetoothOnTime(rawRealtime, which);
         sb.setLength(0);
         sb.append(prefix);
+                sb.append("  Interactive: "); formatTimeMs(sb, interactiveTime / 1000);
+                sb.append("("); sb.append(formatRatioLocked(interactiveTime, whichBatteryRealtime));
+                sb.append(")");
+        pw.println(sb.toString());
+        sb.setLength(0);
+        sb.append(prefix);
                 sb.append("  Screen on: "); formatTimeMs(sb, screenOnTime / 1000);
                 sb.append("("); sb.append(formatRatioLocked(screenOnTime, whichBatteryRealtime));
                 sb.append(") "); sb.append(getScreenOnCount(which));
-                sb.append("x, Input events: "); sb.append(getInputEventCount(which));
+                sb.append("x, Active phone call: "); formatTimeMs(sb, phoneOnTime / 1000);
+                sb.append("("); sb.append(formatRatioLocked(phoneOnTime, whichBatteryRealtime));
+                sb.append(")");
         pw.println(sb.toString());
         if (phoneOnTime != 0) {
             sb.setLength(0);
@@ -2897,7 +2968,7 @@
             }
         }
         if (!didWake && wakelockTag != null) {
-            pw.print(longNames ? "wake_lock=" : "w=");
+            pw.print(longNames ? " wake_lock=" : ",w=");
             if (longNames) {
                 UserHandle.formatUid(pw, wakelockTag.uid);
                 pw.print(":\"");
@@ -2945,10 +3016,14 @@
                     pw.print(":");
                 }
                 pw.println("START");
-            } else if (rec.cmd == HistoryItem.CMD_CURRENT_TIME) {
+            } else if (rec.cmd == HistoryItem.CMD_CURRENT_TIME
+                    || rec.cmd == HistoryItem.CMD_RESET) {
                 if (checkin) {
                     pw.print(":");
                 }
+                if (rec.cmd == HistoryItem.CMD_RESET) {
+                    pw.print("RESET:");
+                }
                 pw.print("TIME:");
                 if (checkin) {
                     pw.println(rec.currentTime);
@@ -3076,7 +3151,7 @@
                         HISTORY_STATE2_DESCRIPTIONS, !checkin);
                 if (rec.wakeReasonTag != null) {
                     if (checkin) {
-                        pw.print(",Wr=");
+                        pw.print(",wr=");
                         pw.print(rec.wakeReasonTag.poolIdx);
                     } else {
                         pw.print(" wake_reason=");
@@ -3174,6 +3249,86 @@
     public static final int DUMP_INCLUDE_HISTORY = 1<<3;
     public static final int DUMP_VERBOSE = 1<<4;
 
+    private void dumpHistoryLocked(PrintWriter pw, int flags, long histStart, boolean checkin) {
+        final HistoryPrinter hprinter = new HistoryPrinter();
+        final HistoryItem rec = new HistoryItem();
+        long lastTime = -1;
+        long baseTime = -1;
+        boolean printed = false;
+        HistoryEventTracker tracker = null;
+        while (getNextHistoryLocked(rec)) {
+            lastTime = rec.time;
+            if (baseTime < 0) {
+                baseTime = lastTime;
+            }
+            if (rec.time >= histStart) {
+                if (histStart >= 0 && !printed) {
+                    if (rec.cmd == HistoryItem.CMD_CURRENT_TIME
+                            || rec.cmd == HistoryItem.CMD_RESET) {
+                        printed = true;
+                    } else if (rec.currentTime != 0) {
+                        printed = true;
+                        byte cmd = rec.cmd;
+                        rec.cmd = HistoryItem.CMD_CURRENT_TIME;
+                        if (checkin) {
+                            pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+                            pw.print(HISTORY_DATA); pw.print(',');
+                        }
+                        hprinter.printNextItem(pw, rec, baseTime, checkin,
+                                (flags&DUMP_VERBOSE) != 0);
+                        rec.cmd = cmd;
+                    }
+                    if (tracker != null) {
+                        int oldCode = rec.eventCode;
+                        HistoryTag oldTag = rec.eventTag;
+                        rec.eventTag = new HistoryTag();
+                        for (int i=0; i<HistoryItem.EVENT_COUNT; i++) {
+                            HashMap<String, SparseIntArray> active
+                                    = tracker.getStateForEvent(i);
+                            if (active == null) {
+                                continue;
+                            }
+                            for (HashMap.Entry<String, SparseIntArray> ent
+                                    : active.entrySet()) {
+                                SparseIntArray uids = ent.getValue();
+                                for (int j=0; j<uids.size(); j++) {
+                                    rec.eventCode = i;
+                                    rec.eventTag.string = ent.getKey();
+                                    rec.eventTag.uid = uids.keyAt(j);
+                                    rec.eventTag.poolIdx = uids.valueAt(j);
+                                    if (checkin) {
+                                        pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+                                        pw.print(HISTORY_DATA); pw.print(',');
+                                    }
+                                    hprinter.printNextItem(pw, rec, baseTime, checkin,
+                                            (flags&DUMP_VERBOSE) != 0);
+                                }
+                            }
+                        }
+                        rec.eventCode = oldCode;
+                        rec.eventTag = oldTag;
+                        tracker = null;
+                    }
+                }
+                if (checkin) {
+                    pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+                    pw.print(HISTORY_DATA); pw.print(',');
+                }
+                hprinter.printNextItem(pw, rec, baseTime, checkin,
+                        (flags&DUMP_VERBOSE) != 0);
+            } else if (rec.eventCode != HistoryItem.EVENT_NONE) {
+                if (tracker == null) {
+                    tracker = new HistoryEventTracker();
+                }
+                tracker.updateState(rec.eventCode, rec.eventTag.string,
+                        rec.eventTag.uid, rec.eventTag.poolIdx);
+            }
+        }
+        if (histStart >= 0) {
+            pw.print(checkin ? "NEXT: " : "  NEXT: "); pw.println(lastTime+1);
+        }
+    }
+
     /**
      * Dumps a human-readable summary of the battery statistics to the given PrintWriter.
      *
@@ -3187,9 +3342,6 @@
                 (flags&(DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY)) != 0;
 
         if ((flags&DUMP_HISTORY_ONLY) != 0 || !filtering) {
-            long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
-
-            final HistoryItem rec = new HistoryItem();
             final long historyTotalSize = getHistoryTotalSize();
             final long historyUsedSize = getHistoryUsedSize();
             if (startIteratingHistoryLocked()) {
@@ -3205,35 +3357,7 @@
                     pw.print(" strings using ");
                     printSizeValue(pw, getHistoryStringPoolBytes());
                     pw.println("):");
-                    HistoryPrinter hprinter = new HistoryPrinter();
-                    long lastTime = -1;
-                    long baseTime = -1;
-                    boolean printed = false;
-                    while (getNextHistoryLocked(rec)) {
-                        lastTime = rec.time;
-                        if (baseTime < 0) {
-                            baseTime = lastTime;
-                        }
-                        if (rec.time >= histStart) {
-                            if (histStart >= 0 && !printed) {
-                                if (rec.cmd == HistoryItem.CMD_CURRENT_TIME) {
-                                    printed = true;
-                                } else if (rec.currentTime != 0) {
-                                    printed = true;
-                                    byte cmd = rec.cmd;
-                                    rec.cmd = HistoryItem.CMD_CURRENT_TIME;
-                                    hprinter.printNextItem(pw, rec, baseTime, false,
-                                            (flags&DUMP_VERBOSE) != 0);
-                                    rec.cmd = cmd;
-                                }
-                            }
-                            hprinter.printNextItem(pw, rec, baseTime, false,
-                                    (flags&DUMP_VERBOSE) != 0);
-                        }
-                    }
-                    if (histStart >= 0) {
-                        pw.print("  NEXT: "); pw.println(lastTime+1);
-                    }
+                    dumpHistoryLocked(pw, flags, histStart, false);
                     pw.println();
                 } finally {
                     finishIteratingHistoryLocked();
@@ -3242,6 +3366,7 @@
 
             if (startIteratingOldHistoryLocked()) {
                 try {
+                    final HistoryItem rec = new HistoryItem();
                     pw.println("Old battery History:");
                     HistoryPrinter hprinter = new HistoryPrinter();
                     long baseTime = -1;
@@ -3335,7 +3460,6 @@
                 (flags&(DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY)) != 0;
 
         if ((flags&DUMP_INCLUDE_HISTORY) != 0 || (flags&DUMP_HISTORY_ONLY) != 0) {
-            final HistoryItem rec = new HistoryItem();
             if (startIteratingHistoryLocked()) {
                 try {
                     for (int i=0; i<getHistoryStringPoolSize(); i++) {
@@ -3352,37 +3476,7 @@
                         pw.print("\"");
                         pw.println();
                     }
-                    HistoryPrinter hprinter = new HistoryPrinter();
-                    long lastTime = -1;
-                    long baseTime = -1;
-                    boolean printed = false;
-                    while (getNextHistoryLocked(rec)) {
-                        lastTime = rec.time;
-                        if (baseTime < 0) {
-                            baseTime = lastTime;
-                        }
-                        if (rec.time >= histStart) {
-                            if (histStart >= 0 && !printed) {
-                                if (rec.cmd == HistoryItem.CMD_CURRENT_TIME) {
-                                    printed = true;
-                                } else if (rec.currentTime != 0) {
-                                    printed = true;
-                                    byte cmd = rec.cmd;
-                                    rec.cmd = HistoryItem.CMD_CURRENT_TIME;
-                                    pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
-                                    pw.print(HISTORY_DATA); pw.print(',');
-                                    hprinter.printNextItem(pw, rec, baseTime, true, false);
-                                    rec.cmd = cmd;
-                                }
-                            }
-                            pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
-                            pw.print(HISTORY_DATA); pw.print(',');
-                            hprinter.printNextItem(pw, rec, baseTime, true, false);
-                        }
-                    }
-                    if (histStart >= 0) {
-                        pw.print("NEXT: "); pw.println(lastTime+1);
-                    }
+                    dumpHistoryLocked(pw, flags, histStart, true);
                 } finally {
                     finishIteratingHistoryLocked();
                 }
@@ -3423,8 +3517,21 @@
         if (!filtering) {
             dumpDurationSteps(pw, DISCHARGE_STEP_DATA, getDischargeStepDurationsArray(),
                     getNumDischargeStepDurations(), true);
+            String[] lineArgs = new String[1];
+            long timeRemaining = computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
+            if (timeRemaining >= 0) {
+                lineArgs[0] = Long.toString(timeRemaining);
+                dumpLine(pw, 0 /* uid */, "i" /* category */, DISCHARGE_TIME_REMAIN_DATA,
+                        (Object[])lineArgs);
+            }
             dumpDurationSteps(pw, CHARGE_STEP_DATA, getChargeStepDurationsArray(),
                     getNumChargeStepDurations(), true);
+            timeRemaining = computeChargeTimeRemaining(SystemClock.elapsedRealtime());
+            if (timeRemaining >= 0) {
+                lineArgs[0] = Long.toString(timeRemaining);
+                dumpLine(pw, 0 /* uid */, "i" /* category */, CHARGE_TIME_REMAIN_DATA,
+                        (Object[])lineArgs);
+            }
         }
         if (!filtering || (flags&DUMP_CHARGED_ONLY) != 0) {
             dumpCheckinLocked(context, pw, STATS_SINCE_CHARGED, -1);
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 1ca6b90..a7485b4 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -88,7 +88,8 @@
      *
      * @hide
      */
-    public static final String[] SUPPORTED_ABIS = getString("ro.product.cpu.abilist").split(",");
+    public static final String[] SUPPORTED_ABIS = SystemProperties.get("ro.product.cpu.abilist")
+            .split(",");
 
     /**
      * An ordered list of <b>32 bit</b> ABIs supported by this device. The most preferred ABI
@@ -98,8 +99,8 @@
      *
      * @hide
      */
-    public static final String[] SUPPORTED_32_BIT_ABIS = getString("ro.product.cpu.abilist32")
-            .split(",");
+    public static final String[] SUPPORTED_32_BIT_ABIS =
+            SystemProperties.get("ro.product.cpu.abilist32").split(",");
 
     /**
      * An ordered list of <b>64 bit</b> ABIs supported by this device. The most preferred ABI
@@ -109,8 +110,8 @@
      *
      * @hide
      */
-    public static final String[] SUPPORTED_64_BIT_ABIS = getString("ro.product.cpu.abilist64")
-            .split(",");
+    public static final String[] SUPPORTED_64_BIT_ABIS =
+            SystemProperties.get("ro.product.cpu.abilist64").split(",");
 
 
     /** Various version strings. */
@@ -515,9 +516,16 @@
         public static final int KITKAT = 19;
 
         /**
-         * Android 4.5: KitKat for watches, snacks on the run.
+         * Android 4.4W: KitKat for watches, snacks on the run.
+         *
+         * <p>Applications targeting this or a later release will get these
+         * new changes in behavior:</p>
+         * <ul>
+         * <li>{@link android.app.AlertDialog} might not have a default background if the theme does
+         * not specify one.</li>
+         * </ul>
          */
-        public static final int KITKAT_WATCH = CUR_DEVELOPMENT; // STOPSHIP: update API level
+        public static final int KITKAT_WATCH = 20;
 
         /**
          * L!
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index d71c3e6..1dba77d 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -17,6 +17,7 @@
 package android.os;
 
 import android.system.ErrnoException;
+import android.text.TextUtils;
 import android.system.Os;
 import android.system.OsConstants;
 import android.util.Log;
@@ -382,4 +383,32 @@
         }
         return filePath.startsWith(dirPath);
     }
+
+    public static void deleteContents(File dir) {
+        File[] files = dir.listFiles();
+        if (files != null) {
+            for (File file : files) {
+                if (file.isDirectory()) {
+                    deleteContents(file);
+                }
+                file.delete();
+            }
+        }
+    }
+
+    /**
+     * Assert that given filename is valid on ext4.
+     */
+    public static boolean isValidExtFilename(String name) {
+        if (TextUtils.isEmpty(name) || ".".equals(name) || "..".equals(name)) {
+            return false;
+        }
+        for (int i = 0; i < name.length(); i++) {
+            final char c = name.charAt(i);
+            if (c == '\0' || c == '/') {
+                return false;
+            }
+        }
+        return true;
+    }
 }
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index f5ff185..eb9ba13 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -99,24 +99,12 @@
     /**
      * Add the specified route to the interface.
      */
-    void addRoute(String iface, in RouteInfo route);
+    void addRoute(int netId, in RouteInfo route);
 
     /**
      * Remove the specified route from the interface.
      */
-    void removeRoute(String iface, in RouteInfo route);
-
-    /**
-     * Add the specified route to a secondary interface
-     * This will go into a special route table to be accessed
-     * via ip rules
-     */
-    void addSecondaryRoute(String iface, in RouteInfo route);
-
-    /**
-     * Remove the specified secondary route.
-     */
-    void removeSecondaryRoute(String iface, in RouteInfo route);
+    void removeRoute(int netId, in RouteInfo route);
 
     /**
      * Set the specified MTU size
@@ -320,24 +308,14 @@
     void removeIdleTimer(String iface);
 
     /**
-     * Sets the name of the default interface in the DNS resolver.
+     * Bind name servers to a network in the DNS resolver.
      */
-    void setDefaultInterfaceForDns(String iface);
+    void setDnsServersForNetwork(int netId, in String[] servers, String domains);
 
     /**
-     * Bind name servers to an interface in the DNS resolver.
+     * Flush the DNS cache associated with the specified network.
      */
-    void setDnsServersForInterface(String iface, in String[] servers, String domains);
-
-    /**
-     * Flush the DNS cache associated with the default interface.
-     */
-    void flushDefaultDnsCache();
-
-    /**
-     * Flush the DNS cache associated with the specified interface.
-     */
-    void flushInterfaceDnsCache(String iface);
+    void flushNetworkDnsCache(int netId);
 
     void setFirewallEnabled(boolean enabled);
     boolean isFirewallEnabled();
@@ -350,7 +328,7 @@
      * Set all packets from users [uid_start,uid_end] to go through interface iface
      * iface must already be set for marked forwarding by {@link setMarkedForwarding}
      */
-    void setUidRangeRoute(String iface, int uid_start, int uid_end);
+    void setUidRangeRoute(String iface, int uid_start, int uid_end, boolean forward_dns);
 
     /**
      * Clears the special routing rules for users [uid_start,uid_end]
@@ -402,31 +380,6 @@
     void clearHostExemption(in LinkAddress host);
 
     /**
-     * Set a process (pid) to use the name servers associated with the specified interface.
-     */
-    void setDnsInterfaceForPid(String iface, int pid);
-
-    /**
-     * Clear a process (pid) from being associated with an interface.
-     */
-    void clearDnsInterfaceForPid(int pid);
-
-    /**
-    * Set a range of user ids to use the name servers associated with the specified interface.
-    */
-    void setDnsInterfaceForUidRange(String iface, int uid_start, int uid_end);
-
-    /**
-    * Clear a user range from being associated with an interface.
-    */
-    void clearDnsInterfaceForUidRange(String iface, int uid_start, int uid_end);
-
-    /**
-    * Clear the mappings from pid to Dns interface and from uid range to Dns interface.
-    */
-    void clearDnsInterfaceMaps();
-
-    /**
      * Start the clatd (464xlat) service
      */
     void startClatd(String interfaceName);
@@ -455,4 +408,33 @@
      * Check whether the mobile radio is currently active.
      */
     boolean isNetworkActive();
+
+    /**
+     * Setup a new network.
+     */
+    void createNetwork(int netId);
+
+    /**
+     * Remove a network.
+     */
+    void removeNetwork(int netId);
+
+    /**
+     * Add an interface to a network.
+     */
+    void addInterfaceToNetwork(String iface, int netId);
+
+    /**
+     * Remove an Interface from a network.
+     */
+    void removeInterfaceFromNetwork(String iface, int netId);
+
+    void addLegacyRouteForNetId(int netId, in RouteInfo routeInfo, int uid);
+    void removeLegacyRouteForNetId(int netId, in RouteInfo routeInfo, int uid);
+
+    void setDefaultNetId(int netId);
+    void clearDefaultNetId();
+
+    void setPermission(boolean internal, boolean changeNetState, in int[] uids);
+    void clearPermission(in int[] uids);
 }
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index c3f7370..cd47099 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -29,12 +29,14 @@
 interface IUserManager {
     UserInfo createUser(in String name, int flags);
     UserInfo createProfileForUser(in String name, int flags, int userHandle);
+    void setUserEnabled(int userHandle);
     boolean removeUser(int userHandle);
     void setUserName(int userHandle, String name);
     void setUserIcon(int userHandle, in Bitmap icon);
     Bitmap getUserIcon(int userHandle);
     List<UserInfo> getUsers(boolean excludeDying);
     List<UserInfo> getProfiles(int userHandle, boolean enabledOnly);
+    UserInfo getProfileParent(int userHandle);
     UserInfo getUserInfo(int userHandle);
     boolean isRestricted();
     void setGuestEnabled(boolean enable);
diff --git a/core/java/android/os/ParcelableParcel.aidl b/core/java/android/os/ParcelableParcel.aidl
new file mode 100644
index 0000000..61f730c
--- /dev/null
+++ b/core/java/android/os/ParcelableParcel.aidl
@@ -0,0 +1,19 @@
+/*
+** 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.os;
+
+parcelable ParcelableParcel;
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index f8d7c3e..5b2c8db 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -366,15 +366,6 @@
     }
 
     /**
-     * Returns true if the screen auto-brightness adjustment setting should
-     * be available in the UI.  This setting is experimental and disabled by default.
-     * @hide
-     */
-    public static boolean useScreenAutoBrightnessAdjustmentFeature() {
-        return SystemProperties.getBoolean("persist.power.useautobrightadj", false);
-    }
-
-    /**
      * Returns true if the twilight service should be used to adjust screen brightness
      * policy.  This setting is experimental and disabled by default.
      * @hide
diff --git a/core/java/android/os/RemoteException.java b/core/java/android/os/RemoteException.java
index e30d24f..98d7523 100644
--- a/core/java/android/os/RemoteException.java
+++ b/core/java/android/os/RemoteException.java
@@ -28,4 +28,9 @@
     public RemoteException(String message) {
         super(message);
     }
+
+    /** {@hide} */
+    public RuntimeException rethrowAsRuntimeException() {
+        throw new RuntimeException(this);
+    }
 }
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 1fe9337..312cdbe 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -91,7 +91,6 @@
      * @see #setUserRestrictions(Bundle)
      * @see #getUserRestrictions()
      */
-
     public static final String DISALLOW_SHARE_LOCATION = "no_share_location";
 
     /**
@@ -145,6 +144,128 @@
      */
     public static final String DISALLOW_REMOVE_USER = "no_remove_user";
 
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from enabling or
+     * accessing debugging features. The default value is <code>false</code>.
+     * <p/>
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features";
+
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from configuring VPN.
+     * The default value is <code>false</code>.
+     * <p/>
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_CONFIG_VPN = "no_config_vpn";
+
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from configuring Tethering
+     * & portable hotspots. The default value is <code>false</code>.
+     * <p/>
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_CONFIG_TETHERING = "no_config_tethering";
+
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from factory resetting
+     * from Settings.
+     * The default value is <code>false</code>.
+     * <p>
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_FACTORY_RESET = "no_factory_reset";
+
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from adding new users and
+     * profiles. The default value is <code>false</code>.
+     * <p>
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_ADD_USER = "no_add_user";
+
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from disabling application
+     * verification. The default value is <code>false</code>.
+     * <p>
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String ENSURE_VERIFY_APPS = "ensure_verify_apps";
+
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from configuring cell
+     * broadcasts. The default value is <code>false</code>.
+     * <p>
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
+
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from configuring mobile
+     * networks. The default value is <code>false</code>.
+     * <p>
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
+
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from configuring
+     * applications in Settings. The default value is <code>false</code>.
+     * <p>
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_CONFIG_APPS = "no_config_apps";
+
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from mounting
+     * physical external media. The default value is <code>false</code>.
+     * <p/>
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media";
+
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from adjusting microphone
+     * volume.
+     * The default value is <code>false</code>.
+     * <p/>
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone";
+
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from adjusting the master
+     * volume.
+     * The default value is <code>false</code>.
+     * <p/>
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
+
     /** @hide */
     public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3;
     /** @hide */
@@ -180,7 +301,8 @@
     }
 
     /**
-     * Returns the user handle for the user that this application is running for.
+     * Returns the user handle for the user that the calling process is running on.
+     *
      * @return the user handle of the user making this call.
      * @hide
      */
@@ -437,6 +559,22 @@
     }
 
     /**
+     * Sets the user as enabled, if such an user exists.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+     * Note that the default is true, it's only that managed profiles might not be enabled.
+     *
+     * @param userHandle the id of the profile to enable
+     * @hide
+     */
+    public void setUserEnabled(int userHandle) {
+        try {
+            mService.setUserEnabled(userHandle);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Could not enable the profile", e);
+        }
+    }
+
+    /**
      * Return the number of users currently created on the device.
      */
     public int getUserCount() {
@@ -480,7 +618,8 @@
     }
 
     /**
-     * Returns a list of UserHandles for profiles associated with this user, including this user.
+     * Returns a list of UserHandles for profiles associated with the user that the calling process
+     * is running on, including the user itself.
      *
      * @return A non-empty list of UserHandles associated with the calling user.
      */
@@ -488,8 +627,7 @@
         ArrayList<UserHandle> profiles = new ArrayList<UserHandle>();
         List<UserInfo> users = new ArrayList<UserInfo>();
         try {
-            // TODO: Switch enabledOnly to true once client apps are updated
-            users = mService.getProfiles(UserHandle.myUserId(), false /* enabledOnly */);
+            users = mService.getProfiles(UserHandle.myUserId(), true /* enabledOnly */);
         } catch (RemoteException re) {
             Log.w(TAG, "Could not get user list", re);
             return null;
@@ -502,6 +640,21 @@
     }
 
     /**
+     * Returns the parent of the profile which this method is called from
+     * or null if called from a user that is not a profile.
+     *
+     * @hide
+     */
+    public UserInfo getProfileParent(int userHandle) {
+        try {
+            return mService.getProfileParent(userHandle);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not get profile parent", re);
+            return null;
+        }
+    }
+
+    /**
      * If the target user is a managed profile of the calling user or the caller
      * is itself a managed profile, then this returns a badged copy of the given
      * icon to be able to distinguish it from the original icon.
@@ -528,7 +681,7 @@
 
     private int getBadgeResIdForUser(int userHandle) {
         // Return the framework-provided badge.
-        List<UserInfo> userProfiles = getProfiles(UserHandle.myUserId());
+        List<UserInfo> userProfiles = getProfiles(getUserHandle());
         for (UserInfo user : userProfiles) {
             if (user.id == userHandle
                     && user.isManagedProfile()) {
@@ -557,7 +710,7 @@
     /**
      * Returns information for all users on this device. Requires
      * {@link android.Manifest.permission#MANAGE_USERS} permission.
-     * 
+     *
      * @param excludeDying specify if the list should exclude users being
      *            removed.
      * @return the list of users that were created.
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index e4f73cb..811751d 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -167,7 +167,7 @@
 
         /**
          * Callback notifying that a print job state changed.
-         * 
+         *
          * @param printJobId The print job id.
          */
         public void onPrintJobStateChanged(PrintJobId printJobId);
@@ -175,7 +175,7 @@
 
     /**
      * Creates a new instance.
-     * 
+     *
      * @param context The current context in which to operate.
      * @param service The backing system service.
      * @hide
@@ -207,13 +207,17 @@
 
     /**
      * Creates an instance that can access all print jobs.
-     * 
+     *
      * @param userId The user id for which to get all print jobs.
      * @return An instance if the caller has the permission to access all print
      *         jobs, null otherwise.
      * @hide
      */
     public PrintManager getGlobalPrintManagerForUser(int userId) {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return null;
+        }
         return new PrintManager(mContext, mService, userId, APP_ID_ANY);
     }
 
@@ -228,11 +232,15 @@
 
     /**
      * Adds a listener for observing the state of print jobs.
-     * 
+     *
      * @param listener The listener to add.
      * @hide
      */
     public void addPrintJobStateChangeListener(PrintJobStateChangeListener listener) {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return;
+        }
         if (mPrintJobStateChangeListeners == null) {
             mPrintJobStateChangeListeners = new ArrayMap<PrintJobStateChangeListener,
                     PrintJobStateChangeListenerWrapper>();
@@ -249,11 +257,15 @@
 
     /**
      * Removes a listener for observing the state of print jobs.
-     * 
+     *
      * @param listener The listener to remove.
      * @hide
      */
     public void removePrintJobStateChangeListener(PrintJobStateChangeListener listener) {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return;
+        }
         if (mPrintJobStateChangeListeners == null) {
             return;
         }
@@ -275,12 +287,16 @@
 
     /**
      * Gets a print job given its id.
-     * 
+     *
      * @return The print job list.
      * @see PrintJob
      * @hide
      */
     public PrintJob getPrintJob(PrintJobId printJobId) {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return null;
+        }
         try {
             PrintJobInfo printJob = mService.getPrintJobInfo(printJobId, mAppId, mUserId);
             if (printJob != null) {
@@ -294,11 +310,15 @@
 
     /**
      * Gets the print jobs for this application.
-     * 
+     *
      * @return The print job list.
      * @see PrintJob
      */
     public List<PrintJob> getPrintJobs() {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return Collections.emptyList();
+        }
         try {
             List<PrintJobInfo> printJobInfos = mService.getPrintJobInfos(mAppId, mUserId);
             if (printJobInfos == null) {
@@ -317,6 +337,10 @@
     }
 
     void cancelPrintJob(PrintJobId printJobId) {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return;
+        }
         try {
             mService.cancelPrintJob(printJobId, mAppId, mUserId);
         } catch (RemoteException re) {
@@ -325,6 +349,10 @@
     }
 
     void restartPrintJob(PrintJobId printJobId) {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return;
+        }
         try {
             mService.restartPrintJob(printJobId, mAppId, mUserId);
         } catch (RemoteException re) {
@@ -383,6 +411,10 @@
      */
     public PrintJob print(String printJobName, PrintDocumentAdapter documentAdapter,
             PrintAttributes attributes) {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return null;
+        }
         if (!(mContext instanceof Activity)) {
             throw new IllegalStateException("Can print only from an activity");
         }
@@ -418,11 +450,15 @@
 
     /**
      * Gets the list of enabled print services.
-     * 
+     *
      * @return The enabled service list or an empty list.
      * @hide
      */
     public List<PrintServiceInfo> getEnabledPrintServices() {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return Collections.emptyList();
+        }
         try {
             List<PrintServiceInfo> enabledServices = mService.getEnabledPrintServices(mUserId);
             if (enabledServices != null) {
@@ -436,11 +472,15 @@
 
     /**
      * Gets the list of installed print services.
-     * 
+     *
      * @return The installed service list or an empty list.
      * @hide
      */
     public List<PrintServiceInfo> getInstalledPrintServices() {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return Collections.emptyList();
+        }
         try {
             List<PrintServiceInfo> installedServices = mService.getInstalledPrintServices(mUserId);
             if (installedServices != null) {
@@ -456,6 +496,10 @@
      * @hide
      */
     public PrinterDiscoverySession createPrinterDiscoverySession() {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return null;
+        }
         return new PrinterDiscoverySession(mService, mContext, mUserId);
     }
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ab06230..89f4388 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2503,6 +2503,14 @@
             NOTIFICATION_SOUND
         };
 
+        /**
+         * When to use Wi-Fi calling
+         *
+         * @see android.telephony.TelephonyManager.WifiCallingChoices
+         * @hide
+         */
+        public static final String WHEN_TO_MAKE_WIFI_CALLS = "when_to_make_wifi_calls";
+
         // Settings moved to Settings.Secure
 
         /**
@@ -2823,7 +2831,6 @@
             MOVED_TO_GLOBAL.add(Settings.Global.TETHER_SUPPORTED);
             MOVED_TO_GLOBAL.add(Settings.Global.USB_MASS_STORAGE_ENABLED);
             MOVED_TO_GLOBAL.add(Settings.Global.USE_GOOGLE_MAIL);
-            MOVED_TO_GLOBAL.add(Settings.Global.WEB_AUTOFILL_QUERY_URL);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_COUNTRY_CODE);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_FREQUENCY_BAND);
@@ -2838,6 +2845,8 @@
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SAVED_STATE);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_ENHANCED_AUTO_JOIN);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_NETWORK_SHOW_RSSI);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_ON);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED);
             MOVED_TO_GLOBAL.add(Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON);
@@ -3480,6 +3489,12 @@
             "lock_screen_appwidget_ids";
 
         /**
+         * List of enrolled fingerprint identifiers (comma-delimited).
+         * @hide
+         */
+        public static final String USER_FINGERPRINT_IDS = "user_fingerprint_ids";
+
+        /**
          * Id of the appwidget shown on the lock screen when appwidgets are disabled.
          * @hide
          */
@@ -3831,22 +3846,11 @@
 
         /**
          * Setting that specifies whether display color inversion is enabled.
-         *
-         * @hide
          */
         public static final String ACCESSIBILITY_DISPLAY_INVERSION_ENABLED =
                 "accessibility_display_inversion_enabled";
 
         /**
-         * Integer property that specifies the type of color inversion to
-         * perform. Valid values are defined in AccessibilityManager.
-         *
-         * @hide
-         */
-        public static final String ACCESSIBILITY_DISPLAY_INVERSION =
-                "accessibility_display_inversion";
-
-        /**
          * Setting that specifies whether the quick setting tile for display
          * color space adjustment is enabled.
          *
@@ -3874,44 +3878,6 @@
                 "accessibility_display_daltonizer";
 
         /**
-         * Setting that specifies whether the quick setting tile for display
-         * contrast enhancement is enabled.
-         *
-         * @hide
-         */
-        public static final String ACCESSIBILITY_DISPLAY_CONTRAST_QUICK_SETTING_ENABLED =
-                "accessibility_display_contrast_quick_setting_enabled";
-
-        /**
-         * Setting that specifies whether display contrast enhancement is
-         * enabled.
-         *
-         * @hide
-         */
-        public static final String ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED =
-                "accessibility_display_contrast_enabled";
-
-        /**
-         * Floating point property that specifies display contrast adjustment.
-         * Valid range is [0, ...] where 0 is gray, 1 is normal, and higher
-         * values indicate enhanced contrast.
-         *
-         * @hide
-         */
-        public static final String ACCESSIBILITY_DISPLAY_CONTRAST =
-                "accessibility_display_contrast";
-
-        /**
-         * Floating point property that specifies display brightness adjustment.
-         * Valid range is [-1, 1] where -1 is black, 0 is default, and 1 is
-         * white.
-         *
-         * @hide
-         */
-        public static final String ACCESSIBILITY_DISPLAY_BRIGHTNESS =
-                "accessibility_display_brightness";
-
-        /**
          * The timout for considering a press to be a long press in milliseconds.
          * @hide
          */
@@ -4395,6 +4361,13 @@
         public static final String ANR_SHOW_BACKGROUND = "anr_show_background";
 
         /**
+         * (Experimental). If nonzero, WebView uses data reduction proxy to save network
+         * bandwidth. Otherwise, WebView does not use data reduction proxy.
+         * @hide
+         */
+        public static final String WEBVIEW_DATA_REDUCTION_PROXY = "webview_data_reduction_proxy";
+
+        /**
          * The {@link ComponentName} string of the service to be used as the voice recognition
          * service.
          *
@@ -4515,6 +4488,12 @@
         public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component";
 
         /**
+         * Whether NFC payment is handled by the foreground application or a default.
+         * @hide
+         */
+        public static final String NFC_PAYMENT_FOREGROUND = "nfc_payment_foreground";
+
+        /**
          * Specifies the package name currently configured to be the primary sms application
          * @hide
          */
@@ -5340,11 +5319,6 @@
         */
        public static final String USE_GOOGLE_MAIL = "use_google_mail";
 
-       /** Autofill server address (Used in WebView/browser).
-        * {@hide} */
-       public static final String WEB_AUTOFILL_QUERY_URL =
-           "web_autofill_query_url";
-
        /**
         * Whether Wifi display is enabled/disabled
         * 0=disabled. 1=enabled.
@@ -5456,7 +5430,21 @@
        public static final String WIFI_SUPPLICANT_SCAN_INTERVAL_MS =
                "wifi_supplicant_scan_interval_ms";
 
-       /**
+        /**
+         * whether frameworks handles wifi auto-join
+         * @hide
+         */
+       public static final String WIFI_ENHANCED_AUTO_JOIN =
+                "wifi_enhanced_auto_join";
+
+        /**
+         * whether settings show RSSI
+         * @hide
+         */
+        public static final String WIFI_NETWORK_SHOW_RSSI =
+                "wifi_network_show_rssi";
+
+        /**
         * The interval in milliseconds to scan at supplicant when p2p is connected
         * @hide
         */
@@ -6167,6 +6155,13 @@
         /** @hide */ public static final int HEADS_UP_ON = 1;
 
         /**
+         * The name of the device
+         *
+         * @hide
+         */
+        public static final String DEVICE_NAME = "device_name";
+
+        /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
          *
diff --git a/core/java/android/provider/TvContract.java b/core/java/android/provider/TvContract.java
index 62252be..5ffffb5 100644
--- a/core/java/android/provider/TvContract.java
+++ b/core/java/android/provider/TvContract.java
@@ -20,6 +20,7 @@
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.net.Uri;
+import android.tv.TvInputService;
 
 import java.util.List;
 
@@ -139,9 +140,9 @@
      *
      * @param channelUri The URI of the channel to return programs for.
      * @param startTime The start time used to filter programs. The returned programs should have
-     *            {@link Programs#END_TIME_UTC_MILLIS} that is greater than this time.
+     *            {@link Programs#COLUMN_END_TIME_UTC_MILLIS} that is greater than this time.
      * @param endTime The end time used to filter programs. The returned programs should have
-     *            {@link Programs#START_TIME_UTC_MILLIS} that is less than this time.
+     *            {@link Programs#COLUMN_START_TIME_UTC_MILLIS} that is less than this time.
      */
     public static final Uri buildProgramsUriForChannel(Uri channelUri, long startTime,
             long endTime) {
@@ -161,7 +162,7 @@
     }
 
     /**
-     * Extracts the {@link Channels#PACKAGE_NAME} from a given URI.
+     * Extracts the {@link Channels#COLUMN_PACKAGE_NAME} from a given URI.
      *
      * @param channelsUri A URI constructed by {@link #buildChannelsUriForInput(ComponentName)} or
      *            {@link #buildChannelsUriForInput(ComponentName, boolean)}.
@@ -179,7 +180,7 @@
     }
 
     /**
-     * Extracts the {@link Channels#SERVICE_NAME} from a given URI.
+     * Extracts the {@link Channels#COLUMN_SERVICE_NAME} from a given URI.
      *
      * @param channelsUri A URI constructed by {@link #buildChannelsUriForInput(ComponentName)} or
      *            {@link #buildChannelsUriForInput(ComponentName, boolean)}.
@@ -231,7 +232,7 @@
          * Type: TEXT
          * </p>
          */
-        public static final String PACKAGE_NAME = "package_name";
+        public static final String COLUMN_PACKAGE_NAME = "package_name";
     }
 
     /** Column definitions for the TV channels table. */
@@ -279,14 +280,14 @@
         /** The channel type for DVB-SH (satellite). */
         public static final int TYPE_DVB_SH = 0x00020400;
 
-        /** The channel type for ATSC (terrestrial/cable). */
-        public static final int TYPE_ATSC = 0x00030000;
+        /** The channel type for ATSC (terrestrial). */
+        public static final int TYPE_ATSC_T = 0x00030000;
 
-        /** The channel type for ATSC 2.0. */
-        public static final int TYPE_ATSC_2_0 = 0x00030001;
+        /** The channel type for ATSC (cable). */
+        public static final int TYPE_ATSC_C = 0x00030200;
 
         /** The channel type for ATSC-M/H (mobile/handheld). */
-        public static final int TYPE_ATSC_M_H = 0x00030100;
+        public static final int TYPE_ATSC_M_H = 0x00030200;
 
         /** The channel type for ISDB-T (terrestrial). */
         public static final int TYPE_ISDB_T = 0x00040000;
@@ -315,49 +316,124 @@
         /** The channel type for S-DMB (satellite). */
         public static final int TYPE_S_DMB = 0x00060100;
 
+        /** A generic service type. */
+        public static final int SERVICE_TYPE_OTHER = 0x0;
+
+        /** The service type for regular TV channels. */
+        public static final int SERVICE_TYPE_TV = 0x1;
+
+        /** The service type for radio channels. */
+        public static final int SERVICE_TYPE_RADIO = 0x2;
+
         /**
-         * The name of the TV input service that provides this TV channel.
+         * The name of the {@link TvInputService} subclass that provides this TV channel. This
+         * should be a fully qualified class name (such as, "com.example.project.TvInputService").
          * <p>
          * This is a required field.
          * </p><p>
          * Type: TEXT
          * </p>
          */
-        public static final String SERVICE_NAME = "service_name";
+        public static final String COLUMN_SERVICE_NAME = "service_name";
 
         /**
          * The predefined type of this TV channel.
          * <p>
-         * This is used to indicate which broadcast standard (e.g. ATSC, DVB or ISDB) the current
-         * channel conforms to.
+         * This is primarily used to indicate which broadcast standard (e.g. ATSC, DVB or ISDB) the
+         * current channel conforms to, with an exception being {@link #TYPE_PASSTHROUGH}, which is
+         * a special channel type used only by pass-through inputs such as HDMI. The value should
+         * match to one of the followings: {@link #TYPE_OTHER}, {@link #TYPE_PASSTHROUGH},
+         * {@link #TYPE_DVB_T}, {@link #TYPE_DVB_T2}, {@link #TYPE_DVB_S}, {@link #TYPE_DVB_S2},
+         * {@link #TYPE_DVB_C}, {@link #TYPE_DVB_C2}, {@link #TYPE_DVB_H}, {@link #TYPE_DVB_SH},
+         * {@link #TYPE_ATSC_T}, {@link #TYPE_ATSC_C}, {@link #TYPE_ATSC_M_H}, {@link #TYPE_ISDB_T},
+         * {@link #TYPE_ISDB_TB}, {@link #TYPE_ISDB_S}, {@link #TYPE_ISDB_C} {@link #TYPE_1SEG},
+         * {@link #TYPE_DTMB}, {@link #TYPE_CMMB}, {@link #TYPE_T_DMB}, {@link #TYPE_S_DMB}
          * </p><p>
          * This is a required field.
          * </p><p>
          * Type: INTEGER
          * </p>
          */
-        public static final String TYPE = "type";
+        public static final String COLUMN_TYPE = "type";
 
         /**
-         * The transport stream ID as appeared in various broadcast standards.
+         * The predefined service type of this TV channel.
          * <p>
-         * This is not a required field but if provided, can significantly increase the accuracy of
-         * channel identification.
+         * This is primarily used to indicate whether the current channel is a regular TV channel or
+         * a radio-like channel. Use the same coding for {@code service_type} in the underlying
+         * broadcast standard if it is defined there (e.g. ATSC A/53, ETSI EN 300 468 and ARIB
+         * STD-B10). Otherwise use one of the followings: {@link #SERVICE_TYPE_OTHER},
+         * {@link #SERVICE_TYPE_TV}, {@link #SERVICE_TYPE_RADIO}
+         * </p><p>
+         * This is a required field.
          * </p><p>
          * Type: INTEGER
          * </p>
          */
-        public static final String TRANSPORT_STREAM_ID = "transport_stream_id";
+        public static final String COLUMN_SERVICE_TYPE = "service_type";
+
+        /**
+         * The original network ID of this TV channel.
+         * <p>
+         * This is used to identify the originating delivery system, if applicable. Use the same
+         * coding for {@code origianal_network_id} in the underlying broadcast standard if it is
+         * defined there (e.g. ETSI EN 300 468/TR 101 211 and ARIB STD-B10). If channels cannot be
+         * globally identified by 2-tuple {{@link #COLUMN_TRANSPORT_STREAM_ID},
+         * {@link #COLUMN_SERVICE_ID}}, one must carefully assign a value to this field to form a
+         * unique 3-tuple identification {{@link #COLUMN_ORIGINAL_NETWORK_ID},
+         * {@link #COLUMN_TRANSPORT_STREAM_ID}, {@link #COLUMN_SERVICE_ID}} for its channels.
+         * </p><p>
+         * This is a required field if the channel cannot be uniquely identified by a 2-tuple
+         * {{@link #COLUMN_TRANSPORT_STREAM_ID}, {@link #COLUMN_SERVICE_ID}}.
+         * </p><p>
+         * Type: INTEGER
+         * </p>
+         */
+        public static final String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
+
+        /**
+         * The transport stream ID of this channel.
+         * <p>
+         * This is used to identify the Transport Stream that contains the current channel from any
+         * other multiplex within a network, if applicable. Use the same coding for
+         * {@code transport_stream_id} defined in ISO/IEC 13818-1 if the channel is transmitted via
+         * the MPEG Transport Stream as is the case for many digital broadcast standards.
+         * </p><p>
+         * This is a required field if the current channel is transmitted via the MPEG Transport
+         * Stream.
+         * </p><p>
+         * Type: INTEGER
+         * </p>
+         */
+        public static final String COLUMN_TRANSPORT_STREAM_ID = "transport_stream_id";
+
+        /**
+         * The service ID of this channel.
+         * <p>
+         * This is used to identify the current service (roughly equivalent to channel) from any
+         * other service within the Transport Stream, if applicable. Use the same coding for
+         * {@code service_id} in the underlying broadcast standard if it is defined there (e.g. ETSI
+         * EN 300 468 and ARIB STD-B10) or {@code program_number} (which usually has the same value
+         * as {@code service_id}) in ISO/IEC 13818-1 if the channel is transmitted via the MPEG
+         * Transport Stream.
+         * </p><p>
+         * This is a required field if the current channel is transmitted via the MPEG Transport
+         * Stream.
+         * </p><p>
+         * Type: INTEGER
+         * </p>
+         */
+        public static final String COLUMN_SERVICE_ID = "service_id";
 
         /**
          * The channel number that is displayed to the user.
          * <p>
          * The format can vary depending on broadcast standard and product specification.
          * </p><p>
-         * Type: INTEGER
+         * Type: TEXT
          * </p>
          */
-        public static final String DISPLAY_NUMBER = "display_number";
+        public static final String COLUMN_DISPLAY_NUMBER = "display_number";
 
         /**
          * The channel name that is displayed to the user.
@@ -369,7 +445,7 @@
          * Type: TEXT
          * </p>
          */
-        public static final String DISPLAY_NAME = "display_name";
+        public static final String COLUMN_DISPLAY_NAME = "display_name";
 
         /**
          * The description of this TV channel.
@@ -379,7 +455,7 @@
          * Type: TEXT
          * </p>
          */
-        public static final String DESCRIPTION = "description";
+        public static final String COLUMN_DESCRIPTION = "description";
 
         /**
          * The flag indicating whether this TV channel is browsable or not.
@@ -391,7 +467,7 @@
          * Type: INTEGER (boolean)
          * </p>
          */
-        public static final String BROWSABLE = "browsable";
+        public static final String COLUMN_BROWSABLE = "browsable";
 
         /**
          * Generic data used by individual TV input services.
@@ -399,7 +475,7 @@
          * Type: BLOB
          * </p>
          */
-        public static final String DATA = "data";
+        public static final String COLUMN_DATA = "data";
 
 
         /**
@@ -413,7 +489,7 @@
          * Type: INTEGER
          * </p>
          */
-        public static final String VERSION_NUMBER = "version_number";
+        public static final String COLUMN_VERSION_NUMBER = "version_number";
 
         private Channels() {}
     }
@@ -441,7 +517,7 @@
          * Type: INTEGER (long)
          * </p>
          */
-        public static final String CHANNEL_ID = "channel_id";
+        public static final String COLUMN_CHANNEL_ID = "channel_id";
 
         /**
          * The title of this TV program.
@@ -449,7 +525,7 @@
          * Type: TEXT
          * </p>
          **/
-        public static final String TITLE = "title";
+        public static final String COLUMN_TITLE = "title";
 
         /**
          * The start time of this TV program, in milliseconds since the epoch.
@@ -457,7 +533,7 @@
          * Type: INTEGER (long)
          * </p>
          */
-        public static final String START_TIME_UTC_MILLIS = "start_time_utc_millis";
+        public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
 
         /**
          * The end time of this TV program, in milliseconds since the epoch.
@@ -465,7 +541,7 @@
          * Type: INTEGER (long)
          * </p>
          */
-        public static final String END_TIME_UTC_MILLIS = "end_time_utc_millis";
+        public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
 
         /**
          * The description of this TV program that is displayed to the user by default.
@@ -475,19 +551,19 @@
          * Type: TEXT
          * </p>
          */
-        public static final String DESCRIPTION = "description";
+        public static final String COLUMN_DESCRIPTION = "description";
 
         /**
          * The detailed, lengthy description of this TV program that is displayed only when the user
          * wants to see more information.
          * <p>
          * TV input services should leave this field empty if they have no additional
-         * details beyond {@link #DESCRIPTION}.
+         * details beyond {@link #COLUMN_DESCRIPTION}.
          * </p><p>
          * Type: TEXT
          * </p>
          */
-        public static final String LONG_DESCRIPTION = "long_description";
+        public static final String COLUMN_LONG_DESCRIPTION = "long_description";
 
         /**
          * Generic data used by TV input services.
@@ -495,7 +571,7 @@
          * Type: BLOB
          * </p>
          */
-        public static final String DATA = "data";
+        public static final String COLUMN_DATA = "data";
 
         /**
          * The version number of this row entry used by TV input services.
@@ -508,7 +584,7 @@
          * Type: INTEGER
          * </p>
          */
-        public static final String VERSION_NUMBER = "version_number";
+        public static final String COLUMN_VERSION_NUMBER = "version_number";
 
         private Programs() {}
     }
@@ -540,7 +616,8 @@
          * Type: INTEGER (long)
          * </p>
          */
-        public static final String WATCH_START_TIME_UTC_MILLIS = "watch_start_time_utc_millis";
+        public static final String COLUMN_WATCH_START_TIME_UTC_MILLIS =
+                "watch_start_time_utc_millis";
 
         /**
          * The UTC time that the user stopped watching this TV program, in milliseconds since the
@@ -549,7 +626,7 @@
          * Type: INTEGER (long)
          * </p>
          */
-        public static final String WATCH_END_TIME_UTC_MILLIS = "watch_end_time_utc_millis";
+        public static final String COLUMN_WATCH_END_TIME_UTC_MILLIS = "watch_end_time_utc_millis";
 
         /**
          * The channel ID that contains this TV program.
@@ -557,7 +634,7 @@
          * Type: INTEGER (long)
          * </p>
          */
-        public static final String CHANNEL_ID = "channel_id";
+        public static final String COLUMN_CHANNEL_ID = "channel_id";
 
         /**
          * The title of this TV program.
@@ -565,7 +642,7 @@
          * Type: TEXT
          * </p>
          */
-        public static final String TITLE = "title";
+        public static final String COLUMN_TITLE = "title";
 
         /**
          * The start time of this TV program, in milliseconds since the epoch.
@@ -573,7 +650,7 @@
          * Type: INTEGER (long)
          * </p>
          */
-        public static final String START_TIME_UTC_MILLIS = "start_time_utc_millis";
+        public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
 
         /**
          * The end time of this TV program, in milliseconds since the epoch.
@@ -581,7 +658,7 @@
          * Type: INTEGER (long)
          * </p>
          */
-        public static final String END_TIME_UTC_MILLIS = "end_time_utc_millis";
+        public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
 
         /**
          * The description of this TV program.
@@ -589,7 +666,7 @@
          * Type: TEXT
          * </p>
          */
-        public static final String DESCRIPTION = "description";
+        public static final String COLUMN_DESCRIPTION = "description";
 
         private WatchedPrograms() {}
     }
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 2303d65..b02a79d 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -300,10 +300,6 @@
     public void onDetachedFromWindow() {
     }
 
-    @Override
-    public void onWindowDismissed() {
-    }
-
     /** {@inheritDoc} */
     @Override
     public void onPanelClosed(int featureId, Menu menu) {
diff --git a/core/java/android/service/fingerprint/FingerprintManager.java b/core/java/android/service/fingerprint/FingerprintManager.java
new file mode 100644
index 0000000..0d14c59
--- /dev/null
+++ b/core/java/android/service/fingerprint/FingerprintManager.java
@@ -0,0 +1,200 @@
+/**
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.fingerprint;
+
+import android.app.ActivityManagerNative;
+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.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+/**
+ * A class that coordinates access to the fingerprint hardware.
+ */
+
+public class FingerprintManager {
+    private static final String TAG = "FingerprintManager";
+    protected static final boolean DEBUG = true;
+    private static final String FINGERPRINT_SERVICE_PACKAGE = "com.android.service.fingerprint";
+    private static final String FINGERPRINT_SERVICE_CLASS =
+            "com.android.service.fingerprint.FingerprintService";
+    private static final int MSG_ENROLL_RESULT = 100;
+    private static final int MSG_SCANNED = 101;
+    private static final int MSG_ERROR = 102;
+    private static final int MSG_REMOVED = 103;
+
+    public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10;
+    public static final int FINGERPRINT_ERROR = -1; // One of the error messages below.
+
+    // Progress messages.
+    public static final int FINGERPRINT_SCANNED = 1;
+    public static final int FINGERPRINT_TEMPLATE_ENROLLING = 2;
+    public static final int FINGERPRINT_TEMPLATE_REMOVED = 4;
+
+    // Error messages. Must agree with fingerprint HAL definitions.
+    public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1;
+    public static final int FINGERPRINT_ERROR_BAD_CAPTURE = 2;
+    public static final int FINGERPRINT_ERROR_TIMEOUT = 3;
+    public static final int FINGERPRINT_ERROR_NO_SPACE = 4;
+
+    private IFingerprintService mService;
+    private FingerprintManagerReceiver mClientReceiver;
+
+    private Handler mHandler = new Handler() {
+        public void handleMessage(android.os.Message msg) {
+            if (mClientReceiver != null) {
+                switch(msg.what) {
+                    case MSG_ENROLL_RESULT:
+                        mClientReceiver.onEnrollResult(msg.arg1, msg.arg2);
+                        break;
+                    case MSG_SCANNED:
+                        mClientReceiver.onScanned(msg.arg1, msg.arg2);
+                        break;
+                    case MSG_ERROR:
+                        mClientReceiver.onError(msg.arg1);
+                        break;
+                    case MSG_REMOVED:
+                        mClientReceiver.onRemoved(msg.arg1);
+                }
+            }
+        }
+    };
+
+    public FingerprintManager(Context context) {
+        // Connect to service...
+        Intent intent = new Intent();
+        intent.setClassName(FINGERPRINT_SERVICE_PACKAGE, FINGERPRINT_SERVICE_CLASS);
+        if (!context.bindServiceAsUser(intent, mFingerprintConnection,
+                Context.BIND_AUTO_CREATE, UserHandle.CURRENT_OR_SELF)) {
+            if (DEBUG) Log.v(TAG, "Can't bind to " + FINGERPRINT_SERVICE_CLASS);
+        }
+    }
+
+    private final ServiceConnection mFingerprintConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            if (DEBUG) Log.v(TAG, "Connected to FingerprintService");
+            mService = IFingerprintService.Stub.asInterface(service);
+            try {
+                mService.startListening(mServiceReceiver, getCurrentUserId());
+            } catch (RemoteException e) {
+                if (DEBUG) Log.v(TAG, "Failed to set callback", e);
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            if (DEBUG) Log.v(TAG, "Disconnected from FingerprintService");
+            mService = null;
+        }
+    };
+
+    private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
+
+        public void onEnrollResult(int fingerprintId,  int remaining) {
+            mHandler.obtainMessage(MSG_ENROLL_RESULT, fingerprintId, remaining).sendToTarget();
+        }
+
+        public void onScanned(int fingerprintId, int confidence) {
+            mHandler.obtainMessage(MSG_SCANNED, fingerprintId, confidence)
+                    .sendToTarget();;
+        }
+
+        public void onError(int error) {
+            mHandler.obtainMessage(MSG_ERROR, error, 0).sendToTarget();
+        }
+
+        public void onRemoved(int fingerprintId) {
+            mHandler.obtainMessage(MSG_REMOVED, fingerprintId, 0).sendToTarget();
+        }
+    };
+
+    /**
+     * Start the enrollment process.  Timeout dictates how long to wait for the user to
+     * enroll a fingerprint.
+     *
+     * @param timeout
+     */
+    public void enroll(long timeout) {
+        if (mServiceReceiver == null) {
+            throw new IllegalStateException("enroll: Call registerCallback() first");
+        }
+        if (mService != null) try {
+            mService.enroll(timeout, getCurrentUserId());
+        } catch (RemoteException e) {
+            Log.v(TAG, "Remote exception while enrolling: ", e);
+        }
+    }
+
+    /**
+     * Remove the given fingerprintId from the system.  FingerprintId of 0 has special meaning
+     * which is to delete all fingerprint data for the current user. Use with caution.
+     * @param fingerprintId
+     */
+    public void remove(int fingerprintId) {
+        if (mService != null) try {
+            mService.remove(fingerprintId, getCurrentUserId());
+        } catch (RemoteException e) {
+            Log.v(TAG, "Remote exception during remove of fingerprintId: " + fingerprintId, e);
+        }
+    }
+
+    /**
+     * Starts listening for fingerprint events.  When a finger is scanned or recognized, the
+     * client will be notified via the callback.
+     */
+    public void startListening(FingerprintManagerReceiver receiver) {
+        mClientReceiver = receiver;
+        if (mService != null) {
+            try {
+                mService.startListening(mServiceReceiver, getCurrentUserId());
+            } catch (RemoteException e) {
+                Log.v(TAG, "Remote exception in startListening(): ", e);
+            }
+        }
+    }
+
+    private int getCurrentUserId() {
+        try {
+            return ActivityManagerNative.getDefault().getCurrentUser().id;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to get current user id\n");
+            return UserHandle.USER_NULL;
+        }
+    }
+
+    /**
+     * Stops the client from listening to fingerprint events.
+     */
+    public void stopListening() {
+        mClientReceiver = null;
+        if (mService != null) {
+            try {
+                mService.stopListening(getCurrentUserId());
+            } catch (RemoteException e) {
+                Log.v(TAG, "Remote exception in stopListening(): ", e);
+            }
+        } else {
+            Log.w(TAG, "stopListening(): Service not connected!");
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintManagerReceiver.java b/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
new file mode 100644
index 0000000..34f1655
--- /dev/null
+++ b/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
@@ -0,0 +1,59 @@
+package android.service.fingerprint;
+/**
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class FingerprintManagerReceiver {
+    /**
+     * Fingerprint enrollment progress update. Enrollment is considered complete if
+     * remaining hits 0 without {@link #onError(int)} being called.
+     *
+     * @param fingerprintId the fingerprint we're currently enrolling
+     * @param remaining the number of samples required to complete enrollment. It's up to
+     * the hardware to define what each step in enrollment means. Some hardware
+     * requires multiple samples of the same part of the finger.  Others require sampling of
+     * different parts of the finger.  The enrollment flow can use remaining to
+     * mean "step x" of the process or "just need another sample."
+     */
+    public void onEnrollResult(int fingerprintId,  int remaining) { }
+
+    /**
+     * Fingerprint scan detected. Most clients will use this function to detect a fingerprint
+     *
+     * @param fingerprintId is the finger the hardware has detected.
+     * @param confidence from 0 (no confidence) to 65535 (high confidence). Fingerprint 0 has
+     * special meaning - the finger wasn't recognized.
+     */
+    public void onScanned(int fingerprintId, int confidence) { }
+
+    /**
+     * An error was detected during scan or enrollment.  One of
+     * {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE},
+     * {@link FingerprintManager#FINGERPRINT_ERROR_BAD_CAPTURE} or
+     * {@link FingerprintManager#FINGERPRINT_ERROR_TIMEOUT}
+     * {@link FingerprintManager#FINGERPRINT_ERROR_NO_SPACE}
+     *
+     * @param error one of the above error codes
+     */
+    public void onError(int error) { }
+
+    /**
+     * The given fingerprint template was successfully removed by the driver.
+     * See {@link FingerprintManager#remove(int)}
+     *
+     * @param fingerprintId id of template to remove.
+     */
+    public void onRemoved(int fingerprintId) { }
+}
\ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintService.java b/core/java/android/service/fingerprint/FingerprintService.java
new file mode 100644
index 0000000..c7fa7cd
--- /dev/null
+++ b/core/java/android/service/fingerprint/FingerprintService.java
@@ -0,0 +1,219 @@
+/**
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.fingerprint;
+
+import android.app.Service;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+import java.util.HashMap;
+
+/**
+ * A service to manage multiple clients that want to access the fingerprint HAL API.
+ * The service is responsible for maintaining a list of clients and dispatching all
+ * fingerprint -related events.
+ *
+ * @hide
+ */
+public class FingerprintService extends Service {
+    private final String TAG = FingerprintService.class.getSimpleName() +
+            "[" + getClass().getSimpleName() + "]";
+    private static final boolean DEBUG = true;
+    HashMap<IFingerprintServiceReceiver, ClientData> mClients =
+            new HashMap<IFingerprintServiceReceiver, ClientData>();
+
+    private static final int MSG_NOTIFY = 10;
+
+    Handler mHandler = new Handler() {
+        public void handleMessage(android.os.Message msg) {
+            switch (msg.what) {
+                case MSG_NOTIFY:
+                    handleNotify(msg.arg1, msg.arg2, (Integer) msg.obj);
+                    break;
+
+                default:
+                    Slog.w(TAG, "Unknown message:" + msg.what);
+            }
+        }
+    };
+
+    private static final int STATE_IDLE = 0;
+    private static final int STATE_LISTENING = 1;
+    private static final int STATE_ENROLLING = 2;
+    private static final int STATE_DELETING = 3;
+    private static final long MS_PER_SEC = 1000;
+
+    private static final class ClientData {
+        public IFingerprintServiceReceiver receiver;
+        int state;
+        int userId;
+    }
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
+        return new FingerprintServiceWrapper();
+    }
+
+    // JNI methods to communicate from FingerprintManagerService to HAL
+    native int nativeEnroll(int timeout);
+    native int nativeRemove(int fingerprintId);
+
+    // JNI methods for communicating from HAL to clients
+    void notify(int msg, int arg1, int arg2) {
+        mHandler.obtainMessage(MSG_NOTIFY, msg, arg1, arg2).sendToTarget();
+    }
+
+    void handleNotify(int msg, int arg1, int arg2) {
+        for (int i = 0; i < mClients.size(); i++) {
+            ClientData clientData = mClients.get(i);
+            switch (msg) {
+                case FingerprintManager.FINGERPRINT_ERROR: {
+                    if (clientData.state != STATE_IDLE) {
+                        // FINGERPRINT_ERROR_HW_UNAVAILABLE
+                        // FINGERPRINT_ERROR_BAD_CAPTURE
+                        // FINGERPRINT_ERROR_TIMEOUT
+                        // FINGERPRINT_ERROR_NO_SPACE
+                        final int error = arg1;
+                        clientData.state = STATE_IDLE;
+                        if (clientData.receiver != null) {
+                            try {
+                                clientData.receiver.onError(error);
+                            } catch (RemoteException e) {
+                                Slog.e(TAG, "can't send message to client. Did it die?", e);
+                            }
+                        }
+                    }
+                }
+                break;
+                case FingerprintManager.FINGERPRINT_SCANNED: {
+                    final int fingerId = arg1;
+                    final int confidence = arg2;
+                    if (clientData.state == STATE_LISTENING && clientData.receiver != null) {
+                        try {
+                            clientData.receiver.onScanned(fingerId, confidence);
+                        } catch (RemoteException e) {
+                            Slog.e(TAG, "can't send message to client. Did it die?", e);
+                        }
+                    }
+                    break;
+                }
+                case FingerprintManager.FINGERPRINT_TEMPLATE_ENROLLING: {
+                    if (clientData.state == STATE_ENROLLING) {
+                        final int fingerId = arg1;
+                        final int remaining = arg2;
+                        if (remaining == 0) {
+                            FingerprintUtils.addFingerprintIdForUser(fingerId,
+                                    getContentResolver(), clientData.userId);
+                            clientData.state = STATE_IDLE; // Nothing left to do
+                        }
+                        if (clientData.receiver != null) {
+                            try {
+                                clientData.receiver.onEnrollResult(fingerId, remaining);
+                            } catch (RemoteException e) {
+                                Slog.e(TAG, "can't send message to client. Did it die?", e);
+                            }
+                        }
+                    }
+                    break;
+                }
+                case FingerprintManager.FINGERPRINT_TEMPLATE_REMOVED: {
+                    int fingerId = arg1;
+                    if (fingerId == 0) throw new IllegalStateException("Got illegal id from HAL");
+                    if (clientData.state == STATE_DELETING) {
+                        FingerprintUtils.removeFingerprintIdForUser(fingerId, getContentResolver(),
+                                clientData.userId);
+                        if (clientData.receiver != null) {
+                            try {
+                                clientData.receiver.onRemoved(fingerId);
+                            } catch (RemoteException e) {
+                                Slog.e(TAG, "can't send message to client. Did it die?", e);
+                            }
+                        }
+                    }
+                }
+                break;
+            }
+        }
+    }
+
+    int enroll(IFingerprintServiceReceiver receiver, long timeout, int userId) {
+        ClientData clientData = mClients.get(receiver);
+        if (clientData != null) {
+            if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+            clientData.state = STATE_ENROLLING;
+            return nativeEnroll((int) (timeout / MS_PER_SEC));
+        }
+        return -1;
+    }
+
+    int remove(IFingerprintServiceReceiver receiver, int fingerId, int userId) {
+        ClientData clientData = mClients.get(receiver);
+        if (clientData != null) {
+            if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+            clientData.state = STATE_DELETING;
+            // The fingerprint id will be removed when we get confirmation from the HAL
+            return nativeRemove(fingerId);
+        }
+        return -1;
+    }
+
+    void startListening(IFingerprintServiceReceiver receiver, int userId) {
+        ClientData clientData = new ClientData();
+        clientData.state = STATE_LISTENING;
+        clientData.receiver = receiver;
+        clientData.userId = userId;
+        mClients.put(receiver, clientData);
+    }
+
+    void stopListening(IFingerprintServiceReceiver receiver, int userId) {
+        ClientData clientData = mClients.get(receiver);
+        if (clientData != null) {
+            clientData.state = STATE_IDLE;
+            clientData.userId = -1;
+            clientData.receiver = null;
+        }
+        mClients.remove(receiver);
+    }
+
+    private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
+        IFingerprintServiceReceiver mReceiver;
+        public int enroll(long timeout, int userId) {
+            return mReceiver != null ? FingerprintService.this.enroll(mReceiver, timeout, userId)
+                    : FingerprintManager.FINGERPRINT_ERROR_NO_RECEIVER;
+        }
+
+        public int remove(int fingerprintId, int userId) {
+            return FingerprintService.this.remove(mReceiver, fingerprintId, userId);
+        }
+
+        public void startListening(IFingerprintServiceReceiver receiver, int userId) {
+            mReceiver = receiver;
+            FingerprintService.this.startListening(receiver, userId);
+        }
+
+        public void stopListening(int userId) {
+            FingerprintService.this.stopListening(mReceiver, userId);
+        }
+    }
+}
diff --git a/core/java/android/service/fingerprint/FingerprintUtils.java b/core/java/android/service/fingerprint/FingerprintUtils.java
new file mode 100644
index 0000000..81a2aac
--- /dev/null
+++ b/core/java/android/service/fingerprint/FingerprintUtils.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 android.service.fingerprint;
+
+import android.content.ContentResolver;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.util.Arrays;
+
+class FingerprintUtils {
+    private static final boolean DEBUG = true;
+    private static final String TAG = "FingerprintUtils";
+
+    public static int[] getFingerprintIdsForUser(ContentResolver res, int userId) {
+        String fingerIdsRaw = Settings.Secure.getStringForUser(res,
+                Settings.Secure.USER_FINGERPRINT_IDS, userId);
+
+        String[] fingerStringIds = fingerIdsRaw.replace("[","").replace("]","").split(", ");
+        int result[] = new int[fingerStringIds.length];
+        for (int i = 0; i < result.length; i++) {
+            try {
+                result[i] = Integer.decode(fingerStringIds[i]);
+            } catch (NumberFormatException e) {
+                if (DEBUG) Log.d(TAG, "Error when parsing finger id " + fingerStringIds[i]);
+            }
+        }
+        return result;
+    }
+
+    public static void addFingerprintIdForUser(int fingerId, ContentResolver res, int userId) {
+        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;
+        }
+        int[] newList = Arrays.copyOf(fingerIds, fingerIds.length + 1);
+        newList[fingerIds.length] = fingerId;
+        Settings.Secure.putStringForUser(res, Settings.Secure.USER_FINGERPRINT_IDS,
+                Arrays.toString(newList), userId);
+    }
+
+    public static boolean removeFingerprintIdForUser(int fingerId, ContentResolver res, int userId)
+    {
+        // 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");
+
+        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) {
+            Settings.Secure.putStringForUser(res, Settings.Secure.USER_FINGERPRINT_IDS,
+                    Arrays.toString(Arrays.copyOf(resultIds, resultCount)), userId);
+            return true;
+        }
+        return false;
+    }
+
+};
+
diff --git a/core/java/android/service/fingerprint/IFingerprintService.aidl b/core/java/android/service/fingerprint/IFingerprintService.aidl
new file mode 100644
index 0000000..e92c20c
--- /dev/null
+++ b/core/java/android/service/fingerprint/IFingerprintService.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.fingerprint;
+
+import android.os.Bundle;
+import android.service.fingerprint.IFingerprintServiceReceiver;
+
+/**
+ * Communication channel from client to the fingerprint service.
+ * @hide
+ */
+interface IFingerprintService {
+    // Returns 0 if successfully started, -1 otherwise
+    int enroll(long timeout, int userId);
+
+    // Returns 0 if fingerprintId's template can be removed, -1 otherwise
+    int remove(int fingerprintId, int userId);
+
+    // Start listening for fingerprint events.  This has the side effect of starting
+    // the hardware if not already started.
+    oneway void startListening(IFingerprintServiceReceiver receiver, int userId);
+
+    // Stops listening for fingerprints
+    oneway void stopListening(int userId);
+}
diff --git a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
new file mode 100644
index 0000000..4826b59
--- /dev/null
+++ b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.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.service.fingerprint;
+
+import android.os.Bundle;
+import android.os.UserHandle;
+
+/**
+ * Communication channel from the FingerprintService back to FingerprintManager.
+ * @hide
+ */
+oneway interface IFingerprintServiceReceiver {
+    void onEnrollResult(int fingerprintId,  int remaining);
+    void onScanned(int fingerprintId, int confidence);
+    void onError(int error);
+    void onRemoved(int fingerprintId);
+}
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index 71e3166..aa724f0 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -41,16 +41,25 @@
     public static final int FLAG_RELEVANT_ALWAYS = 1 << 1;
 
     public final Uri id;
-    public String caption;
-    public int state;
-    public int flags;
+    public final String summary;
+    public final String line1;
+    public final String line2;
+    public final int icon;
+    public final int state;
+    public final int flags;
 
-    public Condition(Uri id, String caption, int state, int flags) {
+    public Condition(Uri id, String summary, String line1, String line2, int icon,
+            int state, int flags) {
         if (id == null) throw new IllegalArgumentException("id is required");
-        if (caption == null) throw new IllegalArgumentException("caption is required");
+        if (summary == null) throw new IllegalArgumentException("summary is required");
+        if (line1 == null) throw new IllegalArgumentException("line1 is required");
+        if (line2 == null) throw new IllegalArgumentException("line2 is required");
         if (!isValidState(state)) throw new IllegalArgumentException("state is invalid: " + state);
         this.id = id;
-        this.caption = caption;
+        this.summary = summary;
+        this.line1 = line1;
+        this.line2 = line2;
+        this.icon = icon;
         this.state = state;
         this.flags = flags;
     }
@@ -58,6 +67,9 @@
     private Condition(Parcel source) {
         this((Uri)source.readParcelable(Condition.class.getClassLoader()),
                 source.readString(),
+                source.readString(),
+                source.readString(),
+                source.readInt(),
                 source.readInt(),
                 source.readInt());
     }
@@ -69,16 +81,22 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeParcelable(id, 0);
-        dest.writeString(caption);
+        dest.writeString(summary);
+        dest.writeString(line1);
+        dest.writeString(line2);
+        dest.writeInt(icon);
         dest.writeInt(state);
-        dest.writeInt(flags);
+        dest.writeInt(this.flags);
     }
 
     @Override
     public String toString() {
         return new StringBuilder(Condition.class.getSimpleName()).append('[')
             .append("id=").append(id)
-            .append(",caption=").append(caption)
+            .append(",summary=").append(summary)
+            .append(",line1=").append(line1)
+            .append(",line2=").append(line2)
+            .append(",icon=").append(icon)
             .append(",state=").append(stateToString(state))
             .append(",flags=").append(flags)
             .append(']').toString();
@@ -92,20 +110,31 @@
         throw new IllegalArgumentException("state is invalid: " + state);
     }
 
+    public static String relevanceToString(int flags) {
+        final boolean now = (flags & FLAG_RELEVANT_NOW) != 0;
+        final boolean always = (flags & FLAG_RELEVANT_ALWAYS) != 0;
+        if (!now && !always) return "NONE";
+        if (now && always) return "NOW, ALWAYS";
+        return now ? "NOW" : "ALWAYS";
+    }
+
     @Override
     public boolean equals(Object o) {
         if (!(o instanceof Condition)) return false;
         if (o == this) return true;
         final Condition other = (Condition) o;
         return Objects.equals(other.id, id)
-                && Objects.equals(other.caption, caption)
+                && Objects.equals(other.summary, summary)
+                && Objects.equals(other.line1, line1)
+                && Objects.equals(other.line2, line2)
+                && other.icon == icon
                 && other.state == state
                 && other.flags == flags;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(id, caption, state, flags);
+        return Objects.hash(id, summary, line1, line2, icon, state, flags);
     }
 
     @Override
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index d4b29d8..d4919eb 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -17,11 +17,15 @@
 package android.service.notification;
 
 import android.service.notification.StatusBarNotification;
+import android.service.notification.NotificationOrderUpdate;
 
 /** @hide */
 oneway interface INotificationListener
 {
-    void onListenerConnected(in String[] notificationKeys);
-    void onNotificationPosted(in StatusBarNotification notification);
-    void onNotificationRemoved(in StatusBarNotification notification);
+    void onListenerConnected(in NotificationOrderUpdate update);
+    void onNotificationPosted(in StatusBarNotification notification,
+            in NotificationOrderUpdate update);
+    void onNotificationRemoved(in StatusBarNotification notification,
+            in NotificationOrderUpdate update);
+    void onNotificationOrderUpdate(in NotificationOrderUpdate update);
 }
\ No newline at end of file
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 3673f03..a94f45a 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -22,10 +22,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.IBinder;
+import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.UserHandle;
 import android.util.Log;
 
+import java.util.Comparator;
+import java.util.HashMap;
+
 /**
  * A service that receives calls from the system when new notifications are posted or removed.
  * <p>To extend this class, you must declare the service in your manifest file with
@@ -46,6 +49,7 @@
             + "[" + getClass().getSimpleName() + "]";
 
     private INotificationListenerWrapper mWrapper = null;
+    private String[] mNotificationKeys;
 
     private INotificationManager mNoMan;
 
@@ -95,6 +99,15 @@
         // optional
     }
 
+    /**
+     * Implement this method to be notified when the notification order cahnges.
+     *
+     * Call {@link #getOrderedNotificationKeys()} to retrieve the new order.
+     */
+    public void onNotificationOrderUpdate() {
+        // optional
+    }
+
     private final INotificationManager getNotificationInterface() {
         if (mNoMan == null) {
             mNoMan = INotificationManager.Stub.asInterface(
@@ -202,7 +215,7 @@
      * Request the list of outstanding notifications (that is, those that are visible to the
      * current user). Useful when you don't know what's already been posted.
      *
-     * @return An array of active notifications.
+     * @return An array of active notifications, sorted in natural order.
      */
     public StatusBarNotification[] getActiveNotifications() {
         return getActiveNotifications(null /*all*/);
@@ -213,7 +226,8 @@
      * current user). Useful when you don't know what's already been posted.
      *
      * @param keys A specific list of notification keys, or {@code null} for all.
-     * @return An array of active notifications.
+     * @return An array of active notifications, sorted in natural order
+     *   if {@code keys} is {@code null}.
      */
     public StatusBarNotification[] getActiveNotifications(String[] keys) {
         if (!isBound()) return null;
@@ -226,21 +240,15 @@
     }
 
     /**
-     * Request the list of outstanding notification keys(that is, those that are visible to the
-     * current user).  You can use the notification keys for subsequent retrieval via
+     * Request the list of notification keys in their current natural order.
+     * You can use the notification keys for subsequent retrieval via
      * {@link #getActiveNotifications(String[]) or dismissal via
      * {@link #cancelNotifications(String[]).
      *
-     * @return An array of active notification keys.
+     * @return An array of active notification keys, in their natural order.
      */
-    public String[] getActiveNotificationKeys() {
-        if (!isBound()) return null;
-        try {
-            return getNotificationInterface().getActiveNotificationKeysFromListener(mWrapper);
-        } catch (android.os.RemoteException ex) {
-            Log.v(TAG, "Unable to contact notification manager", ex);
-        }
-        return null;
+    public String[] getOrderedNotificationKeys() {
+        return mNotificationKeys;
     }
 
     @Override
@@ -261,28 +269,60 @@
 
     private class INotificationListenerWrapper extends INotificationListener.Stub {
         @Override
-        public void onNotificationPosted(StatusBarNotification sbn) {
+        public void onNotificationPosted(StatusBarNotification sbn,
+                NotificationOrderUpdate update) {
             try {
-                NotificationListenerService.this.onNotificationPosted(sbn);
+                // protect subclass from concurrent modifications of (@link mNotificationKeys}.
+                synchronized (mWrapper) {
+                    updateNotificationKeys(update);
+                    NotificationListenerService.this.onNotificationPosted(sbn);
+                }
             } catch (Throwable t) {
-                Log.w(TAG, "Error running onNotificationPosted", t);
+                Log.w(TAG, "Error running onOrderedNotificationPosted", t);
             }
         }
         @Override
-        public void onNotificationRemoved(StatusBarNotification sbn) {
+        public void onNotificationRemoved(StatusBarNotification sbn,
+                NotificationOrderUpdate update) {
             try {
-                NotificationListenerService.this.onNotificationRemoved(sbn);
+                // protect subclass from concurrent modifications of (@link mNotificationKeys}.
+                synchronized (mWrapper) {
+                    updateNotificationKeys(update);
+                    NotificationListenerService.this.onNotificationRemoved(sbn);
+                }
             } catch (Throwable t) {
                 Log.w(TAG, "Error running onNotificationRemoved", t);
             }
         }
         @Override
-        public void onListenerConnected(String[] notificationKeys) {
+        public void onListenerConnected(NotificationOrderUpdate update) {
             try {
-                NotificationListenerService.this.onListenerConnected(notificationKeys);
+                // protect subclass from concurrent modifications of (@link mNotificationKeys}.
+                synchronized (mWrapper) {
+                    updateNotificationKeys(update);
+                    NotificationListenerService.this.onListenerConnected(mNotificationKeys);
+                }
             } catch (Throwable t) {
                 Log.w(TAG, "Error running onListenerConnected", t);
             }
         }
+        @Override
+        public void onNotificationOrderUpdate(NotificationOrderUpdate update)
+                throws RemoteException {
+            try {
+                // protect subclass from concurrent modifications of (@link mNotificationKeys}.
+                synchronized (mWrapper) {
+                    updateNotificationKeys(update);
+                    NotificationListenerService.this.onNotificationOrderUpdate();
+                }
+            } catch (Throwable t) {
+                Log.w(TAG, "Error running onNotificationOrderUpdate", t);
+            }
+        }
+    }
+
+    private void updateNotificationKeys(NotificationOrderUpdate update) {
+        // TODO: avoid garbage by comparing the lists
+        mNotificationKeys = update.getOrderedKeys();
     }
 }
diff --git a/core/java/android/service/notification/NotificationOrderUpdate.aidl b/core/java/android/service/notification/NotificationOrderUpdate.aidl
new file mode 100644
index 0000000..5d50641
--- /dev/null
+++ b/core/java/android/service/notification/NotificationOrderUpdate.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.service.notification;
+
+parcelable NotificationOrderUpdate;
diff --git a/core/java/android/service/notification/NotificationOrderUpdate.java b/core/java/android/service/notification/NotificationOrderUpdate.java
new file mode 100644
index 0000000..20e19a3
--- /dev/null
+++ b/core/java/android/service/notification/NotificationOrderUpdate.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.notification;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class NotificationOrderUpdate implements Parcelable {
+    // TODO replace this with an update instead of the whole array
+    private final String[] mKeys;
+
+    /** @hide */
+    public NotificationOrderUpdate(String[] keys) {
+        this.mKeys = keys;
+    }
+
+    public NotificationOrderUpdate(Parcel in) {
+        this.mKeys = in.readStringArray();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeStringArray(this.mKeys);
+    }
+
+    public static final Parcelable.Creator<NotificationOrderUpdate> CREATOR
+            = new Parcelable.Creator<NotificationOrderUpdate>() {
+        public NotificationOrderUpdate createFromParcel(Parcel parcel) {
+            return new NotificationOrderUpdate(parcel);
+        }
+
+        public NotificationOrderUpdate[] newArray(int size) {
+            return new NotificationOrderUpdate[size];
+        }
+    };
+
+    /**
+     * @hide
+     * @return ordered list of keys
+     */
+    String[] getOrderedKeys() {
+        return mKeys;
+    }
+}
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 72720d1..e7cdc4e 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -87,7 +87,7 @@
     }
 
     private String key() {
-        return pkg + '|' + id + '|' + tag + '|' + uid;
+        return user.getIdentifier() + "|" + pkg + "|" + id + "|" + tag + "|" + uid;
     }
 
     public void writeToParcel(Parcel out, int flags) {
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 925ddcf..846e292 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -16,6 +16,8 @@
 
 package android.service.notification;
 
+import android.content.ComponentName;
+import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -25,6 +27,8 @@
 import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Objects;
 
 /**
@@ -51,6 +55,10 @@
     private static final String SLEEP_ATT_END_HR = "endHour";
     private static final String SLEEP_ATT_END_MIN = "endMin";
 
+    private static final String CONDITION_TAG = "condition";
+    private static final String CONDITION_ATT_COMPONENT = "component";
+    private static final String CONDITION_ATT_ID = "id";
+
     public boolean allowCalls;
     public boolean allowMessages;
 
@@ -59,6 +67,8 @@
     public int sleepStartMinute;
     public int sleepEndHour;
     public int sleepEndMinute;
+    public ComponentName[] conditionComponents;
+    public Uri[] conditionIds;
 
     public ZenModeConfig() { }
 
@@ -72,6 +82,16 @@
         sleepStartMinute = source.readInt();
         sleepEndHour = source.readInt();
         sleepEndMinute = source.readInt();
+        int len = source.readInt();
+        if (len > 0) {
+            conditionComponents = new ComponentName[len];
+            source.readTypedArray(conditionComponents, ComponentName.CREATOR);
+        }
+        len = source.readInt();
+        if (len > 0) {
+            conditionIds = new Uri[len];
+            source.readTypedArray(conditionIds, Uri.CREATOR);
+        }
     }
 
     @Override
@@ -88,6 +108,18 @@
         dest.writeInt(sleepStartMinute);
         dest.writeInt(sleepEndHour);
         dest.writeInt(sleepEndMinute);
+        if (conditionComponents != null && conditionComponents.length > 0) {
+            dest.writeInt(conditionComponents.length);
+            dest.writeTypedArray(conditionComponents, 0);
+        } else {
+            dest.writeInt(0);
+        }
+        if (conditionIds != null && conditionIds.length > 0) {
+            dest.writeInt(conditionIds.length);
+            dest.writeTypedArray(conditionIds, 0);
+        } else {
+            dest.writeInt(0);
+        }
     }
 
     @Override
@@ -98,6 +130,10 @@
             .append(",sleepMode=").append(sleepMode)
             .append(",sleepStart=").append(sleepStartHour).append('.').append(sleepStartMinute)
             .append(",sleepEnd=").append(sleepEndHour).append('.').append(sleepEndMinute)
+            .append(",conditionComponents=")
+            .append(conditionComponents == null ? null : TextUtils.join(",", conditionComponents))
+            .append(",conditionIds=")
+            .append(conditionIds == null ? null : TextUtils.join(",", conditionIds))
             .append(']').toString();
     }
 
@@ -112,13 +148,16 @@
                 && other.sleepStartHour == sleepStartHour
                 && other.sleepStartMinute == sleepStartMinute
                 && other.sleepEndHour == sleepEndHour
-                && other.sleepEndMinute == sleepEndMinute;
+                && other.sleepEndMinute == sleepEndMinute
+                && Objects.deepEquals(other.conditionComponents, conditionComponents)
+                && Objects.deepEquals(other.conditionIds, conditionIds);
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(allowCalls, allowMessages, sleepMode, sleepStartHour,
-                sleepStartMinute, sleepEndHour, sleepEndMinute);
+                sleepStartMinute, sleepEndHour, sleepEndMinute,
+                Arrays.hashCode(conditionComponents), Arrays.hashCode(conditionIds));
     }
 
     public boolean isValid() {
@@ -136,9 +175,18 @@
         if (!ZEN_TAG.equals(tag)) return null;
         final ZenModeConfig rt = new ZenModeConfig();
         final int version = Integer.parseInt(parser.getAttributeValue(null, ZEN_ATT_VERSION));
+        final ArrayList<ComponentName> conditionComponents = new ArrayList<ComponentName>();
+        final ArrayList<Uri> conditionIds = new ArrayList<Uri>();
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
             tag = parser.getName();
-            if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) return rt;
+            if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) {
+                if (!conditionComponents.isEmpty()) {
+                    rt.conditionComponents = conditionComponents
+                            .toArray(new ComponentName[conditionComponents.size()]);
+                    rt.conditionIds = conditionIds.toArray(new Uri[conditionIds.size()]);
+                }
+                return rt;
+            }
             if (type == XmlPullParser.START_TAG) {
                 if (ALLOW_TAG.equals(tag)) {
                     rt.allowCalls = safeBoolean(parser, ALLOW_ATT_CALLS, false);
@@ -155,10 +203,18 @@
                     rt.sleepStartMinute = isValidMinute(startMinute) ? startMinute : 0;
                     rt.sleepEndHour = isValidHour(endHour) ? endHour : 0;
                     rt.sleepEndMinute = isValidMinute(endMinute) ? endMinute : 0;
+                } else if (CONDITION_TAG.equals(tag)) {
+                    final ComponentName component =
+                            safeComponentName(parser, CONDITION_ATT_COMPONENT);
+                    final Uri conditionId = safeUri(parser, CONDITION_ATT_ID);
+                    if (component != null && conditionId != null) {
+                        conditionComponents.add(component);
+                        conditionIds.add(conditionId);
+                    }
                 }
             }
         }
-        return rt;
+        throw new IllegalStateException("Failed to reach END_DOCUMENT");
     }
 
     public void writeXml(XmlSerializer out) throws IOException {
@@ -180,6 +236,16 @@
         out.attribute(null, SLEEP_ATT_END_MIN, Integer.toString(sleepEndMinute));
         out.endTag(null, SLEEP_TAG);
 
+        if (conditionComponents != null && conditionIds != null
+                && conditionComponents.length == conditionIds.length) {
+            for (int i = 0; i < conditionComponents.length; i++) {
+                out.startTag(null, CONDITION_TAG);
+                out.attribute(null, CONDITION_ATT_COMPONENT,
+                        conditionComponents[i].flattenToString());
+                out.attribute(null, CONDITION_ATT_ID, conditionIds[i].toString());
+                out.endTag(null, CONDITION_TAG);
+            }
+        }
         out.endTag(null, ZEN_TAG);
     }
 
@@ -203,6 +269,18 @@
         return Integer.valueOf(val);
     }
 
+    private static ComponentName safeComponentName(XmlPullParser parser, String att) {
+        final String val = parser.getAttributeValue(null, att);
+        if (TextUtils.isEmpty(val)) return null;
+        return ComponentName.unflattenFromString(val);
+    }
+
+    private static Uri safeUri(XmlPullParser parser, String att) {
+        final String val = parser.getAttributeValue(null, att);
+        if (TextUtils.isEmpty(val)) return null;
+        return Uri.parse(val);
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl
index 7dbf66b..9f9c312 100644
--- a/core/java/android/service/voice/IVoiceInteractionSession.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl
@@ -16,13 +16,14 @@
 
 package android.service.voice;
 
-import android.os.Bundle;
-
-import com.android.internal.app.IVoiceInteractorCallback;
-import com.android.internal.app.IVoiceInteractorRequest;
+import android.content.Intent;
 
 /**
  * @hide
  */
-interface IVoiceInteractionSession {
+oneway interface IVoiceInteractionSession {
+    void taskStarted(in Intent intent, int taskId);
+    void taskFinished(in Intent intent, int taskId);
+    void closeSystemDialogs();
+    void destroy();
 }
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index d005890..e15489b 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -27,6 +27,19 @@
 import android.os.ServiceManager;
 import com.android.internal.app.IVoiceInteractionManagerService;
 
+/**
+ * Top-level service of the current global voice interactor, which is providing
+ * support for hotwording, the back-end of a {@link android.app.VoiceInteractor}, etc.
+ * 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 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} 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 {
     /**
      * The {@link Intent} that must be declared as handled by the service.
@@ -51,11 +64,9 @@
 
     IVoiceInteractionManagerService mSystemService;
 
-    public void startVoiceActivity(Intent intent, Bundle sessionArgs) {
+    public void startSession(Bundle args) {
         try {
-            mSystemService.startVoiceActivity(intent,
-                    intent.resolveType(getContentResolver()),
-                    mInterface, sessionArgs);
+            mSystemService.startSession(mInterface, args);
         } catch (RemoteException e) {
         }
     }
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 963b6b4..a83544d 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -16,7 +16,14 @@
 
 package android.service.voice;
 
+import android.app.Dialog;
+import android.app.Instrumentation;
 import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Region;
+import android.inputmethodservice.SoftInputWindow;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -25,16 +32,53 @@
 import android.os.RemoteException;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import com.android.internal.app.IVoiceInteractionManagerService;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.IVoiceInteractorCallback;
 import com.android.internal.app.IVoiceInteractorRequest;
 import com.android.internal.os.HandlerCaller;
 import com.android.internal.os.SomeArgs;
 
-public abstract class VoiceInteractionSession {
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+public abstract class VoiceInteractionSession implements KeyEvent.Callback {
     static final String TAG = "VoiceInteractionSession";
     static final boolean DEBUG = true;
 
+    final Context mContext;
+    final HandlerCaller mHandlerCaller;
+
+    final KeyEvent.DispatcherState mDispatcherState = new KeyEvent.DispatcherState();
+
+    IVoiceInteractionManagerService mSystemService;
+    IBinder mToken;
+
+    int mTheme = 0;
+    LayoutInflater mInflater;
+    TypedArray mThemeAttrs;
+    View mRootView;
+    FrameLayout mContentFrame;
+    SoftInputWindow mWindow;
+
+    boolean mInitialized;
+    boolean mWindowAdded;
+    boolean mWindowVisible;
+    boolean mWindowWasVisible;
+    boolean mInShowWindow;
+
+    final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>();
+
+    final Insets mTmpInsets = new Insets();
+    final int[] mTmpLocation = new int[2];
+
     final IVoiceInteractor mInteractor = new IVoiceInteractor.Stub() {
         @Override
         public IVoiceInteractorRequest startConfirmation(String callingPackage,
@@ -71,6 +115,27 @@
     };
 
     final IVoiceInteractionSession mSession = new IVoiceInteractionSession.Stub() {
+        @Override
+        public void taskStarted(Intent intent, int taskId) {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_TASK_STARTED,
+                    taskId, intent));
+        }
+
+        @Override
+        public void taskFinished(Intent intent, int taskId) {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_TASK_FINISHED,
+                    taskId, intent));
+        }
+
+        @Override
+        public void closeSystemDialogs() {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_CLOSE_SYSTEM_DIALOGS));
+        }
+
+        @Override
+        public void destroy() {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_DESTROY));
+        }
     };
 
     public static class Request {
@@ -129,38 +194,128 @@
     static final int MSG_SUPPORTS_COMMANDS = 3;
     static final int MSG_CANCEL = 4;
 
-    final Context mContext;
-    final HandlerCaller mHandlerCaller;
-    final HandlerCaller.Callback mHandlerCallerCallback = new HandlerCaller.Callback() {
+    static final int MSG_TASK_STARTED = 100;
+    static final int MSG_TASK_FINISHED = 101;
+    static final int MSG_CLOSE_SYSTEM_DIALOGS = 102;
+    static final int MSG_DESTROY = 103;
+
+    class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback {
         @Override
         public void executeMessage(Message msg) {
-            SomeArgs args = (SomeArgs)msg.obj;
+            SomeArgs args;
             switch (msg.what) {
                 case MSG_START_CONFIRMATION:
+                    args = (SomeArgs)msg.obj;
                     if (DEBUG) Log.d(TAG, "onConfirm: req=" + ((Request) args.arg2).mInterface
                             + " prompt=" + args.arg3 + " extras=" + args.arg4);
                     onConfirm((Caller)args.arg1, (Request)args.arg2, (String)args.arg3,
                             (Bundle)args.arg4);
                     break;
                 case MSG_START_COMMAND:
+                    args = (SomeArgs)msg.obj;
                     if (DEBUG) Log.d(TAG, "onCommand: req=" + ((Request) args.arg2).mInterface
                             + " command=" + args.arg3 + " extras=" + args.arg4);
                     onCommand((Caller) args.arg1, (Request) args.arg2, (String) args.arg3,
                             (Bundle) args.arg4);
                     break;
                 case MSG_SUPPORTS_COMMANDS:
+                    args = (SomeArgs)msg.obj;
                     if (DEBUG) Log.d(TAG, "onGetSupportedCommands: cmds=" + args.arg2);
                     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);
                     break;
+                case MSG_TASK_STARTED:
+                    if (DEBUG) Log.d(TAG, "onTaskStarted: intent=" + msg.obj
+                            + " taskId=" + msg.arg1);
+                    onTaskStarted((Intent) msg.obj, msg.arg1);
+                    break;
+                case MSG_TASK_FINISHED:
+                    if (DEBUG) Log.d(TAG, "onTaskFinished: intent=" + msg.obj
+                            + " taskId=" + msg.arg1);
+                    onTaskFinished((Intent) msg.obj, msg.arg1);
+                    break;
+                case MSG_CLOSE_SYSTEM_DIALOGS:
+                    if (DEBUG) Log.d(TAG, "onCloseSystemDialogs");
+                    onCloseSystemDialogs();
+                    break;
+                case MSG_DESTROY:
+                    if (DEBUG) Log.d(TAG, "doDestroy");
+                    doDestroy();
+                    break;
             }
         }
-    };
 
-    final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>();
+        @Override
+        public void onBackPressed() {
+            VoiceInteractionSession.this.onBackPressed();
+        }
+    }
+
+    final MyCallbacks mCallbacks = new MyCallbacks();
+
+    /**
+     * Information about where interesting parts of the input method UI appear.
+     */
+    public static final class Insets {
+        /**
+         * This is the top part of the UI that is the main content.  It is
+         * used to determine the basic space needed, to resize/pan the
+         * application behind.  It is assumed that this inset does not
+         * change very much, since any change will cause a full resize/pan
+         * of the application behind.  This value is relative to the top edge
+         * of the input method window.
+         */
+        public int contentTopInsets;
+
+        /**
+         * This is the region of the UI that is touchable.  It is used when
+         * {@link #touchableInsets} is set to {@link #TOUCHABLE_INSETS_REGION}.
+         * The region should be specified relative to the origin of the window frame.
+         */
+        public final Region touchableRegion = new Region();
+
+        /**
+         * Option for {@link #touchableInsets}: the entire window frame
+         * can be touched.
+         */
+        public static final int TOUCHABLE_INSETS_FRAME
+                = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
+
+        /**
+         * Option for {@link #touchableInsets}: the area inside of
+         * the content insets can be touched.
+         */
+        public static final int TOUCHABLE_INSETS_CONTENT
+                = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
+
+        /**
+         * Option for {@link #touchableInsets}: the region specified by
+         * {@link #touchableRegion} can be touched.
+         */
+        public static final int TOUCHABLE_INSETS_REGION
+                = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
+
+        /**
+         * Determine which area of the window is touchable by the user.  May
+         * be one of: {@link #TOUCHABLE_INSETS_FRAME},
+         * {@link #TOUCHABLE_INSETS_CONTENT}, or {@link #TOUCHABLE_INSETS_REGION}.
+         */
+        public int touchableInsets;
+    }
+
+    final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer =
+            new ViewTreeObserver.OnComputeInternalInsetsListener() {
+        public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
+            onComputeInsets(mTmpInsets);
+            info.contentInsets.top = info.visibleInsets.top = mTmpInsets.contentTopInsets;
+            info.touchableRegion.set(mTmpInsets.touchableRegion);
+            info.setTouchableInsets(mTmpInsets.touchableInsets);
+        }
+    };
 
     public VoiceInteractionSession(Context context) {
         this(context, new Handler());
@@ -169,7 +324,7 @@
     public VoiceInteractionSession(Context context, Handler handler) {
         mContext = context;
         mHandlerCaller = new HandlerCaller(context, handler.getLooper(),
-                mHandlerCallerCallback, true);
+                mCallbacks, true);
     }
 
     Request findRequest(IVoiceInteractorCallback callback, boolean newRequest) {
@@ -188,6 +343,192 @@
         }
     }
 
+    void doCreate(IVoiceInteractionManagerService service, IBinder token, Bundle args) {
+        mSystemService = service;
+        mToken = token;
+        onCreate(args);
+    }
+
+    void doDestroy() {
+        if (mInitialized) {
+            mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
+                    mInsetsComputer);
+            if (mWindowAdded) {
+                mWindow.dismiss();
+                mWindowAdded = false;
+            }
+            mInitialized = false;
+        }
+    }
+
+    void initViews() {
+        mInitialized = true;
+
+        mThemeAttrs = mContext.obtainStyledAttributes(android.R.styleable.VoiceInteractionSession);
+        mRootView = mInflater.inflate(
+                com.android.internal.R.layout.voice_interaction_session, null);
+        mRootView.setSystemUiVisibility(
+                View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+        mWindow.setContentView(mRootView);
+        mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
+
+        mContentFrame = (FrameLayout)mRootView.findViewById(android.R.id.content);
+    }
+
+    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;
+        }
+
+        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;
+        }
+    }
+
+    public void hideWindow() {
+        if (mWindowVisible) {
+            mWindow.hide();
+            mWindowVisible = false;
+        }
+    }
+
+    /**
+     * 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.
+     */
+    public void setTheme(int theme) {
+        if (mWindow != null) {
+            throw new IllegalStateException("Must be called before onCreate()");
+        }
+        mTheme = theme;
+    }
+
+    public void startVoiceActivity(Intent intent) {
+        if (mToken == null) {
+            throw new IllegalStateException("Can't call before onCreate()");
+        }
+        try {
+            int res = mSystemService.startVoiceActivity(mToken, intent,
+                    intent.resolveType(mContext.getContentResolver()));
+            Instrumentation.checkStartActivityResult(res, intent);
+        } catch (RemoteException e) {
+        }
+    }
+
+    public LayoutInflater getLayoutInflater() {
+        return mInflater;
+    }
+
+    public Dialog getWindow() {
+        return mWindow;
+    }
+
+    public void finish() {
+        if (mToken == null) {
+            throw new IllegalStateException("Can't call before onCreate()");
+        }
+        hideWindow();
+        try {
+            mSystemService.finish(mToken);
+        } catch (RemoteException e) {
+        }
+    }
+
+    public void onCreate(Bundle args) {
+        mTheme = mTheme != 0 ? mTheme
+                : com.android.internal.R.style.Theme_DeviceDefault_VoiceInteractionSession;
+        mInflater = (LayoutInflater)mContext.getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+        mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme,
+                mCallbacks, this, mDispatcherState, true);
+        mWindow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
+        initViews();
+        mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
+        mWindow.setToken(mToken);
+    }
+
+    public void onDestroy() {
+    }
+
+    public View onCreateContentView() {
+        return null;
+    }
+
+    public void setContentView(View view) {
+        mContentFrame.removeAllViews();
+        mContentFrame.addView(view, new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT));
+
+    }
+
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        return false;
+    }
+
+    public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+        return false;
+    }
+
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        return false;
+    }
+
+    public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
+        return false;
+    }
+
+    public void onBackPressed() {
+        finish();
+    }
+
+    public void onCloseSystemDialogs() {
+        finish();
+    }
+
+    /**
+     * 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}.
+     *
+     * @param outInsets Fill in with the current UI insets.
+     */
+    public void onComputeInsets(Insets outInsets) {
+        int[] loc = mTmpLocation;
+        View decor = getWindow().getWindow().getDecorView();
+        decor.getLocationInWindow(loc);
+        outInsets.contentTopInsets = loc[1];
+        outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_FRAME;
+        outInsets.touchableRegion.setEmpty();
+    }
+
+    public void onTaskStarted(Intent intent, int taskId) {
+    }
+
+    public void onTaskFinished(Intent intent, int taskId) {
+        finish();
+    }
+
     public abstract boolean[] onGetSupportedCommands(Caller caller, String[] commands);
     public abstract void onConfirm(Caller caller, Request request, String prompt, Bundle extras);
     public abstract void onCommand(Caller caller, Request request, String command, Bundle extras);
diff --git a/core/java/android/service/voice/VoiceInteractionSessionService.java b/core/java/android/service/voice/VoiceInteractionSessionService.java
index 40e5bba..e793849 100644
--- a/core/java/android/service/voice/VoiceInteractionSessionService.java
+++ b/core/java/android/service/voice/VoiceInteractionSessionService.java
@@ -29,11 +29,15 @@
 import com.android.internal.os.HandlerCaller;
 import com.android.internal.os.SomeArgs;
 
+/**
+ * An active voice interaction session, initiated by a {@link VoiceInteractionService}.
+ */
 public abstract class VoiceInteractionSessionService extends Service {
 
     static final int MSG_NEW_SESSION = 1;
 
     IVoiceInteractionManagerService mSystemService;
+    VoiceInteractionSession mSession;
 
     IVoiceInteractionSessionService mInterface = new IVoiceInteractionSessionService.Stub() {
         public void newSession(IBinder token, Bundle args) {
@@ -73,9 +77,14 @@
     }
 
     void doNewSession(IBinder token, Bundle args) {
-        VoiceInteractionSession session = onNewSession(args);
+        if (mSession != null) {
+            mSession.doDestroy();
+            mSession = null;
+        }
+        mSession = onNewSession(args);
         try {
-            mSystemService.deliverNewSession(token, session.mSession, session.mInteractor);
+            mSystemService.deliverNewSession(token, mSession.mSession, mSession.mInteractor);
+            mSession.doCreate(mSystemService, token, args);
         } catch (RemoteException e) {
         }
     }
diff --git a/core/java/android/speech/tts/BlockingAudioTrack.java b/core/java/android/speech/tts/BlockingAudioTrack.java
index 186cb49..92bb0ac 100644
--- a/core/java/android/speech/tts/BlockingAudioTrack.java
+++ b/core/java/android/speech/tts/BlockingAudioTrack.java
@@ -83,7 +83,7 @@
         mVolume = volume;
         mPan = pan;
 
-        mBytesPerFrame = getBytesPerFrame(mAudioFormat) * mChannelCount;
+        mBytesPerFrame = AudioFormat.getBytesPerSample(mAudioFormat) * mChannelCount;
         mIsShortUtterance = false;
         mAudioBufferSize = 0;
         mBytesWritten = 0;
@@ -229,17 +229,6 @@
         return audioTrack;
     }
 
-    private static int getBytesPerFrame(int audioFormat) {
-        if (audioFormat == AudioFormat.ENCODING_PCM_8BIT) {
-            return 1;
-        } else if (audioFormat == AudioFormat.ENCODING_PCM_16BIT) {
-            return 2;
-        }
-
-        return -1;
-    }
-
-
     private void blockUntilDone(AudioTrack audioTrack) {
         if (mBytesWritten <= 0) {
             return;
diff --git a/core/java/android/speech/tts/FileSynthesisCallback.java b/core/java/android/speech/tts/FileSynthesisCallback.java
index 717aeb6..d84f7f0 100644
--- a/core/java/android/speech/tts/FileSynthesisCallback.java
+++ b/core/java/android/speech/tts/FileSynthesisCallback.java
@@ -278,8 +278,7 @@
 
     private ByteBuffer makeWavHeader(int sampleRateInHz, int audioFormat, int channelCount,
             int dataLength) {
-        // TODO: is AudioFormat.ENCODING_DEFAULT always the same as ENCODING_PCM_16BIT?
-        int sampleSizeInBytes = (audioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
+        int sampleSizeInBytes = AudioFormat.getBytesPerSample(audioFormat);
         int byteRate = sampleRateInHz * sampleSizeInBytes * channelCount;
         short blockAlign = (short) (sampleSizeInBytes * channelCount);
         short bitsPerSample = (short) (sampleSizeInBytes * 8);
diff --git a/core/java/android/speech/tts/TtsEngines.java b/core/java/android/speech/tts/TtsEngines.java
index 4f996cd..9b929a3 100644
--- a/core/java/android/speech/tts/TtsEngines.java
+++ b/core/java/android/speech/tts/TtsEngines.java
@@ -307,6 +307,24 @@
     }
 
     /**
+     * True if a given TTS engine uses the default phone locale as a default locale. Attempts to
+     * read the value from {@link Settings.Secure#TTS_DEFAULT_LOCALE}, failing which the
+     * old style value from {@link Settings.Secure#TTS_DEFAULT_LANG} is read. If
+     * both these values are empty, this methods returns true.
+     *
+     * @param engineName the engine to return the locale for.
+     */
+    public boolean isLocaleSetToDefaultForEngine(String engineName) {
+        return (TextUtils.isEmpty(parseEnginePrefFromList(
+                    getString(mContext.getContentResolver(), Settings.Secure.TTS_DEFAULT_LOCALE),
+                    engineName)) &&
+                    TextUtils.isEmpty(
+                        Settings.Secure.getString(mContext.getContentResolver(),
+                        Settings.Secure.TTS_DEFAULT_LANG)));
+    }
+
+
+    /**
      * Parses a locale preference value delimited by {@link #LOCALE_DELIMITER}.
      * Varies from {@link String#split} in that it will always return an array
      * of length 3 with non null values.
diff --git a/core/java/android/transition/CircularPropagation.java b/core/java/android/transition/CircularPropagation.java
index 18a3d22..51beb51 100644
--- a/core/java/android/transition/CircularPropagation.java
+++ b/core/java/android/transition/CircularPropagation.java
@@ -34,7 +34,7 @@
 public class CircularPropagation extends VisibilityPropagation {
     private static final String TAG = "CircularPropagation";
 
-    private float mPropagationSpeed = 4.0f;
+    private float mPropagationSpeed = 3.0f;
 
     /**
      * Sets the speed at which transition propagation happens, relative to the duration of the
@@ -91,8 +91,12 @@
         float maxDistance = distance(0, 0, sceneRoot.getWidth(), sceneRoot.getHeight());
         float distanceFraction = distance/maxDistance;
 
-        return Math.round(transition.getDuration() * directionMultiplier / mPropagationSpeed
-                * distanceFraction);
+        long duration = transition.getDuration();
+        if (duration < 0) {
+            duration = 300;
+        }
+
+        return Math.round(duration * directionMultiplier / mPropagationSpeed * distanceFraction);
     }
 
     private static float distance(float x1, float y1, float x2, float y2) {
diff --git a/core/java/android/transition/MoveImage.java b/core/java/android/transition/MoveImage.java
index e4c3939..6f1b6f7 100644
--- a/core/java/android/transition/MoveImage.java
+++ b/core/java/android/transition/MoveImage.java
@@ -64,7 +64,13 @@
         if (!(view instanceof ImageView) || view.getVisibility() != View.VISIBLE) {
             return;
         }
+        ImageView imageView = (ImageView) view;
+        Drawable drawable = imageView.getDrawable();
+        if (drawable == null) {
+            return;
+        }
         Map<String, Object> values = transitionValues.values;
+        values.put(PROPNAME_DRAWABLE, drawable);
 
         ViewGroup parent = (ViewGroup) view.getParent();
         parent.getLocationInWindow(mTempLoc);
@@ -79,11 +85,9 @@
 
         Rect bounds = new Rect(left, top, right, bottom);
         values.put(PROPNAME_BOUNDS, bounds);
-        ImageView imageView = (ImageView) view;
         Matrix matrix = getMatrix(imageView);
         values.put(PROPNAME_MATRIX, matrix);
         values.put(PROPNAME_CLIP, findClip(imageView));
-        values.put(PROPNAME_DRAWABLE, imageView.getDrawable());
     }
 
     @Override
@@ -125,7 +129,7 @@
         Matrix startMatrix = (Matrix) startValues.values.get(PROPNAME_MATRIX);
         Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_MATRIX);
 
-        if (!startMatrix.equals(endMatrix)) {
+        if (startMatrix != null && !startMatrix.equals(endMatrix)) {
             changes.add(PropertyValuesHolder.ofObject(MatrixClippedDrawable.MATRIX_PROPERTY,
                     new MatrixEvaluator(), startMatrix, endMatrix));
         }
@@ -230,7 +234,9 @@
 
     private static void expandClip(Rect bounds, Matrix matrix, Rect clip, Rect otherClip) {
         RectF boundsF = new RectF(bounds);
-        matrix.mapRect(boundsF);
+        if (matrix != null) {
+            matrix.mapRect(boundsF);
+        }
         clip.left = expandMinDimension(boundsF.left, clip.left, otherClip.left);
         clip.top = expandMinDimension(boundsF.top, clip.top, otherClip.top);
         clip.right = expandMaxDimension(boundsF.right, clip.right, otherClip.right);
@@ -256,10 +262,20 @@
         int drawableWidth = drawable.getIntrinsicWidth();
         int drawableHeight = drawable.getIntrinsicHeight();
         ImageView.ScaleType scaleType = imageView.getScaleType();
-        if (drawableWidth <= 0 || drawableHeight <= 0 || scaleType == ImageView.ScaleType.FIT_XY) {
-            return null;
+        Matrix matrix;
+        if (drawableWidth <= 0 || drawableHeight <= 0) {
+            matrix = null;
+        } else if (scaleType == ImageView.ScaleType.FIT_XY) {
+            matrix = new Matrix();
+            float scaleX = imageView.getWidth();
+            scaleX /= drawableWidth;
+            float scaleY = imageView.getHeight();
+            scaleY /= drawableHeight;
+            matrix.setScale(scaleX, scaleY);
+        } else {
+            matrix = new Matrix(imageView.getImageMatrix());
         }
-        return new Matrix(imageView.getImageMatrix());
+        return matrix;
     }
 
     private Rect findClip(ImageView imageView) {
diff --git a/core/java/android/transition/SidePropagation.java b/core/java/android/transition/SidePropagation.java
index c331945..5d38ac8 100644
--- a/core/java/android/transition/SidePropagation.java
+++ b/core/java/android/transition/SidePropagation.java
@@ -52,7 +52,7 @@
      */
     public static final int BOTTOM = Slide.BOTTOM;
 
-    private float mPropagationSpeed = 4.0f;
+    private float mPropagationSpeed = 3.0f;
     private int mSide = BOTTOM;
 
     /**
@@ -129,8 +129,12 @@
         float maxDistance = getMaxDistance(sceneRoot);
         float distanceFraction = distance/maxDistance;
 
-        return Math.round(transition.getDuration() * directionMultiplier / mPropagationSpeed
-                * distanceFraction);
+        long duration = transition.getDuration();
+        if (duration < 0) {
+            duration = 300;
+        }
+
+        return Math.round(duration * directionMultiplier / mPropagationSpeed * distanceFraction);
     }
 
     private int distance(int viewX, int viewY, int epicenterX, int epicenterY,
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 2549fde..5a432dc 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -24,6 +24,7 @@
 import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
 import android.util.SparseLongArray;
 import android.view.SurfaceView;
 import android.view.TextureView;
@@ -89,7 +90,8 @@
  * out-in behavior. Finally, note the use of the <code>targets</code> sub-tag, which
  * takes a set of {@link android.R.styleable#TransitionTarget target} tags, each
  * of which lists a specific <code>targetId</code>, <code>targetClass</code>,
- * <code>excludeId</code>, or <code>excludeClass</code>, which this transition acts upon.
+ * <code>targetViewName</code>, <code>excludeId</code>, <code>excludeClass</code>, or
+ * <code>excludeViewName</code>, which this transition acts upon.
  * Use of targets is optional, but can be used to either limit the time spent checking
  * attributes on unchanging views, or limiting the types of animations run on specific views.
  * In this case, we know that only the <code>grayscaleContainer</code> will be
@@ -113,10 +115,12 @@
     TimeInterpolator mInterpolator = null;
     ArrayList<Integer> mTargetIds = new ArrayList<Integer>();
     ArrayList<View> mTargets = new ArrayList<View>();
+    ArrayList<String> mTargetNames = null;
+    ArrayList<Class> mTargetTypes = null;
     ArrayList<Integer> mTargetIdExcludes = null;
     ArrayList<View> mTargetExcludes = null;
     ArrayList<Class> mTargetTypeExcludes = null;
-    ArrayList<Class> mTargetTypes = null;
+    ArrayList<String> mTargetNameExcludes = null;
     ArrayList<Integer> mTargetIdChildExcludes = null;
     ArrayList<View> mTargetChildExcludes = null;
     ArrayList<Class> mTargetTypeChildExcludes = null;
@@ -334,6 +338,133 @@
     }
 
     /**
+     * Match start/end values by View instance. Adds matched values to startValuesList
+     * and endValuesList and removes them from unmatchedStart and unmatchedEnd.
+     */
+    private void matchInstances(ArrayList<TransitionValues> startValuesList,
+            ArrayList<TransitionValues> endValuesList,
+            ArrayMap<View, TransitionValues> unmatchedStart,
+            ArrayMap<View, TransitionValues> unmatchedEnd) {
+        for (int i = unmatchedStart.size() - 1; i >= 0; i--) {
+            View view = unmatchedStart.keyAt(i);
+            TransitionValues end = unmatchedEnd.remove(view);
+            if (end != null) {
+                TransitionValues start = unmatchedStart.removeAt(i);
+                startValuesList.add(start);
+                endValuesList.add(end);
+            }
+        }
+    }
+
+    /**
+     * Match start/end values by Adapter item ID. Adds matched values to startValuesList
+     * and endValuesList and removes them from unmatchedStart and unmatchedEnd, using
+     * startItemIds and endItemIds as a guide for which Views have unique item IDs.
+     */
+    private void matchItemIds(ArrayList<TransitionValues> startValuesList,
+            ArrayList<TransitionValues> endValuesList,
+            ArrayMap<View, TransitionValues> unmatchedStart,
+            ArrayMap<View, TransitionValues> unmatchedEnd,
+            LongSparseArray<View> startItemIds, LongSparseArray<View> endItemIds) {
+        int numStartIds = startItemIds.size();
+        for (int i = 0; i < numStartIds; i++) {
+            View startView = startItemIds.valueAt(i);
+            if (startView != null) {
+                View endView = endItemIds.get(startItemIds.keyAt(i));
+                if (endView != null) {
+                    TransitionValues startValues = unmatchedStart.get(startView);
+                    TransitionValues endValues = unmatchedEnd.get(endView);
+                    if (startValues != null && endValues != null) {
+                        startValuesList.add(startValues);
+                        endValuesList.add(endValues);
+                        unmatchedStart.remove(startView);
+                        unmatchedEnd.remove(endView);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Match start/end values by Adapter view ID. Adds matched values to startValuesList
+     * and endValuesList and removes them from unmatchedStart and unmatchedEnd, using
+     * startIds and endIds as a guide for which Views have unique IDs.
+     */
+    private void matchIds(ArrayList<TransitionValues> startValuesList,
+            ArrayList<TransitionValues> endValuesList,
+            ArrayMap<View, TransitionValues> unmatchedStart,
+            ArrayMap<View, TransitionValues> unmatchedEnd,
+            SparseArray<View> startIds, SparseArray<View> endIds) {
+        int numStartIds = startIds.size();
+        for (int i = 0; i < numStartIds; i++) {
+            View startView = startIds.valueAt(i);
+            if (startView != null && isValidTarget(startView)) {
+                View endView = endIds.get(startIds.keyAt(i));
+                if (endView != null && isValidTarget(endView)) {
+                    TransitionValues startValues = unmatchedStart.get(startView);
+                    TransitionValues endValues = unmatchedEnd.get(endView);
+                    if (startValues != null && endValues != null) {
+                        startValuesList.add(startValues);
+                        endValuesList.add(endValues);
+                        unmatchedStart.remove(startView);
+                        unmatchedEnd.remove(endView);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Match start/end values by Adapter viewName. Adds matched values to startValuesList
+     * and endValuesList and removes them from unmatchedStart and unmatchedEnd, using
+     * startNames and endNames as a guide for which Views have unique viewNames.
+     */
+    private void matchNames(ArrayList<TransitionValues> startValuesList,
+            ArrayList<TransitionValues> endValuesList,
+            ArrayMap<View, TransitionValues> unmatchedStart,
+            ArrayMap<View, TransitionValues> unmatchedEnd,
+            ArrayMap<String, View> startNames, ArrayMap<String, View> endNames) {
+        int numStartNames = startNames.size();
+        for (int i = 0; i < numStartNames; i++) {
+            View startView = startNames.valueAt(i);
+            if (startView != null && isValidTarget(startView)) {
+                View endView = endNames.get(startNames.keyAt(i));
+                if (endView != null && isValidTarget(endView)) {
+                    TransitionValues startValues = unmatchedStart.get(startView);
+                    TransitionValues endValues = unmatchedEnd.get(endView);
+                    if (startValues != null && endValues != null) {
+                        startValuesList.add(startValues);
+                        endValuesList.add(endValues);
+                        unmatchedStart.remove(startView);
+                        unmatchedEnd.remove(endView);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Adds all values from unmatchedStart and unmatchedEnd to startValuesList and endValuesList,
+     * assuming that there is no match between values in the list.
+     */
+    private void addUnmatched(ArrayList<TransitionValues> startValuesList,
+            ArrayList<TransitionValues> endValuesList,
+            ArrayMap<View, TransitionValues> unmatchedStart,
+            ArrayMap<View, TransitionValues> unmatchedEnd) {
+        // Views that only exist in the start Scene
+        for (int i = 0; i < unmatchedStart.size(); i++) {
+            startValuesList.add(unmatchedStart.valueAt(i));
+            endValuesList.add(null);
+        }
+
+        // Views that only exist in the end Scene
+        for (int i = 0; i < unmatchedEnd.size(); i++) {
+            endValuesList.add(unmatchedEnd.valueAt(i));
+            startValuesList.add(null);
+        }
+    }
+
+    /**
      * This method, essentially a wrapper around all calls to createAnimator for all
      * possible target views, is called with the entire set of start/end
      * values. The implementation in Transition iterates through these lists
@@ -349,110 +480,22 @@
         if (DBG) {
             Log.d(LOG_TAG, "createAnimators() for " + this);
         }
-        ArrayMap<View, TransitionValues> endCopy =
+        ArrayMap<View, TransitionValues> unmatchedStart =
+                new ArrayMap<View, TransitionValues>(startValues.viewValues);
+        ArrayMap<View, TransitionValues> unmatchedEnd =
                 new ArrayMap<View, TransitionValues>(endValues.viewValues);
-        SparseArray<TransitionValues> endIdCopy =
-                new SparseArray<TransitionValues>(endValues.idValues.size());
-        for (int i = 0; i < endValues.idValues.size(); ++i) {
-            int id = endValues.idValues.keyAt(i);
-            endIdCopy.put(id, endValues.idValues.valueAt(i));
-        }
-        LongSparseArray<TransitionValues> endItemIdCopy =
-                new LongSparseArray<TransitionValues>(endValues.itemIdValues.size());
-        for (int i = 0; i < endValues.itemIdValues.size(); ++i) {
-            long id = endValues.itemIdValues.keyAt(i);
-            endItemIdCopy.put(id, endValues.itemIdValues.valueAt(i));
-        }
-        // Walk through the start values, playing everything we find
-        // Remove from the end set as we go
+
         ArrayList<TransitionValues> startValuesList = new ArrayList<TransitionValues>();
         ArrayList<TransitionValues> endValuesList = new ArrayList<TransitionValues>();
-        for (View view : startValues.viewValues.keySet()) {
-            TransitionValues start = null;
-            TransitionValues end = null;
-            boolean isInListView = false;
-            if (view.getParent() instanceof ListView) {
-                isInListView = true;
-            }
-            if (!isInListView) {
-                int id = view.getId();
-                start = startValues.viewValues.get(view) != null ?
-                        startValues.viewValues.get(view) : startValues.idValues.get(id);
-                if (endValues.viewValues.get(view) != null) {
-                    end = endValues.viewValues.get(view);
-                    endCopy.remove(view);
-                } else if (id != View.NO_ID) {
-                    end = endValues.idValues.get(id);
-                    View removeView = null;
-                    for (View viewToRemove : endCopy.keySet()) {
-                        if (viewToRemove.getId() == id) {
-                            removeView = viewToRemove;
-                        }
-                    }
-                    if (removeView != null) {
-                        endCopy.remove(removeView);
-                    }
-                }
-                endIdCopy.remove(id);
-                if (isValidTarget(view, id)) {
-                    startValuesList.add(start);
-                    endValuesList.add(end);
-                }
-            } else {
-                ListView parent = (ListView) view.getParent();
-                if (parent.getAdapter().hasStableIds()) {
-                    int position = parent.getPositionForView(view);
-                    long itemId = parent.getItemIdAtPosition(position);
-                    start = startValues.itemIdValues.get(itemId);
-                    endItemIdCopy.remove(itemId);
-                    // TODO: deal with targetIDs for itemIDs for ListView items
-                    startValuesList.add(start);
-                    endValuesList.add(end);
-                }
-            }
-        }
-        int startItemIdCopySize = startValues.itemIdValues.size();
-        for (int i = 0; i < startItemIdCopySize; ++i) {
-            long id = startValues.itemIdValues.keyAt(i);
-            if (isValidTarget(null, id)) {
-                TransitionValues start = startValues.itemIdValues.get(id);
-                TransitionValues end = endValues.itemIdValues.get(id);
-                endItemIdCopy.remove(id);
-                startValuesList.add(start);
-                endValuesList.add(end);
-            }
-        }
-        // Now walk through the remains of the end set
-        for (View view : endCopy.keySet()) {
-            int id = view.getId();
-            if (isValidTarget(view, id)) {
-                TransitionValues start = startValues.viewValues.get(view) != null ?
-                        startValues.viewValues.get(view) : startValues.idValues.get(id);
-                TransitionValues end = endCopy.get(view);
-                endIdCopy.remove(id);
-                startValuesList.add(start);
-                endValuesList.add(end);
-            }
-        }
-        int endIdCopySize = endIdCopy.size();
-        for (int i = 0; i < endIdCopySize; ++i) {
-            int id = endIdCopy.keyAt(i);
-            if (isValidTarget(null, id)) {
-                TransitionValues start = startValues.idValues.get(id);
-                TransitionValues end = endIdCopy.get(id);
-                startValuesList.add(start);
-                endValuesList.add(end);
-            }
-        }
-        int endItemIdCopySize = endItemIdCopy.size();
-        for (int i = 0; i < endItemIdCopySize; ++i) {
-            long id = endItemIdCopy.keyAt(i);
-            // TODO: Deal with targetIDs and itemIDs
-            TransitionValues start = startValues.itemIdValues.get(id);
-            TransitionValues end = endItemIdCopy.get(id);
-            startValuesList.add(start);
-            endValuesList.add(end);
-        }
+        matchNames(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
+                startValues.nameValues, endValues.nameValues);
+        matchInstances(startValuesList, endValuesList, unmatchedStart, unmatchedEnd);
+        matchIds(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
+                startValues.idValues, endValues.idValues);
+        matchItemIds(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
+                startValues.itemIdValues, endValues.itemIdValues);
+        addUnmatched(startValuesList, endValuesList, unmatchedStart, unmatchedEnd);
+
         ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
         long minStartDelay = Long.MAX_VALUE;
         int minAnimator = mAnimators.size();
@@ -554,7 +597,8 @@
      * is not checked (this is in the case of ListView items, where the
      * views are ignored and only the ids are used).
      */
-    boolean isValidTarget(View target, long targetId) {
+    boolean isValidTarget(View target) {
+        int targetId = target.getId();
         if (mTargetIdExcludes != null && mTargetIdExcludes.contains(targetId)) {
             return false;
         }
@@ -570,10 +614,20 @@
                 }
             }
         }
-        if (mTargetIds.size() == 0 && mTargets.size() == 0 && mTargetTypes == null) {
+        if (mTargetNameExcludes != null && target != null && target.getViewName() != null) {
+            if (mTargetNameExcludes.contains(target.getViewName())) {
+                return false;
+            }
+        }
+        if (mTargetIds.size() == 0 && mTargets.size() == 0 &&
+                (mTargetTypes == null || mTargetTypes.isEmpty() &&
+                (mTargetNames == null || mTargetNames.isEmpty()))) {
             return true;
         }
-        if (mTargetIds.contains((int) targetId) || mTargets.contains(target)) {
+        if (mTargetIds.contains(targetId) || mTargets.contains(target)) {
+            return true;
+        }
+        if (mTargetNames != null && mTargetNames.contains(target.getViewName())) {
             return true;
         }
         if (mTargetTypes != null) {
@@ -724,6 +778,33 @@
     }
 
     /**
+     * Adds the viewName of a target view that this Transition is interested in
+     * animating. By default, there are no targetNames, and a Transition will
+     * listen for changes on every view in the hierarchy below the sceneRoot
+     * of the Scene being transitioned into. Setting targetNames constrains
+     * the Transition to only listen for, and act on, views with these viewNames.
+     * Views with different viewNames, or no viewName whatsoever, will be ignored.
+     *
+     * <p>Note that viewNames should be unique within the view hierarchy.</p>
+     *
+     * @see android.view.View#getViewName()
+     * @param targetName The viewName of a target view, must be non-null.
+     * @return The Transition to which the target viewName is added.
+     * Returning the same object makes it easier to chain calls during
+     * construction, such as
+     * <code>transitionSet.addTransitions(new Fade()).addTarget(someName);</code>
+     */
+    public Transition addTarget(String targetName) {
+        if (targetName != null) {
+            if (mTargetNames != null) {
+                mTargetNames = new ArrayList<String>();
+            }
+            mTargetNames.add(targetName);
+        }
+        return this;
+    }
+
+    /**
      * Adds the Class of a target view that this Transition is interested in
      * animating. By default, there are no targetTypes, and a Transition will
      * listen for changes on every view in the hierarchy below the sceneRoot
@@ -746,10 +827,12 @@
      * <code>transitionSet.addTransitions(new Fade()).addTarget(ImageView.class);</code>
      */
     public Transition addTarget(Class targetType) {
-        if (mTargetTypes == null) {
-            mTargetTypes = new ArrayList<Class>();
+        if (targetType != null) {
+            if (mTargetTypes == null) {
+                mTargetTypes = new ArrayList<Class>();
+            }
+            mTargetTypes.add(targetType);
         }
-        mTargetTypes.add(targetType);
         return this;
     }
 
@@ -771,6 +854,23 @@
     }
 
     /**
+     * Removes the given targetName from the list of viewNames that this Transition
+     * is interested in animating.
+     *
+     * @param targetName The viewName of a target view, must not be null.
+     * @return The Transition from which the targetName is removed.
+     * Returning the same object makes it easier to chain calls during
+     * construction, such as
+     * <code>transitionSet.addTransitions(new Fade()).removeTargetName(someName);</code>
+     */
+    public Transition removeTarget(String targetName) {
+        if (targetName != null && mTargetNames != null) {
+            mTargetNames.remove(targetName);
+        }
+        return this;
+    }
+
+    /**
      * Whether to add the given id to the list of target ids to exclude from this
      * transition. The <code>exclude</code> parameter specifies whether the target
      * should be added to or removed from the excluded list.
@@ -792,7 +892,35 @@
      * @return This transition object.
      */
     public Transition excludeTarget(int targetId, boolean exclude) {
-        mTargetIdExcludes = excludeId(mTargetIdExcludes, targetId, exclude);
+        if (targetId >= 0) {
+            mTargetIdExcludes = excludeObject(mTargetIdExcludes, targetId, exclude);
+        }
+        return this;
+    }
+
+    /**
+     * Whether to add the given viewName to the list of target viewNames to exclude from this
+     * transition. The <code>exclude</code> parameter specifies whether the target
+     * should be added to or removed from the excluded list.
+     *
+     * <p>Excluding targets is a general mechanism for allowing transitions to run on
+     * a view hierarchy while skipping target views that should not be part of
+     * the transition. For example, you may want to avoid animating children
+     * of a specific ListView or Spinner. Views can be excluded by their
+     * id, their instance reference, their viewName, or by the Class of that view
+     * (eg, {@link Spinner}).</p>
+     *
+     * @see #excludeTarget(View, boolean)
+     * @see #excludeTarget(int, boolean)
+     * @see #excludeTarget(Class, boolean)
+     *
+     * @param targetViewName The name of a target to ignore when running this transition.
+     * @param exclude Whether to add the target to or remove the target from the
+     * current list of excluded targets.
+     * @return This transition object.
+     */
+    public Transition excludeTarget(String targetViewName, boolean exclude) {
+        mTargetNameExcludes = excludeObject(mTargetNameExcludes, targetViewName, exclude);
         return this;
     }
 
@@ -822,23 +950,10 @@
      * @return This transition object.
      */
     public Transition excludeChildren(int targetId, boolean exclude) {
-        mTargetIdChildExcludes = excludeId(mTargetIdChildExcludes, targetId, exclude);
-        return this;
-    }
-
-    /**
-     * Utility method to manage the boilerplate code that is the same whether we
-     * are excluding targets or their children.
-     */
-    private ArrayList<Integer> excludeId(ArrayList<Integer> list, int targetId, boolean exclude) {
-        if (targetId > 0) {
-            if (exclude) {
-                list = ArrayListManager.add(list, targetId);
-            } else {
-                list = ArrayListManager.remove(list, targetId);
-            }
+        if (targetId >= 0) {
+            mTargetIdChildExcludes = excludeObject(mTargetIdChildExcludes, targetId, exclude);
         }
-        return list;
+        return this;
     }
 
     /**
@@ -863,7 +978,7 @@
      * @return This transition object.
      */
     public Transition excludeTarget(View target, boolean exclude) {
-        mTargetExcludes = excludeView(mTargetExcludes, target, exclude);
+        mTargetExcludes = excludeObject(mTargetExcludes, target, exclude);
         return this;
     }
 
@@ -889,7 +1004,7 @@
      * @return This transition object.
      */
     public Transition excludeChildren(View target, boolean exclude) {
-        mTargetChildExcludes = excludeView(mTargetChildExcludes, target, exclude);
+        mTargetChildExcludes = excludeObject(mTargetChildExcludes, target, exclude);
         return this;
     }
 
@@ -897,7 +1012,7 @@
      * Utility method to manage the boilerplate code that is the same whether we
      * are excluding targets or their children.
      */
-    private ArrayList<View> excludeView(ArrayList<View> list, View target, boolean exclude) {
+    private static <T> ArrayList<T> excludeObject(ArrayList<T> list, T target, boolean exclude) {
         if (target != null) {
             if (exclude) {
                 list = ArrayListManager.add(list, target);
@@ -930,7 +1045,7 @@
      * @return This transition object.
      */
     public Transition excludeTarget(Class type, boolean exclude) {
-        mTargetTypeExcludes = excludeType(mTargetTypeExcludes, type, exclude);
+        mTargetTypeExcludes = excludeObject(mTargetTypeExcludes, type, exclude);
         return this;
     }
 
@@ -957,26 +1072,11 @@
      * @return This transition object.
      */
     public Transition excludeChildren(Class type, boolean exclude) {
-        mTargetTypeChildExcludes = excludeType(mTargetTypeChildExcludes, type, exclude);
+        mTargetTypeChildExcludes = excludeObject(mTargetTypeChildExcludes, type, exclude);
         return this;
     }
 
     /**
-     * Utility method to manage the boilerplate code that is the same whether we
-     * are excluding targets or their children.
-     */
-    private ArrayList<Class> excludeType(ArrayList<Class> list, Class type, boolean exclude) {
-        if (type != null) {
-            if (exclude) {
-                list = ArrayListManager.add(list, type);
-            } else {
-                list = ArrayListManager.remove(list, type);
-            }
-        }
-        return list;
-    }
-
-    /**
      * Sets the target view instances that this Transition is interested in
      * animating. By default, there are no targets, and a Transition will
      * listen for changes on every view in the hierarchy below the sceneRoot
@@ -1025,9 +1125,27 @@
     }
 
     /**
-     * Returns the array of target IDs that this transition limits itself to
-     * tracking and animating. If the array is null for both this method and
-     * {@link #getTargets()}, then this transition is
+     * Removes the given target from the list of targets that this Transition
+     * is interested in animating.
+     *
+     * @param target The type of the target view, must be non-null.
+     * @return Transition The Transition from which the target is removed.
+     * Returning the same object makes it easier to chain calls during
+     * construction, such as
+     * <code>transitionSet.addTransitions(new Fade()).removeTarget(someType);</code>
+     */
+    public Transition removeTarget(Class target) {
+        if (target != null) {
+            mTargetTypes.remove(target);
+        }
+        return this;
+    }
+
+    /**
+     * Returns the list of target IDs that this transition limits itself to
+     * tracking and animating. If the list is null or empty for
+     * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetViewNames()}, and
+     * {@link #getTargetTypes()} then this transition is
      * not limited to specific views, and will handle changes to any views
      * in the hierarchy of a scene change.
      *
@@ -1038,9 +1156,10 @@
     }
 
     /**
-     * Returns the array of target views that this transition limits itself to
-     * tracking and animating. If the array is null for both this method and
-     * {@link #getTargetIds()}, then this transition is
+     * Returns the list of target views that this transition limits itself to
+     * tracking and animating. If the list is null or empty for
+     * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetViewNames()}, and
+     * {@link #getTargetTypes()} then this transition is
      * not limited to specific views, and will handle changes to any views
      * in the hierarchy of a scene change.
      *
@@ -1051,6 +1170,34 @@
     }
 
     /**
+     * Returns the list of target viewNames that this transition limits itself to
+     * tracking and animating. If the list is null or empty for
+     * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetViewNames()}, and
+     * {@link #getTargetTypes()} then this transition is
+     * not limited to specific views, and will handle changes to any views
+     * in the hierarchy of a scene change.
+     *
+     * @return the list of target viewNames
+     */
+    public List<String> getTargetViewNames() {
+        return mTargetNames;
+    }
+
+    /**
+     * Returns the list of target viewNames that this transition limits itself to
+     * tracking and animating. If the list is null or empty for
+     * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetViewNames()}, and
+     * {@link #getTargetTypes()} then this transition is
+     * not limited to specific views, and will handle changes to any views
+     * in the hierarchy of a scene change.
+     *
+     * @return the list of target Types
+     */
+    public List<Class> getTargetTypes() {
+        return mTargetTypes;
+    }
+
+    /**
      * Recursive method that captures values for the given view and the
      * hierarchy underneath it.
      * @param sceneRoot The root of the view hierarchy being captured
@@ -1059,52 +1206,42 @@
      */
     void captureValues(ViewGroup sceneRoot, boolean start) {
         clearValues(start);
-        if (mTargetIds.size() > 0 || mTargets.size() > 0) {
-            if (mTargetIds.size() > 0) {
-                for (int i = 0; i < mTargetIds.size(); ++i) {
-                    int id = mTargetIds.get(i);
-                    View view = sceneRoot.findViewById(id);
-                    if (view != null) {
-                        TransitionValues values = new TransitionValues();
-                        values.view = view;
-                        if (start) {
-                            captureStartValues(values);
-                        } else {
-                            captureEndValues(values);
-                        }
-                        capturePropagationValues(values);
-                        if (start) {
-                            mStartValues.viewValues.put(view, values);
-                            if (id >= 0) {
-                                mStartValues.idValues.put(id, values);
-                            }
-                        } else {
-                            mEndValues.viewValues.put(view, values);
-                            if (id >= 0) {
-                                mEndValues.idValues.put(id, values);
-                            }
-                        }
+        if ((mTargetIds.size() > 0 || mTargets.size() > 0)
+                && (mTargetNames == null || mTargetNames.isEmpty())
+                && (mTargetTypes == null || mTargetTypes.isEmpty())) {
+            for (int i = 0; i < mTargetIds.size(); ++i) {
+                int id = mTargetIds.get(i);
+                View view = sceneRoot.findViewById(id);
+                if (view != null) {
+                    TransitionValues values = new TransitionValues();
+                    values.view = view;
+                    if (start) {
+                        captureStartValues(values);
+                    } else {
+                        captureEndValues(values);
+                    }
+                    capturePropagationValues(values);
+                    if (start) {
+                        addViewValues(mStartValues, view, values);
+                    } else {
+                        addViewValues(mEndValues, view, values);
                     }
                 }
             }
-            if (mTargets.size() > 0) {
-                for (int i = 0; i < mTargets.size(); ++i) {
-                    View view = mTargets.get(i);
-                    if (view != null) {
-                        TransitionValues values = new TransitionValues();
-                        values.view = view;
-                        if (start) {
-                            captureStartValues(values);
-                        } else {
-                            captureEndValues(values);
-                        }
-                        capturePropagationValues(values);
-                        if (start) {
-                            mStartValues.viewValues.put(view, values);
-                        } else {
-                            mEndValues.viewValues.put(view, values);
-                        }
-                    }
+            for (int i = 0; i < mTargets.size(); ++i) {
+                View view = mTargets.get(i);
+                TransitionValues values = new TransitionValues();
+                values.view = view;
+                if (start) {
+                    captureStartValues(values);
+                } else {
+                    captureEndValues(values);
+                }
+                capturePropagationValues(values);
+                if (start) {
+                    mStartValues.viewValues.put(view, values);
+                } else {
+                    mEndValues.viewValues.put(view, values);
                 }
             }
         } else {
@@ -1112,6 +1249,47 @@
         }
     }
 
+    static void addViewValues(TransitionValuesMaps transitionValuesMaps,
+            View view, TransitionValues transitionValues) {
+        transitionValuesMaps.viewValues.put(view, transitionValues);
+        int id = view.getId();
+        if (id >= 0) {
+            if (transitionValuesMaps.idValues.indexOfKey(id) >= 0) {
+                // Duplicate IDs cannot match by ID.
+                transitionValuesMaps.idValues.put(id, null);
+            } else {
+                transitionValuesMaps.idValues.put(id, view);
+            }
+        }
+        String name = view.getViewName();
+        if (name != null) {
+            if (transitionValuesMaps.nameValues.containsKey(name)) {
+                // Duplicate viewNames: cannot match by viewName.
+                transitionValuesMaps.nameValues.put(name, null);
+            } else {
+                transitionValuesMaps.nameValues.put(name, view);
+            }
+        }
+        if (view.getParent() instanceof ListView) {
+            ListView listview = (ListView) view.getParent();
+            if (listview.getAdapter().hasStableIds()) {
+                int position = listview.getPositionForView(view);
+                long itemId = listview.getItemIdAtPosition(position);
+                if (transitionValuesMaps.itemIdValues.indexOfKey(itemId) >= 0) {
+                    // Duplicate item IDs: cannot match by item ID.
+                    View alreadyMatched = transitionValuesMaps.itemIdValues.get(itemId);
+                    if (alreadyMatched != null) {
+                        alreadyMatched.setHasTransientState(false);
+                        transitionValuesMaps.itemIdValues.put(itemId, null);
+                    }
+                } else {
+                    view.setHasTransientState(true);
+                    transitionValuesMaps.itemIdValues.put(itemId, view);
+                }
+            }
+        }
+    }
+
     /**
      * Clear valuesMaps for specified start/end state
      *
@@ -1143,24 +1321,7 @@
         if (view == null) {
             return;
         }
-        boolean isListViewItem = false;
-        if (view.getParent() instanceof ListView) {
-            isListViewItem = true;
-        }
-        if (isListViewItem && !((ListView) view.getParent()).getAdapter().hasStableIds()) {
-            // ignore listview children unless we can track them with stable IDs
-            return;
-        }
-        int id = View.NO_ID;
-        long itemId = View.NO_ID;
-        if (!isListViewItem) {
-            id = view.getId();
-        } else {
-            ListView listview = (ListView) view.getParent();
-            int position = listview.getPositionForView(view);
-            itemId = listview.getItemIdAtPosition(position);
-            view.setHasTransientState(true);
-        }
+        int id = view.getId();
         if (mTargetIdExcludes != null && mTargetIdExcludes.contains(id)) {
             return;
         }
@@ -1185,23 +1346,9 @@
             }
             capturePropagationValues(values);
             if (start) {
-                if (!isListViewItem) {
-                    mStartValues.viewValues.put(view, values);
-                    if (id >= 0) {
-                        mStartValues.idValues.put((int) id, values);
-                    }
-                } else {
-                    mStartValues.itemIdValues.put(itemId, values);
-                }
+                addViewValues(mStartValues, view, values);
             } else {
-                if (!isListViewItem) {
-                    mEndValues.viewValues.put(view, values);
-                    if (id >= 0) {
-                        mEndValues.idValues.put((int) id, values);
-                    }
-                } else {
-                    mEndValues.itemIdValues.put(itemId, values);
-                }
+                addViewValues(mEndValues, view, values);
             }
         }
         if (view instanceof ViewGroup) {
@@ -1212,7 +1359,7 @@
             if (mTargetChildExcludes != null && mTargetChildExcludes.contains(view)) {
                 return;
             }
-            if (mTargetTypeChildExcludes != null && view != null) {
+            if (mTargetTypeChildExcludes != null) {
                 int numTypes = mTargetTypeChildExcludes.size();
                 for (int i = 0; i < numTypes; ++i) {
                     if (mTargetTypeChildExcludes.get(i).isInstance(view)) {
@@ -1238,22 +1385,7 @@
             return mParent.getTransitionValues(view, start);
         }
         TransitionValuesMaps valuesMaps = start ? mStartValues : mEndValues;
-        TransitionValues values = valuesMaps.viewValues.get(view);
-        if (values == null) {
-            int id = view.getId();
-            if (id >= 0) {
-                values = valuesMaps.idValues.get(id);
-            }
-            if (values == null && view.getParent() instanceof ListView) {
-                ListView listview = (ListView) view.getParent();
-                int position = listview.getPositionForView(view);
-                long itemId = listview.getItemIdAtPosition(position);
-                values = valuesMaps.itemIdValues.get(itemId);
-            }
-            // TODO: Doesn't handle the case where a view was parented to a
-            // ListView (with an itemId), but no longer is
-        }
-        return values;
+        return valuesMaps.viewValues.get(view);
     }
 
     /**
@@ -1337,11 +1469,7 @@
                     boolean cancel = false;
                     TransitionValues oldValues = oldInfo.values;
                     View oldView = oldInfo.view;
-                    TransitionValues newValues = mEndValues.viewValues != null ?
-                            mEndValues.viewValues.get(oldView) : null;
-                    if (newValues == null) {
-                        newValues = mEndValues.idValues.get(oldView.getId());
-                    }
+                    TransitionValues newValues = mEndValues.viewValues.get(oldView);
                     if (oldValues != null) {
                         // if oldValues null, then transition didn't care to stash values,
                         // and won't get canceled
@@ -1463,17 +1591,15 @@
                 }
             }
             for (int i = 0; i < mStartValues.itemIdValues.size(); ++i) {
-                TransitionValues tv = mStartValues.itemIdValues.valueAt(i);
-                View v = tv.view;
-                if (v.hasTransientState()) {
-                    v.setHasTransientState(false);
+                View view = mStartValues.itemIdValues.valueAt(i);
+                if (view != null) {
+                    view.setHasTransientState(false);
                 }
             }
             for (int i = 0; i < mEndValues.itemIdValues.size(); ++i) {
-                TransitionValues tv = mEndValues.itemIdValues.valueAt(i);
-                View v = tv.view;
-                if (v.hasTransientState()) {
-                    v.setHasTransientState(false);
+                View view = mEndValues.itemIdValues.valueAt(i);
+                if (view != null) {
+                    view.setHasTransientState(false);
                 }
             }
             mEnded = true;
diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java
index a5e960a..04f8672 100644
--- a/core/java/android/transition/TransitionInflater.java
+++ b/core/java/android/transition/TransitionInflater.java
@@ -229,11 +229,20 @@
                         com.android.internal.R.styleable.TransitionTarget);
                 int id = a.getResourceId(
                         com.android.internal.R.styleable.TransitionTarget_targetId, -1);
+                String viewName;
                 if (id >= 0) {
                     transition.addTarget(id);
                 } else if ((id = a.getResourceId(
                         com.android.internal.R.styleable.TransitionTarget_excludeId, -1)) >= 0) {
                     transition.excludeTarget(id, true);
+                } else if ((viewName = a.getString(
+                            com.android.internal.R.styleable.TransitionTarget_targetViewName))
+                        != null) {
+                    transition.addTarget(viewName);
+                } else if ((viewName = a.getString(
+                        com.android.internal.R.styleable.TransitionTarget_excludeViewName))
+                        != null) {
+                    transition.excludeTarget(viewName, true);
                 } else {
                     String className = a.getString(
                             com.android.internal.R.styleable.TransitionTarget_excludeClass);
diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java
index 9081234..698b563 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -272,24 +272,8 @@
         int numValues = values.viewValues.size();
         for (int i = 0; i < numValues; i++) {
             View view = values.viewValues.keyAt(i);
-            if (isValidTarget(view, view.getId())) {
-                included.viewValues.put(view, values.viewValues.valueAt(i));
-            }
-        }
-        numValues = values.idValues.size();
-        for (int i = 0; i < numValues; i++) {
-            int id = values.idValues.keyAt(i);
-            TransitionValues transitionValues = values.idValues.valueAt(i);
-            if (isValidTarget(transitionValues.view, id)) {
-                included.idValues.put(id, transitionValues);
-            }
-        }
-        numValues = values.itemIdValues.size();
-        for (int i = 0; i < numValues; i++) {
-            long id = values.itemIdValues.keyAt(i);
-            TransitionValues transitionValues = values.itemIdValues.valueAt(i);
-            if (isValidTarget(transitionValues.view, id)) {
-                included.itemIdValues.put(id, transitionValues);
+            if (isValidTarget(view)) {
+                addViewValues(included, view, values.viewValues.valueAt(i));
             }
         }
         return included;
@@ -328,10 +312,9 @@
 
     @Override
     public void captureStartValues(TransitionValues transitionValues) {
-        int targetId = transitionValues.view.getId();
-        if (isValidTarget(transitionValues.view, targetId)) {
+        if (isValidTarget(transitionValues.view)) {
             for (Transition childTransition : mTransitions) {
-                if (childTransition.isValidTarget(transitionValues.view, targetId)) {
+                if (childTransition.isValidTarget(transitionValues.view)) {
                     childTransition.captureStartValues(transitionValues);
                 }
             }
@@ -340,10 +323,9 @@
 
     @Override
     public void captureEndValues(TransitionValues transitionValues) {
-        int targetId = transitionValues.view.getId();
-        if (isValidTarget(transitionValues.view, targetId)) {
+        if (isValidTarget(transitionValues.view)) {
             for (Transition childTransition : mTransitions) {
-                if (childTransition.isValidTarget(transitionValues.view, targetId)) {
+                if (childTransition.isValidTarget(transitionValues.view)) {
                     childTransition.captureEndValues(transitionValues);
                 }
             }
diff --git a/core/java/android/transition/TransitionValuesMaps.java b/core/java/android/transition/TransitionValuesMaps.java
index 131596b..6d5700a 100644
--- a/core/java/android/transition/TransitionValuesMaps.java
+++ b/core/java/android/transition/TransitionValuesMaps.java
@@ -24,7 +24,7 @@
 class TransitionValuesMaps {
     ArrayMap<View, TransitionValues> viewValues =
             new ArrayMap<View, TransitionValues>();
-    SparseArray<TransitionValues> idValues = new SparseArray<TransitionValues>();
-    LongSparseArray<TransitionValues> itemIdValues =
-            new LongSparseArray<TransitionValues>();
+    SparseArray<View> idValues = new SparseArray<View>();
+    LongSparseArray<View> itemIdValues = new LongSparseArray<View>();
+    ArrayMap<String, View> nameValues = new ArrayMap<String, View>();
 }
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 6e6496c..0f7638b 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -162,26 +162,15 @@
     public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
             TransitionValues endValues) {
         VisibilityInfo visInfo = getVisibilityChangeInfo(startValues, endValues);
-        if (visInfo.visibilityChange) {
-            // Only transition views that are either targets of this transition
-            // or whose parent hierarchies remain stable between scenes
-            boolean isTarget = false;
-            if (mTargets.size() > 0 || mTargetIds.size() > 0) {
-                View startView = startValues != null ? startValues.view : null;
-                View endView = endValues != null ? endValues.view : null;
-                int startId = startView != null ? startView.getId() : -1;
-                int endId = endView != null ? endView.getId() : -1;
-                isTarget = isValidTarget(startView, startId) || isValidTarget(endView, endId);
-            }
-            if (isTarget || ((visInfo.startParent != null || visInfo.endParent != null))) {
-                if (visInfo.fadeIn) {
-                    return onAppear(sceneRoot, startValues, visInfo.startVisibility,
-                            endValues, visInfo.endVisibility);
-                } else {
-                    return onDisappear(sceneRoot, startValues, visInfo.startVisibility,
-                            endValues, visInfo.endVisibility
-                    );
-                }
+        if (visInfo.visibilityChange
+                && (visInfo.startParent != null || visInfo.endParent != null)) {
+            if (visInfo.fadeIn) {
+                return onAppear(sceneRoot, startValues, visInfo.startVisibility,
+                        endValues, visInfo.endVisibility);
+            } else {
+                return onDisappear(sceneRoot, startValues, visInfo.startVisibility,
+                        endValues, visInfo.endVisibility
+                );
             }
         }
         return null;
diff --git a/core/java/android/tv/ITvInputClient.aidl b/core/java/android/tv/ITvInputClient.aidl
index 538f8a1..ac83356 100644
--- a/core/java/android/tv/ITvInputClient.aidl
+++ b/core/java/android/tv/ITvInputClient.aidl
@@ -26,6 +26,7 @@
  * @hide
  */
 oneway interface ITvInputClient {
-    void onSessionCreated(in ComponentName name, IBinder token, in InputChannel channel, int seq);
-    void onAvailabilityChanged(in ComponentName name, boolean isAvailable);
+    void onSessionCreated(in String inputId, IBinder token, in InputChannel channel, int seq);
+    void onAvailabilityChanged(in String inputId, boolean isAvailable);
+    void onSessionReleased(int seq);
 }
diff --git a/core/java/android/tv/ITvInputManager.aidl b/core/java/android/tv/ITvInputManager.aidl
index a4c99e4..b756aba 100644
--- a/core/java/android/tv/ITvInputManager.aidl
+++ b/core/java/android/tv/ITvInputManager.aidl
@@ -30,12 +30,12 @@
 interface ITvInputManager {
     List<TvInputInfo> getTvInputList(int userId);
 
-    boolean getAvailability(in ITvInputClient client, in ComponentName name, int userId);
+    boolean getAvailability(in ITvInputClient client, in String inputId, int userId);
 
-    void registerCallback(in ITvInputClient client, in ComponentName name, int userId);
-    void unregisterCallback(in ITvInputClient client, in ComponentName name, int userId);
+    void registerCallback(in ITvInputClient client, in String inputId, int userId);
+    void unregisterCallback(in ITvInputClient client, in String inputId, int userId);
 
-    void createSession(in ITvInputClient client, in ComponentName name, int seq, int userId);
+    void createSession(in ITvInputClient client, in String inputId, int seq, int userId);
     void releaseSession(in IBinder sessionToken, int userId);
 
     void setSurface(in IBinder sessionToken, in Surface surface, int userId);
diff --git a/core/java/android/tv/ITvInputServiceCallback.aidl b/core/java/android/tv/ITvInputServiceCallback.aidl
index e535c81..71fc780 100644
--- a/core/java/android/tv/ITvInputServiceCallback.aidl
+++ b/core/java/android/tv/ITvInputServiceCallback.aidl
@@ -24,5 +24,5 @@
  * @hide
  */
 oneway interface ITvInputServiceCallback {
-    void onAvailabilityChanged(in ComponentName name, boolean isAvailable);
+    void onAvailabilityChanged(in String inputId, boolean isAvailable);
 }
diff --git a/core/java/android/tv/TvInputInfo.java b/core/java/android/tv/TvInputInfo.java
index 90e4177..50462cc 100644
--- a/core/java/android/tv/TvInputInfo.java
+++ b/core/java/android/tv/TvInputInfo.java
@@ -39,7 +39,7 @@
     public TvInputInfo(ResolveInfo service) {
         mService = service;
         ServiceInfo si = service.serviceInfo;
-        mId = new ComponentName(si.packageName, si.name).flattenToShortString();
+        mId = generateInputIdForComponenetName(new ComponentName(si.packageName, si.name));
     }
 
     /**
@@ -75,7 +75,7 @@
      * Loads the user-displayed label for this TV input service.
      *
      * @param pm Supplies a PackageManager used to load the TV input's resources.
-     * @return Returns a CharSequence containing the TV input's label. If the TV input does not have
+     * @return a CharSequence containing the TV input's label. If the TV input does not have
      *         a label, its name is returned.
      */
     public CharSequence loadLabel(PackageManager pm) {
@@ -128,6 +128,17 @@
     }
 
     /**
+     * Used to generate an input id from a ComponentName.
+     *
+     * @param name the component name for generating an input id.
+     * @return the generated input id for the given {@code name}.
+     * @hide
+     */
+    public static final String generateInputIdForComponenetName(ComponentName name) {
+        return name.flattenToShortString();
+    }
+
+    /**
      * Used to make this class parcelable.
      *
      * @hide
diff --git a/core/java/android/tv/TvInputManager.java b/core/java/android/tv/TvInputManager.java
index 7b9b1fb..c5f179a 100644
--- a/core/java/android/tv/TvInputManager.java
+++ b/core/java/android/tv/TvInputManager.java
@@ -16,7 +16,6 @@
 
 package android.tv;
 
-import android.content.ComponentName;
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Handler;
@@ -50,15 +49,15 @@
     private final ITvInputManager mService;
 
     // A mapping from an input to the list of its TvInputListenerRecords.
-    private final Map<ComponentName, List<TvInputListenerRecord>> mTvInputListenerRecordsMap =
-            new HashMap<ComponentName, List<TvInputListenerRecord>>();
+    private final Map<String, List<TvInputListenerRecord>> mTvInputListenerRecordsMap =
+            new HashMap<String, List<TvInputListenerRecord>>();
 
-    // A mapping from the sequence number of a session to its SessionCreateCallbackRecord.
-    private final SparseArray<SessionCreateCallbackRecord> mSessionCreateCallbackRecordMap =
-            new SparseArray<SessionCreateCallbackRecord>();
+    // A mapping from the sequence number of a session to its SessionCallbackRecord.
+    private final SparseArray<SessionCallbackRecord> mSessionCallbackRecordMap =
+            new SparseArray<SessionCallbackRecord>();
 
     // A sequence number for the next session to be created. Should be protected by a lock
-    // {@code mSessionCreateCallbackRecordMap}.
+    // {@code mSessionCallbackRecordMap}.
     private int mNextSeq;
 
     private final ITvInputClient mClient;
@@ -68,31 +67,52 @@
     /**
      * Interface used to receive the created session.
      */
-    public interface SessionCreateCallback {
+    public abstract static class SessionCallback {
         /**
          * This is called after {@link TvInputManager#createSession} has been processed.
          *
          * @param session A {@link TvInputManager.Session} instance created. This can be
          *            {@code null} if the creation request failed.
          */
-        void onSessionCreated(Session session);
+        public void onSessionCreated(Session session) {
+        }
+
+        /**
+         * This is called when {@link TvInputManager.Session} is released.
+         * This typically happens when the process hosting the session has crashed or been killed.
+         *
+         * @param session A {@link TvInputManager.Session} instance released.
+         */
+        public void onSessionReleased(Session session) {
+        }
     }
 
-    private static final class SessionCreateCallbackRecord {
-        private final SessionCreateCallback mSessionCreateCallback;
+    private static final class SessionCallbackRecord {
+        private final SessionCallback mSessionCallback;
         private final Handler mHandler;
+        private Session mSession;
 
-        public SessionCreateCallbackRecord(SessionCreateCallback sessionCreateCallback,
+        public SessionCallbackRecord(SessionCallback sessionCallback,
                 Handler handler) {
-            mSessionCreateCallback = sessionCreateCallback;
+            mSessionCallback = sessionCallback;
             mHandler = handler;
         }
 
         public void postSessionCreated(final Session session) {
+            mSession = session;
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    mSessionCreateCallback.onSessionCreated(session);
+                    mSessionCallback.onSessionCreated(session);
+                }
+            });
+        }
+
+        public void postSessionReleased() {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSessionCallback.onSessionReleased(mSession);
                 }
             });
         }
@@ -105,12 +125,11 @@
         /**
          * This is called when the availability status of a given TV input is changed.
          *
-         * @param name {@link ComponentName} of {@link android.app.Service} that implements the
-         *            given TV input.
+         * @param inputId the id of the TV input.
          * @param isAvailable {@code true} if the given TV input is available to show TV programs.
          *            {@code false} otherwise.
          */
-        public void onAvailabilityChanged(ComponentName name, boolean isAvailable) {
+        public void onAvailabilityChanged(String inputId, boolean isAvailable) {
         }
     }
 
@@ -127,11 +146,11 @@
             return mListener;
         }
 
-        public void postAvailabilityChanged(final ComponentName name, final boolean isAvailable) {
+        public void postAvailabilityChanged(final String inputId, final boolean isAvailable) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    mListener.onAvailabilityChanged(name, isAvailable);
+                    mListener.onAvailabilityChanged(inputId, isAvailable);
                 }
             });
         }
@@ -145,34 +164,48 @@
         mUserId = userId;
         mClient = new ITvInputClient.Stub() {
             @Override
-            public void onSessionCreated(ComponentName name, IBinder token, InputChannel channel,
+            public void onSessionCreated(String inputId, IBinder token, InputChannel channel,
                     int seq) {
-                synchronized (mSessionCreateCallbackRecordMap) {
-                    SessionCreateCallbackRecord record = mSessionCreateCallbackRecordMap.get(seq);
-                    mSessionCreateCallbackRecordMap.delete(seq);
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
                     if (record == null) {
                         Log.e(TAG, "Callback not found for " + token);
                         return;
                     }
                     Session session = null;
                     if (token != null) {
-                        session = new Session(token, channel, mService, mUserId);
+                        session = new Session(token, channel, mService, mUserId, seq,
+                                mSessionCallbackRecordMap);
                     }
                     record.postSessionCreated(session);
                 }
             }
 
             @Override
-            public void onAvailabilityChanged(ComponentName name, boolean isAvailable) {
+            public void onSessionReleased(int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    mSessionCallbackRecordMap.delete(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq:" + seq);
+                        return;
+                    }
+                    record.mSession.releaseInternal();
+                    record.postSessionReleased();
+                }
+            }
+
+            @Override
+            public void onAvailabilityChanged(String inputId, boolean isAvailable) {
                 synchronized (mTvInputListenerRecordsMap) {
-                    List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(name);
+                    List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId);
                     if (records == null) {
                         // Silently ignore - no listener is registered yet.
                         return;
                     }
                     int recordsCount = records.size();
                     for (int i = 0; i < recordsCount; i++) {
-                        records.get(i).postAvailabilityChanged(name, isAvailable);
+                        records.get(i).postAvailabilityChanged(inputId, isAvailable);
                     }
                 }
             }
@@ -195,24 +228,23 @@
     /**
      * Returns the availability of a given TV input.
      *
-     * @param name {@link ComponentName} of {@link android.app.Service} that implements the given TV
-     *            input.
+     * @param inputId the id of the TV input.
      * @throws IllegalArgumentException if the argument is {@code null}.
      * @throws IllegalStateException If there is no {@link TvInputListener} registered on the given
      *             TV input.
      */
-    public boolean getAvailability(ComponentName name) {
-        if (name == null) {
-            throw new IllegalArgumentException("name cannot be null");
+    public boolean getAvailability(String inputId) {
+        if (inputId == null) {
+            throw new IllegalArgumentException("id cannot be null");
         }
         synchronized (mTvInputListenerRecordsMap) {
-            List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(name);
+            List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId);
             if (records == null || records.size() == 0) {
                 throw new IllegalStateException("At least one listener should be registered.");
             }
         }
         try {
-            return mService.getAvailability(mClient, name, mUserId);
+            return mService.getAvailability(mClient, inputId, mUserId);
         } catch (RemoteException e) {
             throw new RuntimeException(e);
         }
@@ -221,15 +253,14 @@
     /**
      * Registers a {@link TvInputListener} for a given TV input.
      *
-     * @param name {@link ComponentName} of {@link android.app.Service} that implements the given TV
-     *            input.
+     * @param inputId the id of the TV input.
      * @param listener a listener used to monitor status of the given TV input.
      * @param handler a {@link Handler} that the status change will be delivered to.
      * @throws IllegalArgumentException if any of the arguments is {@code null}.
      */
-    public void registerListener(ComponentName name, TvInputListener listener, Handler handler) {
-        if (name == null) {
-            throw new IllegalArgumentException("name cannot be null");
+    public void registerListener(String inputId, TvInputListener listener, Handler handler) {
+        if (inputId == null) {
+            throw new IllegalArgumentException("id cannot be null");
         }
         if (listener == null) {
             throw new IllegalArgumentException("listener cannot be null");
@@ -238,12 +269,12 @@
             throw new IllegalArgumentException("handler cannot be null");
         }
         synchronized (mTvInputListenerRecordsMap) {
-            List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(name);
+            List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId);
             if (records == null) {
                 records = new ArrayList<TvInputListenerRecord>();
-                mTvInputListenerRecordsMap.put(name, records);
+                mTvInputListenerRecordsMap.put(inputId, records);
                 try {
-                    mService.registerCallback(mClient, name, mUserId);
+                    mService.registerCallback(mClient, inputId, mUserId);
                 } catch (RemoteException e) {
                     throw new RuntimeException(e);
                 }
@@ -255,22 +286,21 @@
     /**
      * Unregisters the existing {@link TvInputListener} for a given TV input.
      *
-     * @param name {@link ComponentName} of {@link android.app.Service} that implements the given TV
-     *            input.
+     * @param inputId the id of the TV input.
      * @param listener the existing listener to remove for the given TV input.
      * @throws IllegalArgumentException if any of the arguments is {@code null}.
      */
-    public void unregisterListener(ComponentName name, final TvInputListener listener) {
-        if (name == null) {
-            throw new IllegalArgumentException("name cannot be null");
+    public void unregisterListener(String inputId, final TvInputListener listener) {
+        if (inputId == null) {
+            throw new IllegalArgumentException("id cannot be null");
         }
         if (listener == null) {
             throw new IllegalArgumentException("listener cannot be null");
         }
         synchronized (mTvInputListenerRecordsMap) {
-            List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(name);
+            List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId);
             if (records == null) {
-                Log.e(TAG, "No listener found for " + name.getClassName());
+                Log.e(TAG, "No listener found for " + inputId);
                 return;
             }
             for (Iterator<TvInputListenerRecord> it = records.iterator(); it.hasNext();) {
@@ -281,11 +311,11 @@
             }
             if (records.isEmpty()) {
                 try {
-                    mService.unregisterCallback(mClient, name, mUserId);
+                    mService.unregisterCallback(mClient, inputId, mUserId);
                 } catch (RemoteException e) {
                     throw new RuntimeException(e);
                 } finally {
-                    mTvInputListenerRecordsMap.remove(name);
+                    mTvInputListenerRecordsMap.remove(inputId);
                 }
             }
         }
@@ -298,16 +328,15 @@
      * the given TV input.
      * </p>
      *
-     * @param name {@link ComponentName} of {@link android.app.Service} that implements the given TV
-     *            input.
+     * @param inputId the id of the TV input.
      * @param callback a callback used to receive the created session.
      * @param handler a {@link Handler} that the session creation will be delivered to.
      * @throws IllegalArgumentException if any of the arguments is {@code null}.
      */
-    public void createSession(ComponentName name, final SessionCreateCallback callback,
+    public void createSession(String inputId, final SessionCallback callback,
             Handler handler) {
-        if (name == null) {
-            throw new IllegalArgumentException("name cannot be null");
+        if (inputId == null) {
+            throw new IllegalArgumentException("id cannot be null");
         }
         if (callback == null) {
             throw new IllegalArgumentException("callback cannot be null");
@@ -315,12 +344,12 @@
         if (handler == null) {
             throw new IllegalArgumentException("handler cannot be null");
         }
-        SessionCreateCallbackRecord record = new SessionCreateCallbackRecord(callback, handler);
-        synchronized (mSessionCreateCallbackRecordMap) {
+        SessionCallbackRecord record = new SessionCallbackRecord(callback, handler);
+        synchronized (mSessionCallbackRecordMap) {
             int seq = mNextSeq++;
-            mSessionCreateCallbackRecordMap.put(seq, record);
+            mSessionCallbackRecordMap.put(seq, record);
             try {
-                mService.createSession(mClient, name, seq, mUserId);
+                mService.createSession(mClient, inputId, seq, mUserId);
             } catch (RemoteException e) {
                 throw new RuntimeException(e);
             }
@@ -337,6 +366,7 @@
 
         private final ITvInputManager mService;
         private final int mUserId;
+        private final int mSeq;
 
         // For scheduling input event handling on the main thread. This also serves as a lock to
         // protect pending input events and the input channel.
@@ -344,17 +374,21 @@
 
         private final Pool<PendingEvent> mPendingEventPool = new SimplePool<PendingEvent>(20);
         private final SparseArray<PendingEvent> mPendingEvents = new SparseArray<PendingEvent>(20);
+        private final SparseArray<SessionCallbackRecord> mSessionCallbackRecordMap;
 
         private IBinder mToken;
         private TvInputEventSender mSender;
         private InputChannel mChannel;
 
         /** @hide */
-        private Session(IBinder token, InputChannel channel, ITvInputManager service, int userId) {
+        private Session(IBinder token, InputChannel channel, ITvInputManager service, int userId,
+                int seq, SparseArray<SessionCallbackRecord> sessionCallbackRecordMap) {
             mToken = token;
             mChannel = channel;
             mService = service;
             mUserId = userId;
+            mSeq = seq;
+            mSessionCallbackRecordMap = sessionCallbackRecordMap;
         }
 
         /**
@@ -368,22 +402,11 @@
             }
             try {
                 mService.releaseSession(mToken, mUserId);
-                mToken = null;
             } catch (RemoteException e) {
                 throw new RuntimeException(e);
             }
 
-            synchronized (mHandler) {
-                if (mChannel != null) {
-                    if (mSender != null) {
-                        flushPendingEventsLocked();
-                        mSender.dispose();
-                        mSender = null;
-                    }
-                    mChannel.dispose();
-                    mChannel = null;
-                }
-            }
+            releaseInternal();
         }
 
         /**
@@ -675,6 +698,24 @@
             mPendingEventPool.release(p);
         }
 
+        private void releaseInternal() {
+            mToken = null;
+            synchronized (mHandler) {
+                if (mChannel != null) {
+                    if (mSender != null) {
+                        flushPendingEventsLocked();
+                        mSender.dispose();
+                        mSender = null;
+                    }
+                    mChannel.dispose();
+                    mChannel = null;
+                }
+            }
+            synchronized (mSessionCallbackRecordMap) {
+                mSessionCallbackRecordMap.remove(mSeq);
+            }
+        }
+
         private final class InputEventHandler extends Handler {
             public static final int MSG_SEND_INPUT_EVENT = 1;
             public static final int MSG_TIMEOUT_INPUT_EVENT = 2;
diff --git a/core/java/android/tv/TvInputService.java b/core/java/android/tv/TvInputService.java
index 70e7f95..eeb738d 100644
--- a/core/java/android/tv/TvInputService.java
+++ b/core/java/android/tv/TvInputService.java
@@ -60,7 +60,7 @@
      */
     public static final String SERVICE_INTERFACE = "android.tv.TvInputService";
 
-    private ComponentName mComponentName;
+    private String mId;
     private final Handler mHandler = new ServiceHandler();
     private final RemoteCallbackList<ITvInputServiceCallback> mCallbacks =
             new RemoteCallbackList<ITvInputServiceCallback>();
@@ -69,7 +69,8 @@
     @Override
     public void onCreate() {
         super.onCreate();
-        mComponentName = new ComponentName(getPackageName(), getClass().getName());
+        mId = TvInputInfo.generateInputIdForComponenetName(
+                new ComponentName(getPackageName(), getClass().getName()));
     }
 
     @Override
@@ -82,7 +83,7 @@
                     // The first time a callback is registered, the service needs to report its
                     // availability status so that the system can know its initial value.
                     try {
-                        cb.onAvailabilityChanged(mComponentName, mAvailable);
+                        cb.onAvailabilityChanged(mId, mAvailable);
                     } catch (RemoteException e) {
                         Log.e(TAG, "error in onAvailabilityChanged", e);
                     }
@@ -488,7 +489,7 @@
                     }
                 }
             }
-            if (mOverlayView == null) {
+            if (mOverlayView == null || !mOverlayView.isAttachedToWindow()) {
                 return Session.DISPATCH_NOT_HANDLED;
             }
             if (!mOverlayView.hasWindowFocus()) {
@@ -531,8 +532,7 @@
                     int n = mCallbacks.beginBroadcast();
                     try {
                         for (int i = 0; i < n; i++) {
-                            mCallbacks.getBroadcastItem(i).onAvailabilityChanged(mComponentName,
-                                    isAvailable);
+                            mCallbacks.getBroadcastItem(i).onAvailabilityChanged(mId, isAvailable);
                         }
                     } catch (RemoteException e) {
                         Log.e(TAG, "Unexpected exception", e);
diff --git a/core/java/android/tv/TvView.java b/core/java/android/tv/TvView.java
index 289823b..7721575 100644
--- a/core/java/android/tv/TvView.java
+++ b/core/java/android/tv/TvView.java
@@ -16,13 +16,13 @@
 
 package android.tv;
 
-import android.content.ComponentName;
 import android.content.Context;
 import android.graphics.Rect;
 import android.os.Handler;
+import android.text.TextUtils;
 import android.tv.TvInputManager.Session;
 import android.tv.TvInputManager.Session.FinishedInputEventCallback;
-import android.tv.TvInputManager.SessionCreateCallback;
+import android.tv.TvInputManager.SessionCallback;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.InputEvent;
@@ -31,6 +31,7 @@
 import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
+import android.view.ViewRootImpl;
 
 /**
  * View playing TV
@@ -46,7 +47,7 @@
     private boolean mOverlayViewCreated;
     private Rect mOverlayViewFrame;
     private final TvInputManager mTvInputManager;
-    private SessionCreateCallback mSessionCreateCallback;
+    private SessionCallback mSessionCallback;
     private OnUnhandledInputEventListener mOnUnhandledInputEventListener;
 
     private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
@@ -89,7 +90,10 @@
             if (dispatchUnhandledInputEvent(event)) {
                 return;
             }
-            getViewRootImpl().dispatchUnhandledInputEvent(event);
+            ViewRootImpl viewRootImpl = getViewRootImpl();
+            if (viewRootImpl != null) {
+                viewRootImpl.dispatchUnhandledInputEvent(event);
+            }
         }
     };
 
@@ -108,19 +112,19 @@
     }
 
     /**
-     * Binds a TV input to this view. {@link SessionCreateCallback#onSessionCreated} will be
+     * Binds a TV input to this view. {@link SessionCallback#onSessionCreated} will be
      * called to send the result of this binding with {@link TvInputManager.Session}.
      * If a TV input is already bound, the input will be unbound from this view and its session
      * will be released.
      *
-     * @param name TV input name will be bound to this view.
+     * @param inputId the id of TV input which will be bound to this view.
      * @param callback called when TV input is bound. The callback sends
      *        {@link TvInputManager.Session}
      * @throws IllegalArgumentException if any of the arguments is {@code null}.
      */
-    public void bindTvInput(ComponentName name, SessionCreateCallback callback) {
-        if (name == null) {
-            throw new IllegalArgumentException("name cannot be null");
+    public void bindTvInput(String inputId, SessionCallback callback) {
+        if (TextUtils.isEmpty(inputId)) {
+            throw new IllegalArgumentException("inputId cannot be null or an empty string");
         }
         if (callback == null) {
             throw new IllegalArgumentException("callback cannot be null");
@@ -130,11 +134,11 @@
         }
         // When bindTvInput is called multiple times before the callback is called,
         // only the callback of the last bindTvInput call will be actually called back.
-        // The previous callbacks will be ignored. For the logic, mSessionCreateCallback
+        // The previous callbacks will be ignored. For the logic, mSessionCallback
         // is newly assigned for every bindTvInput call and compared with
         // MySessionCreateCallback.this.
-        mSessionCreateCallback = new MySessionCreateCallback(callback);
-        mTvInputManager.createSession(name, mSessionCreateCallback, mHandler);
+        mSessionCallback = new MySessionCallback(callback);
+        mTvInputManager.createSession(inputId, mSessionCallback, mHandler);
     }
 
     /**
@@ -196,7 +200,9 @@
         if (mSession == null) {
             return false;
         }
-        int ret = mSession.dispatchInputEvent(event, event, mFinishedInputEventCallback, mHandler);
+        InputEvent copiedEvent = event.copy();
+        int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback,
+                mHandler);
         return ret != Session.DISPATCH_NOT_HANDLED;
     }
 
@@ -209,7 +215,9 @@
         if (mSession == null) {
             return false;
         }
-        int ret = mSession.dispatchInputEvent(event, event, mFinishedInputEventCallback, mHandler);
+        InputEvent copiedEvent = event.copy();
+        int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback,
+                mHandler);
         return ret != Session.DISPATCH_NOT_HANDLED;
     }
 
@@ -222,7 +230,9 @@
         if (mSession == null) {
             return false;
         }
-        int ret = mSession.dispatchInputEvent(event, event, mFinishedInputEventCallback, mHandler);
+        InputEvent copiedEvent = event.copy();
+        int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback,
+                mHandler);
         return ret != Session.DISPATCH_NOT_HANDLED;
     }
 
@@ -235,7 +245,9 @@
         if (mSession == null) {
             return false;
         }
-        int ret = mSession.dispatchInputEvent(event, event, mFinishedInputEventCallback, mHandler);
+        InputEvent copiedEvent = event.copy();
+        int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback,
+                mHandler);
         return ret != Session.DISPATCH_NOT_HANDLED;
     }
 
@@ -328,18 +340,20 @@
         boolean onUnhandledInputEvent(InputEvent event);
     }
 
-    private class MySessionCreateCallback implements SessionCreateCallback {
-        final SessionCreateCallback mExternalCallback;
+    private class MySessionCallback extends SessionCallback {
+        final SessionCallback mExternalCallback;
 
-        MySessionCreateCallback(SessionCreateCallback externalCallback) {
+        MySessionCallback(SessionCallback externalCallback) {
             mExternalCallback = externalCallback;
         }
 
         @Override
         public void onSessionCreated(Session session) {
-            if (this != mSessionCreateCallback) {
+            if (this != mSessionCallback) {
                 // This callback is obsolete.
-                session.release();
+                if (session != null) {
+                    session.release();
+                }
                 return;
             }
             mSession = session;
@@ -356,5 +370,13 @@
                 mExternalCallback.onSessionCreated(session);
             }
         }
+
+        @Override
+        public void onSessionReleased(Session session) {
+            mSession = null;
+            if (mExternalCallback != null) {
+                mExternalCallback.onSessionReleased(session);
+            }
+        }
     }
 }
diff --git a/core/java/android/util/Range.java b/core/java/android/util/Range.java
new file mode 100644
index 0000000..d7e8cf0
--- /dev/null
+++ b/core/java/android/util/Range.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 static com.android.internal.util.Preconditions.*;
+
+import android.hardware.camera2.utils.HashCodeHelpers;
+
+/**
+ * Immutable class for describing the range of two numeric values.
+ * <p>
+ * A range (or "interval") defines the inclusive boundaries around a contiguous span of
+ * values of some {@link Comparable} type; for example,
+ * "integers from 1 to 100 inclusive."
+ * </p>
+ * <p>
+ * All ranges are bounded, and the left side of the range is always {@code >=}
+ * the right side of the range.
+ * </p>
+ *
+ * <p>Although the implementation itself is immutable, there is no restriction that objects
+ * stored must also be immutable. If mutable objects are stored here, then the range
+ * effectively becomes mutable. </p>
+ */
+public final class Range<T extends Comparable<? super T>> {
+    /**
+     * Create a new immutable range.
+     *
+     * <p>
+     * The endpoints are {@code [lower, upper]}; that
+     * is the range is bounded. {@code lower} must be {@link Comparable#compareTo lesser or equal}
+     * to {@code upper}.
+     * </p>
+     *
+     * @param lower The lower endpoint (inclusive)
+     * @param upper The upper endpoint (inclusive)
+     *
+     * @throws NullPointerException if {@code lower} or {@code upper} is {@code null}
+     */
+    public Range(final T lower, final T upper) {
+        mLower = checkNotNull(lower, "lower must not be null");
+        mUpper = checkNotNull(upper, "upper must not be null");
+
+        if (lower.compareTo(upper) > 0) {
+            throw new IllegalArgumentException("lower must be less than or equal to upper");
+        }
+    }
+
+    /**
+     * Create a new immutable range, with the argument types inferred.
+     *
+     * <p>
+     * The endpoints are {@code [lower, upper]}; that
+     * is the range is bounded. {@code lower} must be {@link Comparable#compareTo lesser or equal}
+     * to {@code upper}.
+     * </p>
+     *
+     * @param lower The lower endpoint (inclusive)
+     * @param upper The upper endpoint (inclusive)
+     *
+     * @throws NullPointerException if {@code lower} or {@code upper} is {@code null}
+     */
+    public static <T extends Comparable<? super T>> Range<T> create(final T lower, final T upper) {
+        return new Range<T>(lower, upper);
+    }
+
+    /**
+     * Get the lower endpoint.
+     *
+     * @return a non-{@code null} {@code T} reference
+     */
+    public T getLower() {
+        return mLower;
+    }
+
+    /**
+     * Get the upper endpoint.
+     *
+     * @return a non-{@code null} {@code T} reference
+     */
+    public T getUpper() {
+        return mUpper;
+    }
+
+    /**
+     * Compare two ranges for equality.
+     *
+     * <p>A range is considered equal if and only if both the lower and upper endpoints
+     * are also equal.</p>
+     *
+     * @return {@code true} if the ranges are equal, {@code false} otherwise
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof Range) {
+            @SuppressWarnings("rawtypes")
+            final
+            Range other = (Range) obj;
+            return mLower.equals(other.mLower) && mUpper.equals(other.mUpper);
+        }
+        return false;
+    }
+
+    /**
+     * Return the range as a string representation {@code "[lower, upper]"}.
+     *
+     * @return string representation of the range
+     */
+    @Override
+    public String toString() {
+        return String.format("[%s, %s]", mLower, mUpper);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return HashCodeHelpers.hashCode(mLower, mUpper);
+    }
+
+    private final T mLower;
+    private final T mUpper;
+};
diff --git a/core/java/android/util/Size.java b/core/java/android/util/Size.java
new file mode 100644
index 0000000..ba1a35f
--- /dev/null
+++ b/core/java/android/util/Size.java
@@ -0,0 +1,98 @@
+/*
+ * 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.util;
+
+/**
+ * Immutable class for describing width and height dimensions in pixels.
+ */
+public final class Size {
+    /**
+     * Create a new immutable Size instance.
+     *
+     * @param width The width of the size, in pixels
+     * @param height The height of the size, in pixels
+     */
+    public Size(int width, int height) {
+        mWidth = width;
+        mHeight = height;
+    }
+
+    /**
+     * Get the width of the size (in pixels).
+     * @return width
+     */
+    public int getWidth() {
+        return mWidth;
+    }
+
+    /**
+     * Get the height of the size (in pixels).
+     * @return height
+     */
+    public int getHeight() {
+        return mHeight;
+    }
+
+    /**
+     * Check if this size is equal to another size.
+     * <p>
+     * Two sizes are equal if and only if both their widths and heights are
+     * equal.
+     * </p>
+     * <p>
+     * A size object is never equal to any other type of object.
+     * </p>
+     *
+     * @return {@code true} if the objects were equal, {@code false} otherwise
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof Size) {
+            Size other = (Size) obj;
+            return mWidth == other.mWidth && mHeight == other.mHeight;
+        }
+        return false;
+    }
+
+    /**
+     * Return the size represented as a string with the format {@code "WxH"}
+     *
+     * @return string representation of the size
+     */
+    @Override
+    public String toString() {
+        return mWidth + "x" + mHeight;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        // assuming most sizes are <2^16, doing a rotate will give us perfect hashing
+        return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2)));
+    }
+
+    private final int mWidth;
+    private final int mHeight;
+};
diff --git a/core/java/android/util/SizeF.java b/core/java/android/util/SizeF.java
new file mode 100644
index 0000000..0a8b4ed
--- /dev/null
+++ b/core/java/android/util/SizeF.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 static com.android.internal.util.Preconditions.*;
+
+/**
+ * Immutable class for describing width and height dimensions in some arbitrary
+ * unit.
+ * <p>
+ * Width and height are finite values stored as a floating point representation.
+ * </p>
+ */
+public final class SizeF {
+    /**
+     * Create a new immutable SizeF instance.
+     *
+     * <p>Both the {@code width} and the {@code height} must be a finite number.
+     * In particular, {@code NaN} and positive/negative infinity are illegal values.</p>
+     *
+     * @param width The width of the size
+     * @param height The height of the size
+     *
+     * @throws IllegalArgumentException
+     *             if either {@code width} or {@code height} was not finite.
+     */
+    public SizeF(final float width, final float height) {
+        mWidth = checkArgumentFinite(width, "width");
+        mHeight = checkArgumentFinite(height, "height");
+    }
+
+    /**
+     * Get the width of the size (as an arbitrary unit).
+     * @return width
+     */
+    public float getWidth() {
+        return mWidth;
+    }
+
+    /**
+     * Get the height of the size (as an arbitrary unit).
+     * @return height
+     */
+    public float getHeight() {
+        return mHeight;
+    }
+
+    /**
+     * Check if this size is equal to another size.
+     *
+     * <p>Two sizes are equal if and only if both their widths and heights are the same.</p>
+     *
+     * <p>For this purpose, the width/height float values are considered to be the same if and only
+     * if the method {@link Float#floatToIntBits(float)} returns the identical {@code int} value
+     * when applied to each.</p>
+     *
+     * @return {@code true} if the objects were equal, {@code false} otherwise
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof SizeF) {
+            final SizeF other = (SizeF) obj;
+            return mWidth == other.mWidth && mHeight == other.mHeight;
+        }
+        return false;
+    }
+
+    /**
+     * Return the size represented as a string with the format {@code "WxH"}
+     *
+     * @return string representation of the size
+     */
+    @Override
+    public String toString() {
+        return mWidth + "x" + mHeight;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return Float.floatToIntBits(mWidth) ^ Float.floatToIntBits(mHeight);
+    }
+
+    private final float mWidth;
+    private final float mHeight;
+};
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 33964a0..8f4b710 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -245,6 +245,9 @@
     private static final int SECONDS_PER_HOUR = 60 * 60;
     private static final int SECONDS_PER_DAY = 24 * 60 * 60;
 
+    /** @hide */
+    public static final long NANOS_PER_MS = 1000000;
+
     private static final Object sFormatSync = new Object();
     private static char[] sFormatStr = new char[HUNDRED_DAY_FIELD_LEN+5];
 
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index f1523ae..1066430 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -112,8 +112,6 @@
     private static final int SKIPPED_FRAME_WARNING_LIMIT = SystemProperties.getInt(
             "debug.choreographer.skipwarning", 30);
 
-    private static final long NANOS_PER_MS = 1000000;
-
     private static final int MSG_DO_FRAME = 0;
     private static final int MSG_DO_SCHEDULE_VSYNC = 1;
     private static final int MSG_DO_SCHEDULE_CALLBACK = 2;
@@ -259,6 +257,14 @@
         return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
     }
 
+    /**
+     * @return The refresh rate as the nanoseconds between frames
+     * @hide
+     */
+    public long getFrameIntervalNanos() {
+        return mFrameIntervalNanos;
+    }
+
     void dump(String prefix, PrintWriter writer) {
         String innerPrefix = prefix + "  ";
         writer.print(prefix); writer.println("Choreographer:");
@@ -448,7 +454,7 @@
      * @hide
      */
     public long getFrameTime() {
-        return getFrameTimeNanos() / NANOS_PER_MS;
+        return getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
     }
 
     /**
@@ -489,7 +495,7 @@
                 }
             } else {
                 final long nextFrameTime = Math.max(
-                        mLastFrameTimeNanos / NANOS_PER_MS + sFrameDelay, now);
+                        mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
                 if (DEBUG) {
                     Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
                 }
@@ -738,7 +744,7 @@
             mFrame = frame;
             Message msg = Message.obtain(mHandler, this);
             msg.setAsynchronous(true);
-            mHandler.sendMessageAtTime(msg, timestampNanos / NANOS_PER_MS);
+            mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
         }
 
         @Override
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 1b26202..a272296 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -18,6 +18,7 @@
 
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.CanvasProperty;
 import android.graphics.DrawFilter;
 import android.graphics.Matrix;
 import android.graphics.NinePatch;
@@ -42,7 +43,6 @@
 class GLES20Canvas extends HardwareCanvas {
     // Must match modifiers used in the JNI layer
     private static final int MODIFIER_NONE = 0;
-    private static final int MODIFIER_SHADOW = 1;
     private static final int MODIFIER_SHADER = 2;
 
     private final boolean mOpaque;
@@ -263,27 +263,6 @@
 
     private static native int nCallDrawGLFunction(long renderer, long drawGLFunction);
 
-    @Override
-    public int invokeFunctors(Rect dirty) {
-        return nInvokeFunctors(mRenderer, dirty);
-    }
-
-    private static native int nInvokeFunctors(long renderer, Rect dirty);
-
-    @Override
-    public void detachFunctor(long functor) {
-        nDetachFunctor(mRenderer, functor);
-    }
-
-    private static native void nDetachFunctor(long renderer, long functor);
-
-    @Override
-    public void attachFunctor(long functor) {
-        nAttachFunctor(mRenderer, functor);
-    }
-
-    private static native void nAttachFunctor(long renderer, long functor);
-
     ///////////////////////////////////////////////////////////////////////////
     // Memory
     ///////////////////////////////////////////////////////////////////////////
@@ -889,6 +868,16 @@
             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 drawColor(int color) {
         drawColor(color, PorterDuff.Mode.SRC_OVER);
     }
@@ -1309,12 +1298,6 @@
     private int setupModifiers(Paint paint) {
         int modifiers = MODIFIER_NONE;
 
-        if (paint.hasShadow) {
-            nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
-                    paint.shadowColor);
-            modifiers |= MODIFIER_SHADOW;
-        }
-
         final Shader shader = paint.getShader();
         if (shader != null) {
             nSetupShader(mRenderer, shader.native_shader);
@@ -1327,12 +1310,6 @@
     private int setupModifiers(Paint paint, int flags) {
         int modifiers = MODIFIER_NONE;
 
-        if (paint.hasShadow && (flags & MODIFIER_SHADOW) != 0) {
-            nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
-                    paint.shadowColor);
-            modifiers |= MODIFIER_SHADOW;
-        }
-
         final Shader shader = paint.getShader();
         if (shader != null && (flags & MODIFIER_SHADER) != 0) {
             nSetupShader(mRenderer, shader.native_shader);
@@ -1343,8 +1320,6 @@
     }
 
     private static native void nSetupShader(long renderer, long shader);
-    private static native void nSetupShadow(long renderer, float radius,
-            float dx, float dy, int color);
 
     private static native void nResetModifiers(long renderer, int modifiers);
 }
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
index 2b29e5c..a94ec3a 100644
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ b/core/java/android/view/GLES20RecordingCanvas.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.annotation.NonNull;
 import android.util.Pools.SynchronizedPool;
 
 /**
@@ -32,19 +33,25 @@
     private static final SynchronizedPool<GLES20RecordingCanvas> sPool =
             new SynchronizedPool<GLES20RecordingCanvas>(POOL_LIMIT);
 
+    RenderNode mNode;
+
     private GLES20RecordingCanvas() {
         super(true, true);
     }
 
-    static GLES20RecordingCanvas obtain() {
+    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);
     }
 
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index 97339cc..7b49006 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -168,7 +168,6 @@
     private final Rect mRedrawClip = new Rect();
 
     private final int[] mSurfaceSize = new int[2];
-    private final FunctorsRunnable mFunctorsRunnable = new FunctorsRunnable();
 
     private long mDrawDelta = Long.MAX_VALUE;
 
@@ -654,6 +653,11 @@
     }
 
     @Override
+    void setOpaque(boolean opaque) {
+        // Not supported
+    }
+
+    @Override
     boolean loadSystemProperties() {
         boolean value;
         boolean changed = false;
@@ -1116,22 +1120,6 @@
         mName = name;
     }
 
-    class FunctorsRunnable implements Runnable {
-        View.AttachInfo attachInfo;
-
-        @Override
-        public void run() {
-            final HardwareRenderer renderer = attachInfo.mHardwareRenderer;
-            if (renderer == null || !renderer.isEnabled() || renderer != GLRenderer.this) {
-                return;
-            }
-
-            if (checkRenderContext() != SURFACE_STATE_ERROR) {
-                mCanvas.invokeFunctors(mRedrawClip);
-            }
-        }
-    }
-
     @Override
     void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
             Rect dirty) {
@@ -1366,23 +1354,6 @@
         }
     }
 
-    @Override
-    void detachFunctor(long functor) {
-        if (mCanvas != null) {
-            mCanvas.detachFunctor(functor);
-        }
-    }
-
-    @Override
-    void attachFunctor(View.AttachInfo attachInfo, long functor) {
-        if (mCanvas != null) {
-            mCanvas.attachFunctor(functor);
-            mFunctorsRunnable.attachInfo = attachInfo;
-            attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
-            attachInfo.mHandler.postDelayed(mFunctorsRunnable,  0);
-        }
-    }
-
     /**
      * Ensures the current EGL context and surface are the ones we expect.
      * This method throws an IllegalStateException if invoked from a thread
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index 233f846..9568760 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -18,6 +18,7 @@
 
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.CanvasProperty;
 import android.graphics.Paint;
 import android.graphics.Rect;
 
@@ -110,45 +111,6 @@
     }
 
     /**
-     * Invoke all the functors who requested to be invoked during the previous frame.
-     *
-     * @param dirty Ignored
-     *
-     * @return Ignored
-     *
-     * @hide
-     */
-    public int invokeFunctors(Rect dirty) {
-        return RenderNode.STATUS_DONE;
-    }
-
-    /**
-     * Detaches the specified functor from the current functor execution queue.
-     *
-     * @param functor The native functor to remove from the execution queue.
-     *
-     * @see #invokeFunctors(android.graphics.Rect)
-     * @see #callDrawGLFunction(long)
-     * @see #detachFunctor(long)
-     *
-     * @hide
-     */
-    abstract void detachFunctor(long functor);
-
-    /**
-     * Attaches the specified functor to the current functor execution queue.
-     *
-     * @param functor The native functor to add to the execution queue.
-     *
-     * @see #invokeFunctors(android.graphics.Rect)
-     * @see #callDrawGLFunction(long)
-     * @see #detachFunctor(long)
-     *
-     * @hide
-     */
-    abstract void attachFunctor(long functor);
-
-    /**
      * Indicates that the specified layer must be updated as soon as possible.
      *
      * @param layer The layer to update
@@ -189,4 +151,7 @@
      * @hide
      */
     abstract void clearLayerUpdates();
+
+    public abstract void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
+            CanvasProperty<Float> radius, CanvasProperty<Paint> paint);
 }
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index d31c79d..e366697 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -423,28 +423,6 @@
     abstract boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap);
 
     /**
-     * Detaches the specified functor from the current functor execution queue.
-     *
-     * @param functor The native functor to remove from the execution queue.
-     *
-     * @see HardwareCanvas#callDrawGLFunction(int)
-     * @see #attachFunctor(android.view.View.AttachInfo, long)
-     */
-    abstract void detachFunctor(long functor);
-
-    /**
-     * Schedules the specified functor in the functors execution queue.
-     *
-     * @param attachInfo AttachInfo tied to this renderer.
-     * @param functor The native functor to insert in the execution queue.
-     *
-     * @see HardwareCanvas#callDrawGLFunction(int)
-     * @see #detachFunctor(long)
-     *
-     */
-    abstract void attachFunctor(View.AttachInfo attachInfo, long functor);
-
-    /**
      * Schedules the functor for execution in either kModeProcess or
      * kModeProcessNoContext, depending on whether or not there is an EGLContext.
      *
@@ -491,6 +469,11 @@
     abstract void setName(String name);
 
     /**
+     * Change the HardwareRenderer's opacity
+     */
+    abstract void setOpaque(boolean opaque);
+
+    /**
      * Creates a hardware renderer using OpenGL.
      *
      * @param translucent True if the surface is translucent, false otherwise
diff --git a/core/java/android/view/InputEventConsistencyVerifier.java b/core/java/android/view/InputEventConsistencyVerifier.java
index 5dda934..c5e4c21 100644
--- a/core/java/android/view/InputEventConsistencyVerifier.java
+++ b/core/java/android/view/InputEventConsistencyVerifier.java
@@ -113,7 +113,7 @@
      * @param flags Flags to the verifier, or 0 if none.
      */
     public InputEventConsistencyVerifier(Object caller, int flags) {
-        this(caller, flags, InputEventConsistencyVerifier.class.getSimpleName());
+        this(caller, flags, null);
     }
 
     /**
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 05e202b..852fce5 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1685,10 +1685,6 @@
             case KeyEvent.KEYCODE_BRIGHTNESS_DOWN:
             case KeyEvent.KEYCODE_BRIGHTNESS_UP:
             case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
-            case KeyEvent.KEYCODE_DPAD_UP:
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-            case KeyEvent.KEYCODE_DPAD_DOWN:
-            case KeyEvent.KEYCODE_DPAD_LEFT:
                 return true;
         }
 
@@ -2702,10 +2698,10 @@
     public static int keyCodeFromString(String symbolicName) {
         if (symbolicName.startsWith(LABEL_PREFIX)) {
             symbolicName = symbolicName.substring(LABEL_PREFIX.length());
-        }
-        int keyCode = nativeKeyCodeFromString(symbolicName);
-        if (keyCode > 0) {
-            return keyCode;
+            int keyCode = nativeKeyCodeFromString(symbolicName);
+            if (keyCode > 0) {
+                return keyCode;
+            }
         }
         try {
             return Integer.parseInt(symbolicName, 10);
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index e19bda9..b9ed801 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -21,13 +21,16 @@
 import android.os.Message;
 import android.os.Trace;
 import android.widget.FrameLayout;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.Xml;
 
 import java.io.IOException;
@@ -61,7 +64,8 @@
  * @see Context#getSystemService
  */
 public abstract class LayoutInflater {
-    private final boolean DEBUG = false;
+    private static final String TAG = LayoutInflater.class.getSimpleName();
+    private static final boolean DEBUG = false;
 
     /**
      * This field should be made private, so it is hidden from the SDK.
@@ -395,8 +399,13 @@
      *         the inflated XML file.
      */
     public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
-        if (DEBUG) System.out.println("INFLATING from resource: " + resource);
-        XmlResourceParser parser = getContext().getResources().getLayout(resource);
+        final Resources res = getContext().getResources();
+        if (DEBUG) {
+            Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
+                    + Integer.toHexString(resource) + ")");
+        }
+
+        final XmlResourceParser parser = res.getLayout(resource);
         try {
             return inflate(parser, root, attachToRoot);
         } finally {
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 0626ab9..7f2defda 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -3070,10 +3070,10 @@
     public static int axisFromString(String symbolicName) {
         if (symbolicName.startsWith(LABEL_PREFIX)) {
             symbolicName = symbolicName.substring(LABEL_PREFIX.length());
-        }
-        int axis = nativeAxisFromString(symbolicName);
-        if (axis >= 0) {
-            return axis;
+            int axis = nativeAxisFromString(symbolicName);
+            if (axis >= 0) {
+                return axis;
+            }
         }
         try {
             return Integer.parseInt(symbolicName, 10);
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 8b80c3e0..0cfde94 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -239,7 +239,7 @@
      * @see #isValid()
      */
     public HardwareCanvas start(int width, int height) {
-        HardwareCanvas canvas = GLES20RecordingCanvas.obtain();
+        HardwareCanvas canvas = GLES20RecordingCanvas.obtain(this);
         canvas.setViewport(width, height);
         // The dirty rect should always be null for a display list
         canvas.onPreDraw(null);
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index b70ae3d..ec4d560 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -16,7 +16,17 @@
 
 package android.view;
 
+import android.animation.TimeInterpolator;
+import android.graphics.Canvas;
+import android.graphics.CanvasProperty;
+import android.graphics.Paint;
 import android.util.SparseIntArray;
+import android.util.TimeUtils;
+
+import com.android.internal.util.VirtualRefBasePtr;
+import com.android.internal.view.animation.FallbackLUTInterpolator;
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
 
 import java.lang.ref.WeakReference;
 
@@ -26,18 +36,22 @@
 public final class RenderNodeAnimator {
 
     // Keep in sync with enum RenderProperty in Animator.h
-    private static final int TRANSLATION_X = 0;
-    private static final int TRANSLATION_Y = 1;
-    private static final int TRANSLATION_Z = 2;
-    private static final int SCALE_X = 3;
-    private static final int SCALE_Y = 4;
-    private static final int ROTATION = 5;
-    private static final int ROTATION_X = 6;
-    private static final int ROTATION_Y = 7;
-    private static final int X = 8;
-    private static final int Y = 9;
-    private static final int Z = 10;
-    private static final int ALPHA = 11;
+    public static final int TRANSLATION_X = 0;
+    public static final int TRANSLATION_Y = 1;
+    public static final int TRANSLATION_Z = 2;
+    public static final int SCALE_X = 3;
+    public static final int SCALE_Y = 4;
+    public static final int ROTATION = 5;
+    public static final int ROTATION_X = 6;
+    public static final int ROTATION_Y = 7;
+    public static final int X = 8;
+    public static final int Y = 9;
+    public static final int Z = 10;
+    public static final int ALPHA = 11;
+
+    // Keep in sync with enum PaintFields in Animator.h
+    public static final int PAINT_STROKE_WIDTH = 0;
+    public static final int PAINT_ALPHA = 1;
 
     // ViewPropertyAnimator uses a mask for its values, we need to remap them
     // to the enum values here. RenderPropertyAnimator can't use the mask values
@@ -59,38 +73,100 @@
     }};
 
     // Keep in sync DeltaValueType in Animator.h
-    private static final int DELTA_TYPE_ABSOLUTE = 0;
-    private static final int DELTA_TYPE_DELTA = 1;
+    public static final int DELTA_TYPE_ABSOLUTE = 0;
+    public static final int DELTA_TYPE_DELTA = 1;
+
+    private VirtualRefBasePtr mNativePtr;
 
     private RenderNode mTarget;
-    private long mNativePtr;
+    private TimeInterpolator mInterpolator;
+    private boolean mStarted = false;
 
     public int mapViewPropertyToRenderProperty(int viewProperty) {
         return sViewPropertyAnimatorMap.get(viewProperty);
     }
 
     public RenderNodeAnimator(int property, int deltaType, float deltaValue) {
-        mNativePtr = nCreateAnimator(new WeakReference<RenderNodeAnimator>(this),
-                property, deltaType, deltaValue);
+        init(nCreateAnimator(new WeakReference<RenderNodeAnimator>(this),
+                property, deltaType, deltaValue));
+    }
+
+    public RenderNodeAnimator(CanvasProperty<Float> property, int deltaType, float deltaValue) {
+        init(nCreateCanvasPropertyFloatAnimator(
+                new WeakReference<RenderNodeAnimator>(this),
+                property.getNativeContainer(), deltaType, deltaValue));
+    }
+
+    public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField,
+            int deltaType, float deltaValue) {
+        init(nCreateCanvasPropertyPaintAnimator(
+                new WeakReference<RenderNodeAnimator>(this),
+                property.getNativeContainer(), paintField, deltaType, deltaValue));
+    }
+
+    private void init(long ptr) {
+        mNativePtr = new VirtualRefBasePtr(ptr);
+    }
+
+    private void checkMutable() {
+        if (mStarted) {
+            throw new IllegalStateException("Animator has already started, cannot change it now!");
+        }
+    }
+
+    private void applyInterpolator() {
+        if (mInterpolator == null) return;
+
+        long ni;
+        if (mInterpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class)) {
+            ni = ((NativeInterpolatorFactory)mInterpolator).createNativeInterpolator();
+        } else {
+            int duration = nGetDuration(mNativePtr.get());
+            ni = FallbackLUTInterpolator.createNativeInterpolator(mInterpolator, duration);
+        }
+        nSetInterpolator(mNativePtr.get(), ni);
+    }
+
+    private void start(RenderNode node) {
+        if (mStarted) {
+            throw new IllegalStateException("Already started!");
+        }
+        mStarted = true;
+        applyInterpolator();
+        mTarget = node;
+        mTarget.addAnimator(this);
     }
 
     public void start(View target) {
-        mTarget = target.mRenderNode;
-        mTarget.addAnimator(this);
+        start(target.mRenderNode);
         // Kick off a frame to start the process
         target.invalidateViewProperty(true, false);
     }
 
+    public void start(Canvas canvas) {
+        if (!(canvas instanceof GLES20RecordingCanvas)) {
+            throw new IllegalArgumentException("Not a GLES20RecordingCanvas");
+        }
+        GLES20RecordingCanvas recordingCanvas = (GLES20RecordingCanvas) canvas;
+        start(recordingCanvas.mNode);
+    }
+
     public void cancel() {
         mTarget.removeAnimator(this);
     }
 
     public void setDuration(int duration) {
-        nSetDuration(mNativePtr, duration);
+        checkMutable();
+        nSetDuration(mNativePtr.get(), duration);
+    }
+
+    public void setInterpolator(TimeInterpolator interpolator) {
+        checkMutable();
+        mInterpolator = interpolator;
     }
 
     long getNativeAnimator() {
-        return mNativePtr;
+        return mNativePtr.get();
     }
 
     private void onFinished() {
@@ -105,18 +181,13 @@
         }
     }
 
-    @Override
-    protected void finalize() throws Throwable {
-        try {
-            nUnref(mNativePtr);
-            mNativePtr = 0;
-        } finally {
-            super.finalize();
-        }
-    }
-
     private static native long nCreateAnimator(WeakReference<RenderNodeAnimator> weakThis,
             int property, int deltaValueType, float deltaValue);
+    private static native long nCreateCanvasPropertyFloatAnimator(WeakReference<RenderNodeAnimator> weakThis,
+            long canvasProperty, int deltaValueType, float deltaValue);
+    private static native long nCreateCanvasPropertyPaintAnimator(WeakReference<RenderNodeAnimator> weakThis,
+            long canvasProperty, int paintField, int deltaValueType, float deltaValue);
     private static native void nSetDuration(long nativePtr, int duration);
-    private static native void nUnref(long nativePtr);
+    private static native int nGetDuration(long nativePtr);
+    private static native void nSetInterpolator(long animPtr, long interpolatorPtr);
 }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 2d55a01..c15ce44 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -74,8 +74,10 @@
             IBinder displayToken, int orientation,
             int l, int t, int r, int b,
             int L, int T, int R, int B);
-    private static native boolean nativeGetDisplayInfo(
-            IBinder displayToken, SurfaceControl.PhysicalDisplayInfo outInfo);
+    private static native SurfaceControl.PhysicalDisplayInfo[] nativeGetDisplayConfigs(
+            IBinder displayToken);
+    private static native int nativeGetActiveConfig(IBinder displayToken);
+    private static native boolean nativeSetActiveConfig(IBinder displayToken, int id);
     private static native void nativeBlankDisplay(IBinder displayToken);
     private static native void nativeUnblankDisplay(IBinder displayToken);
 
@@ -499,14 +501,25 @@
         nativeBlankDisplay(displayToken);
     }
 
-    public static boolean getDisplayInfo(IBinder displayToken, SurfaceControl.PhysicalDisplayInfo outInfo) {
+    public static SurfaceControl.PhysicalDisplayInfo[] getDisplayConfigs(IBinder displayToken) {
         if (displayToken == null) {
             throw new IllegalArgumentException("displayToken must not be null");
         }
-        if (outInfo == null) {
-            throw new IllegalArgumentException("outInfo must not be null");
+        return nativeGetDisplayConfigs(displayToken);
+    }
+
+    public static int getActiveConfig(IBinder displayToken) {
+        if (displayToken == null) {
+            throw new IllegalArgumentException("displayToken must not be null");
         }
-        return nativeGetDisplayInfo(displayToken, outInfo);
+        return nativeGetActiveConfig(displayToken);
+    }
+
+    public static boolean setActiveConfig(IBinder displayToken, int id) {
+        if (displayToken == null) {
+            throw new IllegalArgumentException("displayToken must not be null");
+        }
+        return nativeSetActiveConfig(displayToken, id);
     }
 
     public static void setDisplayProjection(IBinder displayToken,
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 3cfe5e9..1765c43 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -23,7 +23,6 @@
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
-import android.os.Looper;
 import android.util.AttributeSet;
 import android.util.Log;
 
@@ -119,8 +118,6 @@
     private boolean mUpdateLayer;
     private boolean mUpdateSurface;
 
-    private SurfaceTexture.OnFrameAvailableListener mUpdateListener;
-
     private Canvas mCanvas;
     private int mSaveCount;
 
@@ -370,21 +367,7 @@
             mSurface.setDefaultBufferSize(getWidth(), getHeight());
             nCreateNativeWindow(mSurface);
 
-            mUpdateListener = new SurfaceTexture.OnFrameAvailableListener() {
-                @Override
-                public void onFrameAvailable(SurfaceTexture surfaceTexture) {
-                    // Per SurfaceTexture's documentation, the callback may be invoked
-                    // from an arbitrary thread
-                    updateLayer();
-
-                    if (Looper.myLooper() == Looper.getMainLooper()) {
-                        invalidate();
-                    } else {
-                        postInvalidate();
-                    }
-                }
-            };
-            mSurface.setOnFrameAvailableListener(mUpdateListener);
+            mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
 
             if (mListener != null && !mUpdateSurface) {
                 mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight());
@@ -422,7 +405,7 @@
             // To cancel updates, the easiest thing to do is simply to remove the
             // updates listener
             if (visibility == VISIBLE) {
-                mSurface.setOnFrameAvailableListener(mUpdateListener);
+                mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
                 updateLayerAndInvalidate();
             } else {
                 mSurface.setOnFrameAvailableListener(null);
@@ -767,6 +750,15 @@
         mListener = listener;
     }
 
+    private final SurfaceTexture.OnFrameAvailableListener mUpdateListener =
+            new SurfaceTexture.OnFrameAvailableListener() {
+        @Override
+        public void onFrameAvailable(SurfaceTexture surfaceTexture) {
+            updateLayer();
+            invalidate();
+        }
+    };
+
     /**
      * This listener can be used to be notified when the surface texture
      * associated with this texture view is available.
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index eaec8ab..17035b1 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -19,8 +19,12 @@
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
-import android.os.SystemClock;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.Trace;
+import android.util.Log;
+import android.util.TimeUtils;
 import android.view.Surface.OutOfResourcesException;
 import android.view.View.AttachInfo;
 
@@ -52,16 +56,29 @@
 
     private static final Rect NULL_RECT = new Rect();
 
+    // Keep in sync with DrawFrameTask.h SYNC_* flags
+    // Nothing interesting to report
+    private static final int SYNC_OK = 0x0;
+    // Needs a ViewRoot invalidate
+    private static final int SYNC_INVALIDATE_REQUIRED = 0x1;
+
     private int mWidth, mHeight;
     private long mNativeProxy;
     private boolean mInitialized = false;
     private RenderNode mRootNode;
+    private Choreographer mChoreographer;
 
     ThreadedRenderer(boolean translucent) {
+        AtlasInitializer.sInstance.init();
+
         long rootNodePtr = nCreateRootRenderNode();
         mRootNode = RenderNode.adopt(rootNodePtr);
         mRootNode.setClipToBounds(false);
         mNativeProxy = nCreateProxy(translucent, rootNodePtr);
+
+        // Setup timing
+        mChoreographer = Choreographer.getInstance();
+        nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos());
     }
 
     @Override
@@ -136,6 +153,11 @@
     }
 
     @Override
+    void setOpaque(boolean opaque) {
+        nSetOpaque(mNativeProxy, opaque);
+    }
+
+    @Override
     int getWidth() {
         return mWidth;
     }
@@ -158,16 +180,7 @@
 
     @Override
     boolean loadSystemProperties() {
-        return false;
-    }
-
-    /**
-     * TODO: Remove
-     * Temporary hack to allow RenderThreadTest prototype app to trigger
-     * replaying a DisplayList after modifying the displaylist properties
-     *
-     *  @hide */
-    public void repeatLastDraw() {
+        return nLoadSystemProperties(mNativeProxy);
     }
 
     private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
@@ -194,7 +207,8 @@
     @Override
     void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) {
         attachInfo.mIgnoreDirtyState = true;
-        attachInfo.mDrawingTime = SystemClock.uptimeMillis();
+        long frameTimeNanos = mChoreographer.getFrameTimeNanos();
+        attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS;
 
         updateRootDisplayList(view, callbacks);
 
@@ -203,17 +217,11 @@
         if (dirty == null) {
             dirty = NULL_RECT;
         }
-        nSyncAndDrawFrame(mNativeProxy, dirty.left, dirty.top, dirty.right, dirty.bottom);
-    }
-
-    @Override
-    void detachFunctor(long functor) {
-        // no-op, we never attach functors to need to detach them
-    }
-
-    @Override
-    void attachFunctor(AttachInfo attachInfo, long functor) {
-        invokeFunctor(functor, true);
+        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
+                dirty.left, dirty.top, dirty.right, dirty.bottom);
+        if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
+            attachInfo.mViewRootImpl.invalidate();
+        }
     }
 
     @Override
@@ -290,20 +298,59 @@
         }
     }
 
-    /** @hide */
-    public static native void postToRenderThread(Runnable runnable);
+    private static class AtlasInitializer {
+        static AtlasInitializer sInstance = new AtlasInitializer();
+
+        private boolean mInitialized = false;
+
+        private AtlasInitializer() {}
+
+        synchronized void init() {
+            if (mInitialized) return;
+            IBinder binder = ServiceManager.getService("assetatlas");
+            if (binder == null) return;
+
+            IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
+            try {
+                if (atlas.isCompatible(android.os.Process.myPpid())) {
+                    GraphicBuffer buffer = atlas.getBuffer();
+                    if (buffer != null) {
+                        long[] map = atlas.getMap();
+                        if (map != null) {
+                            nSetAtlas(buffer, map);
+                            mInitialized = true;
+                        }
+                        // If IAssetAtlas is not the same class as the IBinder
+                        // we are using a remote service and we can safely
+                        // destroy the graphic buffer
+                        if (atlas.getClass() != binder.getClass()) {
+                            buffer.destroy();
+                        }
+                    }
+                }
+            } catch (RemoteException e) {
+                Log.w(LOG_TAG, "Could not acquire atlas", e);
+            }
+        }
+    }
+
+    private static native void nSetAtlas(GraphicBuffer buffer, long[] map);
 
     private static native long nCreateRootRenderNode();
     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 boolean nInitialize(long nativeProxy, Surface window);
     private static native void nUpdateSurface(long nativeProxy, Surface window);
     private static native void nPauseSurface(long nativeProxy, Surface window);
     private static native void nSetup(long nativeProxy, int width, int height);
+    private static native void nSetOpaque(long nativeProxy, boolean opaque);
     private static native void nSetDisplayListData(long nativeProxy, long displayList,
             long newData);
-    private static native void nSyncAndDrawFrame(long nativeProxy,
+    private static native int nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos,
             int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
     private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
     private static native void nDestroyCanvasAndSurface(long nativeProxy);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 85e3b3d..e829141 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,7 +16,9 @@
 
 package android.view;
 
+import android.animation.AnimatorInflater;
 import android.animation.RevealAnimator;
+import android.animation.StateListAnimator;
 import android.animation.ValueAnimator;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -667,7 +669,8 @@
  * @attr ref android.R.styleable#View_scrollbarTrackVertical
  * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack
  * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack
- * @attr ref android.R.styleable#View_sharedElementName
+ * @attr ref android.R.styleable#View_stateListAnimator
+ * @attr ref android.R.styleable#View_viewName
  * @attr ref android.R.styleable#View_soundEffectsEnabled
  * @attr ref android.R.styleable#View_tag
  * @attr ref android.R.styleable#View_textAlignment
@@ -3182,6 +3185,8 @@
     private int mBackgroundResource;
     private boolean mBackgroundSizeChanged;
 
+    private String mViewName;
+
     static class ListenerInfo {
         /**
          * Listener used to dispatch focus change events.
@@ -3258,6 +3263,11 @@
     private Outline mOutline;
 
     /**
+     * Animator that automatically runs based on state changes.
+     */
+    private StateListAnimator mStateListAnimator;
+
+    /**
      * When this view has focus and the next focus is {@link #FOCUS_LEFT},
      * the user may specify which view to go to next.
      */
@@ -3989,12 +3999,16 @@
                 case R.styleable.View_accessibilityLiveRegion:
                     setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT));
                     break;
-                case R.styleable.View_sharedElementName:
-                    setSharedElementName(a.getString(attr));
+                case R.styleable.View_viewName:
+                    setViewName(a.getString(attr));
                     break;
                 case R.styleable.View_nestedScrollingEnabled:
                     setNestedScrollingEnabled(a.getBoolean(attr, false));
                     break;
+                case R.styleable.View_stateListAnimator:
+                    setStateListAnimator(AnimatorInflater.loadStateListAnimator(context,
+                            a.getResourceId(attr, 0)));
+                    break;
             }
         }
 
@@ -6147,12 +6161,12 @@
             // call into it as a fallback in case we're in a class that overrides it
             // and has logic to perform.
             if (fitSystemWindows(insets.getSystemWindowInsets())) {
-                return insets.cloneWithSystemWindowInsetsConsumed();
+                return insets.consumeSystemWindowInsets();
             }
         } else {
             // We were called from within a direct call to fitSystemWindows.
             if (fitSystemWindowsInt(insets.getSystemWindowInsets())) {
-                return insets.cloneWithSystemWindowInsetsConsumed();
+                return insets.consumeSystemWindowInsets();
             }
         }
         return insets;
@@ -9766,6 +9780,7 @@
             invalidateViewProperty(false, true);
 
             invalidateParentIfNeededAndWasQuickRejected();
+            notifySubtreeAccessibilityStateChangedIfNeeded();
         }
     }
 
@@ -9809,6 +9824,7 @@
             invalidateViewProperty(false, true);
 
             invalidateParentIfNeededAndWasQuickRejected();
+            notifySubtreeAccessibilityStateChangedIfNeeded();
         }
     }
 
@@ -9852,6 +9868,7 @@
             invalidateViewProperty(false, true);
 
             invalidateParentIfNeededAndWasQuickRejected();
+            notifySubtreeAccessibilityStateChangedIfNeeded();
         }
     }
 
@@ -9887,6 +9904,7 @@
             invalidateViewProperty(false, true);
 
             invalidateParentIfNeededAndWasQuickRejected();
+            notifySubtreeAccessibilityStateChangedIfNeeded();
         }
     }
 
@@ -9922,6 +9940,7 @@
             invalidateViewProperty(false, true);
 
             invalidateParentIfNeededAndWasQuickRejected();
+            notifySubtreeAccessibilityStateChangedIfNeeded();
         }
     }
 
@@ -9958,7 +9977,7 @@
      * @attr ref android.R.styleable#View_transformPivotX
      */
     public void setPivotX(float pivotX) {
-        if (mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) {
+        if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) {
             invalidateViewProperty(true, false);
             mRenderNode.setPivotX(pivotX);
             invalidateViewProperty(false, true);
@@ -9999,7 +10018,7 @@
      * @attr ref android.R.styleable#View_transformPivotY
      */
     public void setPivotY(float pivotY) {
-        if (mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) {
+        if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) {
             invalidateViewProperty(true, false);
             mRenderNode.setPivotY(pivotY);
             invalidateViewProperty(false, true);
@@ -10083,6 +10102,8 @@
                 mPrivateFlags &= ~PFLAG_ALPHA_SET;
                 invalidateViewProperty(true, false);
                 mRenderNode.setAlpha(getFinalAlpha());
+                notifyViewAccessibilityStateChangedIfNeeded(
+                        AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
             }
         }
     }
@@ -10513,6 +10534,7 @@
             invalidateViewProperty(false, true);
 
             invalidateParentIfNeededAndWasQuickRejected();
+            notifySubtreeAccessibilityStateChangedIfNeeded();
         }
     }
 
@@ -10612,6 +10634,40 @@
     }
 
     /**
+     * Returns the current StateListAnimator if exists.
+     *
+     * @return StateListAnimator or null if it does not exists
+     * @see    #setStateListAnimator(android.animation.StateListAnimator)
+     */
+    public StateListAnimator getStateListAnimator() {
+        return mStateListAnimator;
+    }
+
+    /**
+     * Attaches the provided StateListAnimator to this View.
+     * <p>
+     * Any previously attached StateListAnimator will be detached.
+     *
+     * @param stateListAnimator The StateListAnimator to update the view
+     * @see {@link android.animation.StateListAnimator}
+     */
+    public void setStateListAnimator(StateListAnimator stateListAnimator) {
+        if (mStateListAnimator == stateListAnimator) {
+            return;
+        }
+        if (mStateListAnimator != null) {
+            mStateListAnimator.setTarget(null);
+        }
+        mStateListAnimator = stateListAnimator;
+        if (stateListAnimator != null) {
+            stateListAnimator.setTarget(this);
+            if (isAttachedToWindow()) {
+                stateListAnimator.setState(getDrawableState());
+            }
+        }
+    }
+
+    /**
      * Sets the outline of the view, which defines the shape of the shadow it
      * casts.
      * <p>
@@ -10661,6 +10717,7 @@
             } else {
                 mRenderNode.setOutline(null);
             }
+            notifySubtreeAccessibilityStateChangedIfNeeded();
         }
     }
 
@@ -10815,6 +10872,7 @@
                 }
                 invalidateParentIfNeeded();
             }
+            notifySubtreeAccessibilityStateChangedIfNeeded();
         }
     }
 
@@ -10861,6 +10919,7 @@
                 }
                 invalidateParentIfNeeded();
             }
+            notifySubtreeAccessibilityStateChangedIfNeeded();
         }
     }
 
@@ -12824,7 +12883,6 @@
         destroyLayer(false);
 
         cleanupDraw();
-
         mCurrentAnimation = null;
     }
 
@@ -15478,9 +15536,11 @@
     /**
      * This function is called whenever the state of the view changes in such
      * a way that it impacts the state of drawables being shown.
-     *
-     * <p>Be sure to call through to the superclass when overriding this
-     * function.
+     * <p>
+     * If the View has a StateListAnimator, it will also be called to run necessary state
+     * change animations.
+     * <p>
+     * Be sure to call through to the superclass when overriding this function.
      *
      * @see Drawable#setState(int[])
      */
@@ -15489,6 +15549,10 @@
         if (d != null && d.isStateful()) {
             d.setState(getDrawableState());
         }
+
+        if (mStateListAnimator != null) {
+            mStateListAnimator.setState(getDrawableState());
+        }
     }
 
     /**
@@ -15633,11 +15697,17 @@
     /**
      * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()}
      * on all Drawable objects associated with this view.
+     * <p>
+     * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator
+     * attached to this view.
      */
     public void jumpDrawablesToCurrentState() {
         if (mBackground != null) {
             mBackground.jumpToCurrentState();
         }
+        if (mStateListAnimator != null) {
+            mStateListAnimator.jumpToCurrentState();
+        }
     }
 
     /**
@@ -17989,7 +18059,9 @@
      *
      * <p>If this property is set to true the view will be permitted to initiate nested
      * scrolling operations with a compatible parent view in the current hierarchy. If this
-     * view does not implement nested scrolling this will have no effect.</p>
+     * view does not implement nested scrolling this will have no effect. Disabling nested scrolling
+     * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping}
+     * the nested scroll.</p>
      *
      * @param enabled true to enable nested scrolling, false to disable
      *
@@ -17999,6 +18071,7 @@
         if (enabled) {
             mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED;
         } else {
+            stopNestedScroll();
             mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED;
         }
     }
@@ -18138,23 +18211,29 @@
     public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,
             int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
         if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
-            int startX = 0;
-            int startY = 0;
-            if (offsetInWindow != null) {
-                getLocationInWindow(offsetInWindow);
-                startX = offsetInWindow[0];
-                startY = offsetInWindow[1];
-            }
+            if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) {
+                int startX = 0;
+                int startY = 0;
+                if (offsetInWindow != null) {
+                    getLocationInWindow(offsetInWindow);
+                    startX = offsetInWindow[0];
+                    startY = offsetInWindow[1];
+                }
 
-            mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed,
-                    dxUnconsumed, dyUnconsumed);
+                mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed,
+                        dxUnconsumed, dyUnconsumed);
 
-            if (offsetInWindow != null) {
-                getLocationInWindow(offsetInWindow);
-                offsetInWindow[0] -= startX;
-                offsetInWindow[1] -= startY;
+                if (offsetInWindow != null) {
+                    getLocationInWindow(offsetInWindow);
+                    offsetInWindow[0] -= startX;
+                    offsetInWindow[1] -= startY;
+                }
+                return true;
+            } else if (offsetInWindow != null) {
+                // No motion, no dispatch. Keep offsetInWindow up to date.
+                offsetInWindow[0] = 0;
+                offsetInWindow[1] = 0;
             }
-            return true;
         }
         return false;
     }
@@ -18180,30 +18259,35 @@
      */
     public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
         if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
-            int startX = 0;
-            int startY = 0;
-            if (offsetInWindow != null) {
-                getLocationInWindow(offsetInWindow);
-                startX = offsetInWindow[0];
-                startY = offsetInWindow[1];
-            }
-
-            if (consumed == null) {
-                if (mTempNestedScrollConsumed == null) {
-                    mTempNestedScrollConsumed = new int[2];
+            if (dx != 0 || dy != 0) {
+                int startX = 0;
+                int startY = 0;
+                if (offsetInWindow != null) {
+                    getLocationInWindow(offsetInWindow);
+                    startX = offsetInWindow[0];
+                    startY = offsetInWindow[1];
                 }
-                consumed = mTempNestedScrollConsumed;
-            }
-            consumed[0] = 0;
-            consumed[1] = 0;
-            mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed);
 
-            if (offsetInWindow != null) {
-                getLocationInWindow(offsetInWindow);
-                offsetInWindow[0] -= startX;
-                offsetInWindow[1] -= startY;
+                if (consumed == null) {
+                    if (mTempNestedScrollConsumed == null) {
+                        mTempNestedScrollConsumed = new int[2];
+                    }
+                    consumed = mTempNestedScrollConsumed;
+                }
+                consumed[0] = 0;
+                consumed[1] = 0;
+                mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed);
+
+                if (offsetInWindow != null) {
+                    getLocationInWindow(offsetInWindow);
+                    offsetInWindow[0] -= startX;
+                    offsetInWindow[1] -= startY;
+                }
+                return consumed[0] != 0 || consumed[1] != 0;
+            } else if (offsetInWindow != null) {
+                offsetInWindow[0] = 0;
+                offsetInWindow[1] = 0;
             }
-            return consumed[0] != 0 || consumed[1] != 0;
         }
         return false;
     }
@@ -18211,18 +18295,24 @@
     /**
      * Dispatch a fling to a nested scrolling parent.
      *
-     * <p>If a nested scrolling child view would normally fling but it is at the edge of its
-     * own content it should use this method to delegate the fling to its nested scrolling parent.
-     * The view implementation can use a {@link VelocityTracker} to obtain the velocity values
-     * to pass.</p>
+     * <p>This method should be used to indicate that a nested scrolling child has detected
+     * suitable conditions for a fling. Generally this means that a touch scroll has ended with a
+     * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds
+     * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity}
+     * along a scrollable axis.</p>
+     *
+     * <p>If a nested scrolling child view would normally fling but it is at the edge of
+     * its own content, it can use this method to delegate the fling to its nested scrolling
+     * parent instead. The parent may optionally consume the fling or observe a child fling.</p>
      *
      * @param velocityX Horizontal fling velocity in pixels per second
      * @param velocityY Vertical fling velocity in pixels per second
-     * @return true if the nested scrolling parent consumed the fling
+     * @param consumed true if the child consumed the fling, false otherwise
+     * @return true if the nested scrolling parent consumed or otherwise reacted to the fling
      */
-    public boolean dispatchNestedFling(float velocityX, float velocityY) {
+    public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
         if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
-            return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY);
+            return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed);
         }
         return false;
     }
@@ -18751,15 +18841,15 @@
     }
 
     /**
-     * Adds all Views that have {@link #getSharedElementName()} non-null to sharedElements.
-     * @param sharedElements Will contain all Views in the hierarchy having a shared element name.
+     * Adds all Views that have {@link #getViewName()} non-null to namedElements.
+     * @param namedElements Will contain all Views in the hierarchy having a view name.
      * @hide
      */
-    public void findSharedElements(Map<String, View> sharedElements) {
+    public void findNamedViews(Map<String, View> namedElements) {
         if (getVisibility() == VISIBLE) {
-            String sharedElementName = getSharedElementName();
-            if (sharedElementName != null) {
-                sharedElements.put(sharedElementName, this);
+            String viewName = getViewName();
+            if (viewName != null) {
+                namedElements.put(viewName, this);
             }
         }
     }
@@ -19159,32 +19249,26 @@
     }
 
     /**
-     * Specifies that the shared name of the View to be shared with another Activity.
-     * When transitioning between Activities, the name links a UI element in the starting
-     * Activity to UI element in the called Activity. Names should be unique in the
-     * View hierarchy.
+     * Sets the name of the View to be used to identify Views in Transitions.
+     * Names should be unique in the View hierarchy.
      *
-     * @param sharedElementName The cross-Activity View identifier. The called Activity will use
-     *                 the name to match the location with a View in its layout.
-     * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)
+     * @param viewName The name of the View to uniquely identify it for Transitions.
      */
-    public void setSharedElementName(String sharedElementName) {
-        setTagInternal(com.android.internal.R.id.shared_element_name, sharedElementName);
+    public final void setViewName(String viewName) {
+        mViewName = viewName;
     }
 
     /**
-     * Returns the shared name of the View to be shared with another Activity.
-     * When transitioning between Activities, the name links a UI element in the starting
-     * Activity to UI element in the called Activity. Names should be unique in the
-     * View hierarchy.
+     * Returns the name of the View to be used to identify Views in Transitions.
+     * Names should be unique in the View hierarchy.
      *
-     * <p>This returns null if the View is not a shared element or the name if it is.</p>
+     * <p>This returns null if the View has not been given a name.</p>
      *
-     * @return The name used for this View for cross-Activity transitions or null if
-     * this View has not been identified as shared.
+     * @return The name used of the View to be used to identify Views in Transitions or null
+     * if no name has been given.
      */
-    public String getSharedElementName() {
-        return (String) getTag(com.android.internal.R.id.shared_element_name);
+    public String getViewName() {
+        return mViewName;
     }
 
     /**
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 5112b9a..4e91ad4 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -234,6 +234,7 @@
     private final int mOverscrollDistance;
     private final int mOverflingDistance;
     private final boolean mFadingMarqueeEnabled;
+    private final long mGlobalActionsKeyTimeout;
 
     private boolean sHasPermanentMenuKey;
     private boolean sHasPermanentMenuKeySet;
@@ -261,6 +262,7 @@
         mOverscrollDistance = OVERSCROLL_DISTANCE;
         mOverflingDistance = OVERFLING_DISTANCE;
         mFadingMarqueeEnabled = true;
+        mGlobalActionsKeyTimeout = GLOBAL_ACTIONS_KEY_TIMEOUT;
     }
 
     /**
@@ -287,8 +289,6 @@
 
         mEdgeSlop = (int) (sizeAndDensity * EDGE_SLOP + 0.5f);
         mFadingEdgeLength = (int) (sizeAndDensity * FADING_EDGE_LENGTH + 0.5f);
-        mMinimumFlingVelocity = (int) (density * MINIMUM_FLING_VELOCITY + 0.5f);
-        mMaximumFlingVelocity = (int) (density * MAXIMUM_FLING_VELOCITY + 0.5f);
         mScrollbarSize = (int) (density * SCROLL_BAR_SIZE + 0.5f);
         mDoubleTapSlop = (int) (sizeAndDensity * DOUBLE_TAP_SLOP + 0.5f);
         mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f);
@@ -339,6 +339,13 @@
         mPagingTouchSlop = mTouchSlop * 2;
 
         mDoubleTapTouchSlop = mTouchSlop;
+
+        mMinimumFlingVelocity = res.getDimensionPixelSize(
+                com.android.internal.R.dimen.config_viewMinFlingVelocity);
+        mMaximumFlingVelocity = res.getDimensionPixelSize(
+                com.android.internal.R.dimen.config_viewMaxFlingVelocity);
+        mGlobalActionsKeyTimeout = res.getInteger(
+                com.android.internal.R.integer.config_globalActionsKeyTimeout);
     }
 
     /**
@@ -695,12 +702,26 @@
      *
      * @return how long a user needs to press the relevant key to bring up
      *   the global actions dialog.
+     * @deprecated This timeout should not be used by applications
      */
+    @Deprecated
     public static long getGlobalActionKeyTimeout() {
         return GLOBAL_ACTIONS_KEY_TIMEOUT;
     }
 
     /**
+     * The amount of time a user needs to press the relevant key to bring up
+     * the global actions dialog.
+     *
+     * @return how long a user needs to press the relevant key to bring up
+     *   the global actions dialog.
+     * @hide
+     */
+    public long getDeviceGlobalActionKeyTimeout() {
+        return mGlobalActionsKeyTimeout;
+    }
+
+    /**
      * The amount of friction applied to scrolls and flings.
      *
      * @return A scalar dimensionless value representing the coefficient of
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 8865ab4..92a42b7 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2301,13 +2301,13 @@
      * individually during the transition.
      * @return True if the ViewGroup should be acted on together during an Activity transition.
      * The default value is false when the background is null and true when the background
-     * is not null or if {@link #getSharedElementName()} is not null.
+     * is not null or if {@link #getViewName()} is not null.
      */
     public boolean isTransitionGroup() {
         if ((mGroupFlags & FLAG_IS_TRANSITION_GROUP_SET) != 0) {
             return ((mGroupFlags & FLAG_IS_TRANSITION_GROUP) != 0);
         } else {
-            return getBackground() != null || getSharedElementName() != null;
+            return getBackground() != null || getViewName() != null;
         }
     }
 
@@ -2342,7 +2342,6 @@
 
         if (disallowIntercept) {
             mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
-            stopNestedScroll();
         } else {
             mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
         }
@@ -4639,6 +4638,7 @@
         if (invalidate) {
             invalidateViewProperty(false, false);
         }
+        notifySubtreeAccessibilityStateChangedIfNeeded();
     }
 
     /**
@@ -5914,7 +5914,7 @@
      * @inheritDoc
      */
     @Override
-    public boolean onNestedFling(View target, float velocityX, float velocityY) {
+    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
         return false;
     }
 
@@ -5956,15 +5956,15 @@
 
     /** @hide */
     @Override
-    public void findSharedElements(Map<String, View> sharedElements) {
+    public void findNamedViews(Map<String, View> namedElements) {
         if (getVisibility() != VISIBLE) {
             return;
         }
-        super.findSharedElements(sharedElements);
+        super.findNamedViews(namedElements);
         int count = getChildCount();
         for (int i = 0; i < count; i++) {
             View child = getChildAt(i);
-            child.findSharedElements(sharedElements);
+            child.findNamedViews(namedElements);
         }
     }
 
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 3cd6449..588b9cd 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -512,14 +512,21 @@
     /**
      * Request a fling from a nested scroll.
      *
+     * <p>This method signifies that a nested scrolling child has detected suitable conditions
+     * for a fling. Generally this means that a touch scroll has ended with a
+     * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds
+     * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity}
+     * along a scrollable axis.</p>
+     *
      * <p>If a nested scrolling child view would normally fling but it is at the edge of
-     * its own content, it can delegate the fling to its nested scrolling parent instead.
-     * This method allows the parent to optionally consume the fling.</p>
+     * its own content, it can use this method to delegate the fling to its nested scrolling
+     * parent instead. The parent may optionally consume the fling or observe a child fling.</p>
      *
      * @param target View that initiated the nested scroll
      * @param velocityX Horizontal velocity in pixels per second.
      * @param velocityY Vertical velocity in pixels per second
-     * @return true if this parent consumed the fling
+     * @param consumed true if the child consumed the fling, false otherwise
+     * @return true if this parent consumed or otherwise reacted to the fling
      */
-    public boolean onNestedFling(View target, float velocityX, float velocityY);
+    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed);
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 14e422c..9b09d85 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -234,6 +234,7 @@
 
     InputStage mFirstInputStage;
     InputStage mFirstPostImeInputStage;
+    InputStage mSyntheticInputStage;
 
     boolean mWindowAttributesChanged = false;
     int mWindowAttributesChangesFlag = 0;
@@ -599,8 +600,8 @@
 
                 // Set up the input pipeline.
                 CharSequence counterSuffix = attrs.getTitle();
-                InputStage syntheticInputStage = new SyntheticInputStage();
-                InputStage viewPostImeStage = new ViewPostImeInputStage(syntheticInputStage);
+                mSyntheticInputStage = new SyntheticInputStage();
+                InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
                 InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
                         "aq:native-post-ime:" + counterSuffix);
                 InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
@@ -664,18 +665,9 @@
         mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(MSG_FLUSH_LAYER_UPDATES));
     }
 
-    public void attachFunctor(long functor) {
-        //noinspection SimplifiableIfStatement
-        if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
-            mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor);
-        }
-    }
-
     public void detachFunctor(long functor) {
+        // TODO: Make the resize buffer some other way to not need this block
         mBlockResizeBuffer = true;
-        if (mAttachInfo.mHardwareRenderer != null) {
-            mAttachInfo.mHardwareRenderer.detachFunctor(functor);
-        }
     }
 
     public boolean invokeFunctor(long functor, boolean waitForCompletion) {
@@ -718,12 +710,15 @@
 
             if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
                     && forceHwAccelerated)) {
-                // Don't enable hardware acceleration when we're not on the main thread
-                if (!HardwareRenderer.sSystemRendererDisabled &&
-                        Looper.getMainLooper() != Looper.myLooper()) {
-                    Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
-                            + "acceleration outside of the main thread, aborting");
-                    return;
+                if (!HardwareRenderer.sUseRenderThread) {
+                    // TODO: Delete
+                    // Don't enable hardware acceleration when we're not on the main thread
+                    if (!HardwareRenderer.sSystemRendererDisabled &&
+                            Looper.getMainLooper() != Looper.myLooper()) {
+                        Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
+                                + "acceleration outside of the main thread, aborting");
+                        return;
+                    }
                 }
 
                 if (mAttachInfo.mHardwareRenderer != null) {
@@ -2587,10 +2582,6 @@
      * @param canvas The canvas on which to draw.
      */
     private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
-        if (!mAttachInfo.mHasWindowFocus) {
-            return;
-        }
-
         final AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
         if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
             return;
@@ -3007,6 +2998,7 @@
     private final static int MSG_INVALIDATE_WORLD = 23;
     private final static int MSG_WINDOW_MOVED = 24;
     private final static int MSG_FLUSH_LAYER_UPDATES = 25;
+    private final static int MSG_SYNTHESIZE_INPUT_EVENT = 26;
 
     final class ViewRootHandler extends Handler {
         @Override
@@ -3056,6 +3048,8 @@
                     return "MSG_WINDOW_MOVED";
                 case MSG_FLUSH_LAYER_UPDATES:
                     return "MSG_FLUSH_LAYER_UPDATES";
+                case MSG_SYNTHESIZE_INPUT_EVENT:
+                    return "MSG_SYNTHESIZE_INPUT_EVENT";
             }
             return super.getMessageName(message);
         }
@@ -3218,6 +3212,10 @@
                 enqueueInputEvent(event, receiver, 0, true);
                 args.recycle();
             } break;
+            case MSG_SYNTHESIZE_INPUT_EVENT: {
+                InputEvent event = (InputEvent)msg.obj;
+                enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true);
+            } break;
             case MSG_DISPATCH_KEY_FROM_IME: {
                 if (LOCAL_LOGV) Log.v(
                     TAG, "Dispatching key "
@@ -3227,7 +3225,8 @@
                     // The IME is trying to say this event is from the
                     // system!  Bad bad bad!
                     //noinspection UnusedAssignment
-                    event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
+                    event = KeyEvent.changeFlags(event, event.getFlags() &
+                            ~KeyEvent.FLAG_FROM_SYSTEM);
                 }
                 enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
             } break;
@@ -4023,6 +4022,7 @@
         private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
         private final SyntheticTouchNavigationHandler mTouchNavigation =
                 new SyntheticTouchNavigationHandler();
+        private final SyntheticKeyboardHandler mKeyboard = new SyntheticKeyboardHandler();
 
         public SyntheticInputStage() {
             super(null);
@@ -4045,7 +4045,11 @@
                     mTouchNavigation.process(event);
                     return FINISH_HANDLED;
                 }
+            } else if ((q.mFlags & QueuedInputEvent.FLAG_UNHANDLED) != 0) {
+                mKeyboard.process((KeyEvent)q.mEvent);
+                return FINISH_HANDLED;
             }
+
             return FORWARD;
         }
 
@@ -4882,6 +4886,33 @@
         };
     }
 
+    final class SyntheticKeyboardHandler {
+        public void process(KeyEvent event) {
+            if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
+                return;
+            }
+
+            final KeyCharacterMap kcm = event.getKeyCharacterMap();
+            final int keyCode = event.getKeyCode();
+            final int metaState = event.getMetaState();
+
+            // Check for fallback actions specified by the key character map.
+            KeyCharacterMap.FallbackAction fallbackAction =
+                    kcm.getFallbackAction(keyCode, metaState);
+            if (fallbackAction != null) {
+                final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
+                KeyEvent fallbackEvent = KeyEvent.obtain(
+                        event.getDownTime(), event.getEventTime(),
+                        event.getAction(), fallbackAction.keyCode,
+                        event.getRepeatCount(), fallbackAction.metaState,
+                        event.getDeviceId(), event.getScanCode(),
+                        flags, event.getSource(), null);
+                fallbackAction.recycle();
+                enqueueInputEvent(fallbackEvent);
+            }
+        }
+    }
+
     /**
      * Returns true if the key is used for keyboard navigation.
      * @param keyEvent The key event.
@@ -5461,6 +5492,7 @@
         public static final int FLAG_FINISHED = 1 << 2;
         public static final int FLAG_FINISHED_HANDLED = 1 << 3;
         public static final int FLAG_RESYNTHESIZED = 1 << 4;
+        public static final int FLAG_UNHANDLED = 1 << 5;
 
         public QueuedInputEvent mNext;
 
@@ -5475,6 +5507,14 @@
             return mEvent instanceof MotionEvent
                     && mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER);
         }
+
+        public boolean shouldSendToSynthesizer() {
+            if ((mFlags & FLAG_UNHANDLED) != 0) {
+                return true;
+            }
+
+            return false;
+        }
     }
 
     private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
@@ -5578,7 +5618,13 @@
             mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
         }
 
-        InputStage stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
+        InputStage stage;
+        if (q.shouldSendToSynthesizer()) {
+            stage = mSyntheticInputStage;
+        } else {
+            stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
+        }
+
         if (stage != null) {
             stage.deliver(q);
         } else {
@@ -5810,43 +5856,29 @@
         mHandler.sendMessage(msg);
     }
 
+    public void synthesizeInputEvent(InputEvent event) {
+        Message msg = mHandler.obtainMessage(MSG_SYNTHESIZE_INPUT_EVENT, event);
+        msg.setAsynchronous(true);
+        mHandler.sendMessage(msg);
+    }
+
     public void dispatchKeyFromIme(KeyEvent event) {
         Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
         msg.setAsynchronous(true);
         mHandler.sendMessage(msg);
     }
 
-    public void dispatchUnhandledKey(KeyEvent event) {
-        if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
-            // Some fallback keys are decided by the ViewRoot as they might have special
-            // properties (e.g. are locale aware). These take precedence over fallbacks defined by
-            // the kcm.
-            final KeyCharacterMap kcm = event.getKeyCharacterMap();
-            final int keyCode = event.getKeyCode();
-            final int metaState = event.getMetaState();
-
-            // Check for fallback actions specified by the key character map.
-            KeyCharacterMap.FallbackAction fallbackAction =
-                    kcm.getFallbackAction(keyCode, metaState);
-            if (fallbackAction != null) {
-                final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
-                KeyEvent fallbackEvent = KeyEvent.obtain(
-                        event.getDownTime(), event.getEventTime(),
-                        event.getAction(), fallbackAction.keyCode,
-                        event.getRepeatCount(), fallbackAction.metaState,
-                        event.getDeviceId(), event.getScanCode(),
-                        flags, event.getSource(), null);
-                fallbackAction.recycle();
-                dispatchInputEvent(fallbackEvent);
-            }
-        }
-    }
-
+    /**
+     * Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events.
+     *
+     * Note that it is the responsibility of the caller of this API to recycle the InputEvent it
+     * passes in.
+     */
     public void dispatchUnhandledInputEvent(InputEvent event) {
-        if (event instanceof KeyEvent) {
-            dispatchUnhandledKey((KeyEvent) event);
-            return;
+        if (event instanceof MotionEvent) {
+            event = MotionEvent.obtain((MotionEvent) event);
         }
+        synthesizeInputEvent(event);
     }
 
     public void dispatchAppVisibility(boolean visible) {
@@ -6131,13 +6163,15 @@
     }
 
     @Override
-    public boolean onNestedFling(View target, float velocityX, float velocityY) {
+    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
         return false;
     }
 
     void changeCanvasOpacity(boolean opaque) {
-        // TODO(romainguy): recreate Canvas (software or hardware) to reflect the opacity change.
         Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque);
+        if (mAttachInfo.mHardwareRenderer != null) {
+            mAttachInfo.mHardwareRenderer.setOpaque(opaque);
+        }
     }
 
     class TakenSurfaceHolder extends BaseSurfaceHolder {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 9c44bd1..375f5e3 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -147,6 +147,7 @@
     
     private TypedArray mWindowStyle;
     private Callback mCallback;
+    private OnWindowDismissedCallback mOnWindowDismissedCallback;
     private WindowManager mWindowManager;
     private IBinder mAppToken;
     private String mAppName;
@@ -405,7 +406,10 @@
          * @param mode The mode that was just finished.
          */
         public void onActionModeFinished(ActionMode mode);
+    }
 
+    /** @hide */
+    public interface OnWindowDismissedCallback {
         /**
          * Called when a window is dismissed. This informs the callback that the
          * window is gone, and it should finish itself.
@@ -586,6 +590,18 @@
         return mCallback;
     }
 
+    /** @hide */
+    public final void setOnWindowDismissedCallback(OnWindowDismissedCallback dcb) {
+        mOnWindowDismissedCallback = dcb;
+    }
+
+    /** @hide */
+    public final void dispatchOnWindowDismissed() {
+        if (mOnWindowDismissedCallback != null) {
+            mOnWindowDismissedCallback.onWindowDismissed();
+        }
+    }
+
     /**
      * Take ownership of this window's surface.  The window's view hierarchy
      * will no longer draw into the surface, though it will otherwise continue
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 2160efe..294f472 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -29,7 +29,7 @@
  * @see View.OnApplyWindowInsetsListener
  * @see View#onApplyWindowInsets(WindowInsets)
  */
-public class WindowInsets {
+public final class WindowInsets {
     private Rect mSystemWindowInsets;
     private Rect mWindowDecorInsets;
     private Rect mTempRect;
@@ -151,6 +151,7 @@
      * This can include action bars, title bars, toolbars, etc.</p>
      *
      * @return The left window decor inset
+     * @hide pending API
      */
     public int getWindowDecorInsetLeft() {
         return mWindowDecorInsets.left;
@@ -164,6 +165,7 @@
      * This can include action bars, title bars, toolbars, etc.</p>
      *
      * @return The top window decor inset
+     * @hide pending API
      */
     public int getWindowDecorInsetTop() {
         return mWindowDecorInsets.top;
@@ -177,6 +179,7 @@
      * This can include action bars, title bars, toolbars, etc.</p>
      *
      * @return The right window decor inset
+     * @hide pending API
      */
     public int getWindowDecorInsetRight() {
         return mWindowDecorInsets.right;
@@ -190,6 +193,7 @@
      * This can include action bars, title bars, toolbars, etc.</p>
      *
      * @return The bottom window decor inset
+     * @hide pending API
      */
     public int getWindowDecorInsetBottom() {
         return mWindowDecorInsets.bottom;
@@ -217,6 +221,7 @@
      * This can include action bars, title bars, toolbars, etc.</p>
      *
      * @return true if any of the window decor inset values are nonzero
+     * @hide pending API
      */
     public boolean hasWindowDecorInsets() {
         return mWindowDecorInsets.left != 0 || mWindowDecorInsets.top != 0 ||
@@ -246,13 +251,28 @@
         return mIsRound;
     }
 
-    public WindowInsets cloneWithSystemWindowInsetsConsumed() {
+    /**
+     * Returns a copy of this WindowInsets with the system window insets fully consumed.
+     *
+     * @return A modified copy of this WindowInsets
+     */
+    public WindowInsets consumeSystemWindowInsets() {
         final WindowInsets result = new WindowInsets(this);
         result.mSystemWindowInsets = new Rect(0, 0, 0, 0);
         return result;
     }
 
-    public WindowInsets cloneWithSystemWindowInsetsConsumed(boolean left, boolean top,
+    /**
+     * Returns a copy of this WindowInsets with selected system window insets fully consumed.
+     *
+     * @param left true to consume the left system window inset
+     * @param top true to consume the top system window inset
+     * @param right true to consume the right system window inset
+     * @param bottom true to consume the bottom system window inset
+     * @return A modified copy of this WindowInsets
+     * @hide pending API
+     */
+    public WindowInsets consumeSystemWindowInsets(boolean left, boolean top,
             boolean right, boolean bottom) {
         if (left || top || right || bottom) {
             final WindowInsets result = new WindowInsets(this);
@@ -265,19 +285,36 @@
         return this;
     }
 
-    public WindowInsets cloneWithSystemWindowInsets(int left, int top, int right, int bottom) {
+    /**
+     * Returns a copy of this WindowInsets with selected system window insets replaced
+     * with new values.
+     *
+     * @param left New left inset in pixels
+     * @param top New top inset in pixels
+     * @param right New right inset in pixels
+     * @param bottom New bottom inset in pixels
+     * @return A modified copy of this WindowInsets
+     */
+    public WindowInsets replaceSystemWindowInsets(int left, int top,
+            int right, int bottom) {
         final WindowInsets result = new WindowInsets(this);
         result.mSystemWindowInsets = new Rect(left, top, right, bottom);
         return result;
     }
 
-    public WindowInsets cloneWithWindowDecorInsetsConsumed() {
+    /**
+     * @hide
+     */
+    public WindowInsets consumeWindowDecorInsets() {
         final WindowInsets result = new WindowInsets(this);
         result.mWindowDecorInsets.set(0, 0, 0, 0);
         return result;
     }
 
-    public WindowInsets cloneWithWindowDecorInsetsConsumed(boolean left, boolean top,
+    /**
+     * @hide
+     */
+    public WindowInsets consumeWindowDecorInsets(boolean left, boolean top,
             boolean right, boolean bottom) {
         if (left || top || right || bottom) {
             final WindowInsets result = new WindowInsets(this);
@@ -290,7 +327,10 @@
         return this;
     }
 
-    public WindowInsets cloneWithWindowDecorInsets(int left, int top, int right, int bottom) {
+    /**
+     * @hide
+     */
+    public WindowInsets replaceWindowDecorInsets(int left, int top, int right, int bottom) {
         final WindowInsets result = new WindowInsets(this);
         result.mWindowDecorInsets = new Rect(left, top, right, bottom);
         return result;
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index c524611..4fde1e4 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -443,8 +443,6 @@
     public final int OFF_BECAUSE_OF_USER = 2;
     /** Screen turned off because of timeout */
     public final int OFF_BECAUSE_OF_TIMEOUT = 3;
-    /** Screen turned off because of proximity sensor */
-    public final int OFF_BECAUSE_OF_PROX_SENSOR = 4;
 
     /** @hide */
     @IntDef({USER_ROTATION_FREE, USER_ROTATION_LOCKED})
@@ -900,23 +898,23 @@
     public int focusChangedLw(WindowState lastFocus, WindowState newFocus);
     
     /**
-     * Called after the screen turns off.
+     * Called when the device is going to sleep.
      *
      * @param why {@link #OFF_BECAUSE_OF_USER} or
      * {@link #OFF_BECAUSE_OF_TIMEOUT}.
      */
-    public void screenTurnedOff(int why);
+    public void goingToSleep(int why);
 
     public interface ScreenOnListener {
         void onScreenOn();
     }
 
     /**
-     * Called when the power manager would like to turn the screen on.
+     * Called when the device is waking up.
      * Must call back on the listener to tell it when the higher-level system
      * is ready for the screen to go on (i.e. the lock screen is shown).
      */
-    public void screenTurningOn(ScreenOnListener screenOnListener);
+    public void wakingUp(ScreenOnListener screenOnListener);
 
     /**
      * Return whether the screen is about to turn on or is currently on.
diff --git a/core/java/android/view/animation/AccelerateDecelerateInterpolator.java b/core/java/android/view/animation/AccelerateDecelerateInterpolator.java
index 158c56e..ed6949a 100644
--- a/core/java/android/view/animation/AccelerateDecelerateInterpolator.java
+++ b/core/java/android/view/animation/AccelerateDecelerateInterpolator.java
@@ -19,12 +19,17 @@
 import android.content.Context;
 import android.util.AttributeSet;
 
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
 /**
  * An interpolator where the rate of change starts and ends slowly but
  * accelerates through the middle.
  * 
  */
-public class AccelerateDecelerateInterpolator implements Interpolator {
+@HasNativeInterpolator
+public class AccelerateDecelerateInterpolator implements Interpolator, NativeInterpolatorFactory {
     public AccelerateDecelerateInterpolator() {
     }
     
@@ -35,4 +40,10 @@
     public float getInterpolation(float input) {
         return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
     }
+
+    /** @hide */
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactoryHelper.createAccelerateDecelerateInterpolator();
+    }
 }
diff --git a/core/java/android/view/animation/AccelerateInterpolator.java b/core/java/android/view/animation/AccelerateInterpolator.java
index dcab743..c08f348 100644
--- a/core/java/android/view/animation/AccelerateInterpolator.java
+++ b/core/java/android/view/animation/AccelerateInterpolator.java
@@ -20,12 +20,17 @@
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
 
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
 /**
  * An interpolator where the rate of change starts out slowly and 
  * and then accelerates.
  *
  */
-public class AccelerateInterpolator implements Interpolator {
+@HasNativeInterpolator
+public class AccelerateInterpolator implements Interpolator, NativeInterpolatorFactory {
     private final float mFactor;
     private final double mDoubleFactor;
 
@@ -64,4 +69,10 @@
             return (float)Math.pow(input, mDoubleFactor);
         }
     }
+
+    /** @hide */
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactoryHelper.createAccelerateInterpolator(mFactor);
+    }
 }
diff --git a/core/java/android/view/animation/AnticipateInterpolator.java b/core/java/android/view/animation/AnticipateInterpolator.java
index a6f110e..83a8007 100644
--- a/core/java/android/view/animation/AnticipateInterpolator.java
+++ b/core/java/android/view/animation/AnticipateInterpolator.java
@@ -20,10 +20,15 @@
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
 
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
 /**
  * An interpolator where the change starts backward then flings forward.
  */
-public class AnticipateInterpolator implements Interpolator {
+@HasNativeInterpolator
+public class AnticipateInterpolator implements Interpolator, NativeInterpolatorFactory {
     private final float mTension;
 
     public AnticipateInterpolator() {
@@ -53,4 +58,10 @@
         // a(t) = t * t * ((tension + 1) * t - tension)
         return t * t * ((mTension + 1) * t - mTension);
     }
+
+    /** @hide */
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactoryHelper.createAnticipateInterpolator(mTension);
+    }
 }
diff --git a/core/java/android/view/animation/AnticipateOvershootInterpolator.java b/core/java/android/view/animation/AnticipateOvershootInterpolator.java
index 3dc9722..1a8adfd 100644
--- a/core/java/android/view/animation/AnticipateOvershootInterpolator.java
+++ b/core/java/android/view/animation/AnticipateOvershootInterpolator.java
@@ -19,6 +19,11 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
+
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
 import static com.android.internal.R.styleable.AnticipateOvershootInterpolator_extraTension;
 import static com.android.internal.R.styleable.AnticipateOvershootInterpolator_tension;
 import static com.android.internal.R.styleable.AnticipateOvershootInterpolator;
@@ -27,7 +32,8 @@
  * An interpolator where the change starts backward then flings forward and overshoots
  * the target value and finally goes back to the final value.
  */
-public class AnticipateOvershootInterpolator implements Interpolator {
+@HasNativeInterpolator
+public class AnticipateOvershootInterpolator implements Interpolator, NativeInterpolatorFactory {
     private final float mTension;
 
     public AnticipateOvershootInterpolator() {
@@ -80,4 +86,10 @@
         if (t < 0.5f) return 0.5f * a(t * 2.0f, mTension);
         else return 0.5f * (o(t * 2.0f - 2.0f, mTension) + 2.0f);
     }
+
+    /** @hide */
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactoryHelper.createAnticipateOvershootInterpolator(mTension);
+    }
 }
diff --git a/core/java/android/view/animation/BounceInterpolator.java b/core/java/android/view/animation/BounceInterpolator.java
index ecf99a7..9d8ca90 100644
--- a/core/java/android/view/animation/BounceInterpolator.java
+++ b/core/java/android/view/animation/BounceInterpolator.java
@@ -19,10 +19,15 @@
 import android.content.Context;
 import android.util.AttributeSet;
 
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
 /**
  * An interpolator where the change bounces at the end.
  */
-public class BounceInterpolator implements Interpolator {
+@HasNativeInterpolator
+public class BounceInterpolator implements Interpolator, NativeInterpolatorFactory {
     public BounceInterpolator() {
     }
 
@@ -47,4 +52,10 @@
         else if (t < 0.9644f) return bounce(t - 0.8526f) + 0.9f;
         else return bounce(t - 1.0435f) + 0.95f;
     }
+
+    /** @hide */
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactoryHelper.createBounceInterpolator();
+    }
 }
\ No newline at end of file
diff --git a/core/java/android/view/animation/CycleInterpolator.java b/core/java/android/view/animation/CycleInterpolator.java
index d355c23..d1ebf05 100644
--- a/core/java/android/view/animation/CycleInterpolator.java
+++ b/core/java/android/view/animation/CycleInterpolator.java
@@ -20,12 +20,17 @@
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
 
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
 /**
  * Repeats the animation for a specified number of cycles. The
  * rate of change follows a sinusoidal pattern.
  *
  */
-public class CycleInterpolator implements Interpolator {
+@HasNativeInterpolator
+public class CycleInterpolator implements Interpolator, NativeInterpolatorFactory {
     public CycleInterpolator(float cycles) {
         mCycles = cycles;
     }
@@ -44,4 +49,10 @@
     }
     
     private float mCycles;
+
+    /** @hide */
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactoryHelper.createCycleInterpolator(mCycles);
+    }
 }
diff --git a/core/java/android/view/animation/DecelerateInterpolator.java b/core/java/android/view/animation/DecelerateInterpolator.java
index 20e079b..0789a0e 100644
--- a/core/java/android/view/animation/DecelerateInterpolator.java
+++ b/core/java/android/view/animation/DecelerateInterpolator.java
@@ -20,12 +20,17 @@
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
 
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
 /**
  * An interpolator where the rate of change starts out quickly and 
  * and then decelerates.
  *
  */
-public class DecelerateInterpolator implements Interpolator {
+@HasNativeInterpolator
+public class DecelerateInterpolator implements Interpolator, NativeInterpolatorFactory {
     public DecelerateInterpolator() {
     }
 
@@ -60,4 +65,10 @@
     }
     
     private float mFactor = 1.0f;
+
+    /** @hide */
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactoryHelper.createDecelerateInterpolator(mFactor);
+    }
 }
diff --git a/core/java/android/view/animation/LinearInterpolator.java b/core/java/android/view/animation/LinearInterpolator.java
index 96a039f..552c611 100644
--- a/core/java/android/view/animation/LinearInterpolator.java
+++ b/core/java/android/view/animation/LinearInterpolator.java
@@ -19,11 +19,16 @@
 import android.content.Context;
 import android.util.AttributeSet;
 
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
 /**
  * An interpolator where the rate of change is constant
  *
  */
-public class LinearInterpolator implements Interpolator {
+@HasNativeInterpolator
+public class LinearInterpolator implements Interpolator, NativeInterpolatorFactory {
 
     public LinearInterpolator() {
     }
@@ -34,4 +39,10 @@
     public float getInterpolation(float input) {
         return input;
     }
+
+    /** @hide */
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactoryHelper.createLinearInterpolator();
+    }
 }
diff --git a/core/java/android/view/animation/OvershootInterpolator.java b/core/java/android/view/animation/OvershootInterpolator.java
index 494f8ab..a2466f1 100644
--- a/core/java/android/view/animation/OvershootInterpolator.java
+++ b/core/java/android/view/animation/OvershootInterpolator.java
@@ -20,11 +20,16 @@
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
 
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
 /**
  * An interpolator where the change flings forward and overshoots the last value
  * then comes back.
  */
-public class OvershootInterpolator implements Interpolator {
+@HasNativeInterpolator
+public class OvershootInterpolator implements Interpolator, NativeInterpolatorFactory {
     private final float mTension;
 
     public OvershootInterpolator() {
@@ -56,4 +61,10 @@
         t -= 1.0f;
         return t * t * ((mTension + 1) * t + mTension) + 1.0f;
     }
+
+    /** @hide */
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactoryHelper.createOvershootInterpolator(mTension);
+    }
 }
diff --git a/core/java/android/view/inputmethod/CorrectionInfo.java b/core/java/android/view/inputmethod/CorrectionInfo.java
index 1b04e49..a43dfe8 100644
--- a/core/java/android/view/inputmethod/CorrectionInfo.java
+++ b/core/java/android/view/inputmethod/CorrectionInfo.java
@@ -88,16 +88,15 @@
     /**
      * Used to make this class parcelable.
      */
-    public static final Parcelable.Creator<CorrectionInfo> CREATOR
-            = new Parcelable.Creator<CorrectionInfo>() {
-        public CorrectionInfo createFromParcel(Parcel source) {
-            return new CorrectionInfo(source);
-        }
-
-        public CorrectionInfo[] newArray(int size) {
-            return new CorrectionInfo[size];
-        }
-    };
+    public static final Parcelable.Creator<CorrectionInfo> CREATOR =
+            new Parcelable.Creator<CorrectionInfo>() {
+                public CorrectionInfo createFromParcel(Parcel source) {
+                    return new CorrectionInfo(source);
+                }
+                public CorrectionInfo[] newArray(int size) {
+                    return new CorrectionInfo[size];
+                }
+            };
 
     public int describeContents() {
         return 0;
diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.aidl b/core/java/android/view/inputmethod/CursorAnchorInfo.aidl
new file mode 100644
index 0000000..2ee9edb
--- /dev/null
+++ b/core/java/android/view/inputmethod/CursorAnchorInfo.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.view.inputmethod;
+
+parcelable CursorAnchorInfo;
diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java
new file mode 100644
index 0000000..60691b0
--- /dev/null
+++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java
@@ -0,0 +1,466 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view.inputmethod;
+
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.Layout;
+import android.view.inputmethod.SparseRectFArray.SparseRectFArrayBuilder;
+
+import java.util.Objects;
+
+/**
+ * Positional information about the text insertion point and characters in the composition string.
+ *
+ * <p>This class encapsulates locations of the text insertion point and the composition string in
+ * the screen coordinates so that IMEs can render their UI components near where the text is
+ * actually inserted.</p>
+ */
+public final class CursorAnchorInfo implements Parcelable {
+    private final int mSelectionStart;
+    private final int mSelectionEnd;
+
+    private final int mComposingTextStart;
+    /**
+     * The text, tracked as a composing region.
+     */
+    private final String mComposingText;
+
+    /**
+     * Horizontal position of the insertion marker, in the local coordinates that will be
+     * transformed with the transformation matrix when rendered on the screen. This should be
+     * calculated or compatible with {@link Layout#getPrimaryHorizontal(int)}. This can be
+     * {@code java.lang.Float.NaN} when no value is specified.
+     */
+    private final float mInsertionMarkerHorizontal;
+    /**
+     * Vertical position of the insertion marker, in the local coordinates that will be
+     * transformed with the transformation matrix when rendered on the screen. This should be
+     * calculated or compatible with {@link Layout#getLineTop(int)}. This can be
+     * {@code java.lang.Float.NaN} when no value is specified.
+     */
+    private final float mInsertionMarkerTop;
+    /**
+     * Vertical position of the insertion marker, in the local coordinates that will be
+     * transformed with the transformation matrix when rendered on the screen. This should be
+     * calculated or compatible with {@link Layout#getLineBaseline(int)}. This can be
+     * {@code java.lang.Float.NaN} when no value is specified.
+     */
+    private final float mInsertionMarkerBaseline;
+    /**
+     * Vertical position of the insertion marker, in the local coordinates that will be
+     * transformed with the transformation matrix when rendered on the screen. This should be
+     * calculated or compatible with {@link Layout#getLineBottom(int)}. This can be
+     * {@code java.lang.Float.NaN} when no value is specified.
+     */
+    private final float mInsertionMarkerBottom;
+
+    /**
+     * Container of rectangular position of characters, keyed with character index in a unit of
+     * Java chars, in the local coordinates that will be transformed with the transformation matrix
+     * when rendered on the screen.
+     */
+    private final SparseRectFArray mCharacterRects;
+
+    /**
+     * Transformation matrix that is applied to any positional information of this class to
+     * transform local coordinates into screen coordinates.
+     */
+    private final Matrix mMatrix;
+
+    public CursorAnchorInfo(final Parcel source) {
+        mSelectionStart = source.readInt();
+        mSelectionEnd = source.readInt();
+        mComposingTextStart = source.readInt();
+        mComposingText = source.readString();
+        mInsertionMarkerHorizontal = source.readFloat();
+        mInsertionMarkerTop = source.readFloat();
+        mInsertionMarkerBaseline = source.readFloat();
+        mInsertionMarkerBottom = source.readFloat();
+        mCharacterRects = source.readParcelable(SparseRectFArray.class.getClassLoader());
+        mMatrix = new Matrix();
+        mMatrix.setValues(source.createFloatArray());
+    }
+
+    /**
+     * Used to package this object into a {@link Parcel}.
+     *
+     * @param dest The {@link Parcel} to be written.
+     * @param flags The flags used for parceling.
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mSelectionStart);
+        dest.writeInt(mSelectionEnd);
+        dest.writeInt(mComposingTextStart);
+        dest.writeString(mComposingText);
+        dest.writeFloat(mInsertionMarkerHorizontal);
+        dest.writeFloat(mInsertionMarkerTop);
+        dest.writeFloat(mInsertionMarkerBaseline);
+        dest.writeFloat(mInsertionMarkerBottom);
+        dest.writeParcelable(mCharacterRects, flags);
+        final float[] matrixArray = new float[9];
+        mMatrix.getValues(matrixArray);
+        dest.writeFloatArray(matrixArray);
+    }
+
+    @Override
+    public int hashCode(){
+        // TODO: Improve the hash function.
+        final float floatHash = mInsertionMarkerHorizontal + mInsertionMarkerTop
+                + mInsertionMarkerBaseline + mInsertionMarkerBottom;
+        int hash = floatHash > 0 ? (int) floatHash : (int)(-floatHash);
+        hash *= 31;
+        hash += mSelectionStart + mSelectionEnd + mComposingTextStart;
+        hash *= 31;
+        hash += Objects.hashCode(mComposingText);
+        hash *= 31;
+        hash += Objects.hashCode(mCharacterRects);
+        hash *= 31;
+        hash += Objects.hashCode(mMatrix);
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj){
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof CursorAnchorInfo)) {
+            return false;
+        }
+        final CursorAnchorInfo that = (CursorAnchorInfo) obj;
+        if (hashCode() != that.hashCode()) {
+            return false;
+        }
+        if (mSelectionStart != that.mSelectionStart
+                || mSelectionEnd != that.mSelectionEnd
+                || mComposingTextStart != that.mComposingTextStart) {
+            return false;
+        }
+        if (!Objects.equals(mComposingTextStart, that.mComposingTextStart)) {
+            return false;
+        }
+        if (!Objects.equals(mCharacterRects, that.mCharacterRects)) {
+            return false;
+        }
+        if (!Objects.equals(mMatrix, that.mMatrix)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "SelectionInfo{mSelection=" + mSelectionStart + "," + mSelectionEnd
+                + " mComposingTextStart=" + mComposingTextStart
+                + " mComposingText=" + Objects.toString(mComposingText)
+                + " mInsertionMarkerHorizontal=" + mInsertionMarkerHorizontal
+                + " mInsertionMarkerTop=" + mInsertionMarkerTop
+                + " mInsertionMarkerBaseline=" + mInsertionMarkerBaseline
+                + " mInsertionMarkerBottom=" + mInsertionMarkerBottom
+                + " mCharacterRects=" + Objects.toString(mCharacterRects)
+                + " mMatrix=" + Objects.toString(mMatrix)
+                + "}";
+    }
+
+    /**
+     * Builder for {@link CursorAnchorInfo}. This class is not designed to be thread-safe.
+     */
+    public static final class CursorAnchorInfoBuilder {
+        /**
+         * Sets the text range of the selection. Calling this can be skipped if there is no
+         * selection.
+         */
+        public CursorAnchorInfoBuilder setSelectionRange(final int newStart, final int newEnd) {
+            mSelectionStart = newStart;
+            mSelectionEnd = newEnd;
+            return this;
+        }
+        private int mSelectionStart = -1;
+        private int mSelectionEnd = -1;
+
+        /**
+         * Sets the text range of the composing text. Calling this can be skipped if there is
+         * no composing text.
+         * @param index index where the composing text starts.
+         * @param composingText the entire composing text.
+         */
+        public CursorAnchorInfoBuilder setComposingText(final int index,
+                final CharSequence composingText) {
+            mComposingTextStart = index;
+            if (composingText == null) {
+                mComposingText = null;
+            } else {
+                mComposingText = composingText.toString();
+            }
+            return this;
+        }
+        private int mComposingTextStart = -1;
+        private String mComposingText = null;
+
+        /**
+         * Sets the location of the text insertion point (zero width cursor) as a rectangle in
+         * local coordinates. Calling this can be skipped when there is no text insertion point;
+         * however if there is an insertion point, editors must call this method.
+         * @param horizontalPosition horizontal position of the insertion marker, in the local
+         * coordinates that will be transformed with the transformation matrix when rendered on the
+         * screen. This should be calculated or compatible with
+         * {@link Layout#getPrimaryHorizontal(int)}.
+         * @param lineTop vertical position of the insertion marker, in the local coordinates that
+         * will be transformed with the transformation matrix when rendered on the screen. This
+         * should be calculated or compatible with {@link Layout#getLineTop(int)}.
+         * @param lineBaseline vertical position of the insertion marker, in the local coordinates
+         * that will be transformed with the transformation matrix when rendered on the screen. This
+         * should be calculated or compatible with {@link Layout#getLineBaseline(int)}.
+         * @param lineBottom vertical position of the insertion marker, in the local coordinates
+         * that will be transformed with the transformation matrix when rendered on the screen. This
+         * should be calculated or compatible with {@link Layout#getLineBottom(int)}.
+         */
+        public CursorAnchorInfoBuilder setInsertionMarkerLocation(
+                final float horizontalPosition, final float lineTop, final float lineBaseline,
+                final float lineBottom){
+            mInsertionMarkerHorizontal = horizontalPosition;
+            mInsertionMarkerTop = lineTop;
+            mInsertionMarkerBaseline = lineBaseline;
+            mInsertionMarkerBottom = lineBottom;
+            return this;
+        }
+        private float mInsertionMarkerHorizontal = Float.NaN;
+        private float mInsertionMarkerTop = Float.NaN;
+        private float mInsertionMarkerBaseline = Float.NaN;
+        private float mInsertionMarkerBottom = Float.NaN;
+
+        /**
+         * Adds the bounding box of the character specified with the index.
+         * <p>
+         * Editor authors should not call this method for characters that are invisible.
+         * </p>
+         *
+         * @param index index of the character in Java chars units. Must be specified in
+         * ascending order across successive calls.
+         * @param leadingEdgeX x coordinate of the leading edge of the character in local
+         * coordinates, that is, left edge for LTR text and right edge for RTL text.
+         * @param leadingEdgeY y coordinate of the leading edge of the character in local
+         * coordinates.
+         * @param trailingEdgeX x coordinate of the trailing edge of the character in local
+         * coordinates, that is, right edge for LTR text and left edge for RTL text.
+         * @param trailingEdgeY y coordinate of the trailing edge of the character in local
+         * coordinates.
+         * @throws IllegalArgumentException If the index is a negative value, or not greater than
+         * all of the previously called indices.
+         */
+        public CursorAnchorInfoBuilder addCharacterRect(final int index,
+                final float leadingEdgeX, final float leadingEdgeY, final float trailingEdgeX,
+                final float trailingEdgeY) {
+            if (index < 0) {
+                throw new IllegalArgumentException("index must not be a negative integer.");
+            }
+            if (mCharacterRectBuilder == null) {
+                mCharacterRectBuilder = new SparseRectFArrayBuilder();
+            }
+            mCharacterRectBuilder.append(index, leadingEdgeX, leadingEdgeY, trailingEdgeX,
+                    trailingEdgeY);
+            return this;
+        }
+        private SparseRectFArrayBuilder mCharacterRectBuilder = null;
+
+        /**
+         * Sets the matrix that transforms local coordinates into screen coordinates.
+         * @param matrix transformation matrix from local coordinates into screen coordinates. null
+         * is interpreted as an identity matrix.
+         */
+        public CursorAnchorInfoBuilder setMatrix(final Matrix matrix) {
+            if (matrix != null) {
+                mMatrix = matrix;
+            } else {
+                mMatrix = Matrix.IDENTITY_MATRIX;
+            }
+            return this;
+        }
+        private Matrix mMatrix = Matrix.IDENTITY_MATRIX;
+
+        /**
+         * @return {@link CursorAnchorInfo} using parameters in this
+         * {@link CursorAnchorInfoBuilder}.
+         */
+        public CursorAnchorInfo build() {
+            return new CursorAnchorInfo(this);
+        }
+
+        /**
+         * Resets the internal state so that this instance can be reused to build another
+         * instance of {@link CursorAnchorInfo}.
+         */
+        public void reset() {
+            mSelectionStart = -1;
+            mSelectionEnd = -1;
+            mComposingTextStart = -1;
+            mComposingText = null;
+            mInsertionMarkerHorizontal = Float.NaN;
+            mInsertionMarkerTop = Float.NaN;
+            mInsertionMarkerBaseline = Float.NaN;
+            mInsertionMarkerBottom = Float.NaN;
+            mMatrix = Matrix.IDENTITY_MATRIX;
+            if (mCharacterRectBuilder != null) {
+                mCharacterRectBuilder.reset();
+            }
+        }
+    }
+
+    private CursorAnchorInfo(final CursorAnchorInfoBuilder builder) {
+        mSelectionStart = builder.mSelectionStart;
+        mSelectionEnd = builder.mSelectionEnd;
+        mComposingTextStart = builder.mComposingTextStart;
+        mComposingText = builder.mComposingText;
+        mInsertionMarkerHorizontal = builder.mInsertionMarkerHorizontal;
+        mInsertionMarkerTop = builder.mInsertionMarkerTop;
+        mInsertionMarkerBaseline = builder.mInsertionMarkerBaseline;
+        mInsertionMarkerBottom = builder.mInsertionMarkerBottom;
+        mCharacterRects = builder.mCharacterRectBuilder != null ?
+                builder.mCharacterRectBuilder.build() : null;
+        mMatrix = builder.mMatrix;
+    }
+
+    /**
+     * Returns the index where the selection starts.
+     * @return -1 if there is no selection.
+     */
+    public int getSelectionStart() {
+        return mSelectionStart;
+    }
+
+    /**
+     * Returns the index where the selection ends.
+     * @return -1 if there is no selection.
+     */
+    public int getSelectionEnd() {
+        return mSelectionEnd;
+    }
+
+    /**
+     * Returns the index where the composing text starts.
+     * @return -1 if there is no composing text.
+     */
+    public int getComposingTextStart() {
+        return mComposingTextStart;
+    }
+
+    /**
+     * Returns the entire composing text.
+     * @return null if there is no composition.
+     */
+    public String getComposingText() {
+        return mComposingText;
+    }
+
+    /**
+     * Returns the horizontal start of the insertion marker, in the local coordinates that will
+     * be transformed with {@link #getMatrix()} when rendered on the screen.
+     * @return x coordinate that is compatible with {@link Layout#getPrimaryHorizontal(int)}.
+     * Pay special care to RTL/LTR handling.
+     * {@code java.lang.Float.NaN} if not specified.
+     * @see Layout#getPrimaryHorizontal(int)
+     */
+    public float getInsertionMarkerHorizontal() {
+        return mInsertionMarkerHorizontal;
+    }
+    /**
+     * Returns the vertical top position of the insertion marker, in the local coordinates that
+     * will be transformed with {@link #getMatrix()} when rendered on the screen.
+     * @return y coordinate that is compatible with {@link Layout#getLineTop(int)}.
+     * {@code java.lang.Float.NaN} if not specified.
+     */
+    public float getInsertionMarkerTop() {
+        return mInsertionMarkerTop;
+    }
+    /**
+     * Returns the vertical baseline position of the insertion marker, in the local coordinates
+     * that will be transformed with {@link #getMatrix()} when rendered on the screen.
+     * @return y coordinate that is compatible with {@link Layout#getLineBaseline(int)}.
+     * {@code java.lang.Float.NaN} if not specified.
+     */
+    public float getInsertionMarkerBaseline() {
+        return mInsertionMarkerBaseline;
+    }
+    /**
+     * Returns the vertical bottom position of the insertion marker, in the local coordinates
+     * that will be transformed with {@link #getMatrix()} when rendered on the screen.
+     * @return y coordinate that is compatible with {@link Layout#getLineBottom(int)}.
+     * {@code java.lang.Float.NaN} if not specified.
+     */
+    public float getInsertionMarkerBottom() {
+        return mInsertionMarkerBottom;
+    }
+
+    /**
+     * Returns a new instance of {@link RectF} that indicates the location of the character
+     * specified with the index.
+     * <p>
+     * Note that coordinates are not necessarily contiguous or even monotonous, especially when
+     * RTL text and LTR text are mixed.
+     * </p>
+     * @param index index of the character in a Java chars.
+     * @return a new instance of {@link RectF} that represents the location of the character in
+     * local coordinates. null if the character is invisible or the application did not provide
+     * the location. Note that the {@code left} field can be greater than the {@code right} field
+     * if the character is in RTL text.
+     */
+    // TODO: Prepare a document about the expected behavior for surrogate pairs, combining
+    // characters, and non-graphical chars.
+    public RectF getCharacterRect(final int index) {
+        if (mCharacterRects == null) {
+            return null;
+        }
+        return mCharacterRects.get(index);
+    }
+
+    /**
+     * Returns a new instance of {@link android.graphics.Matrix} that indicates the transformation
+     * matrix that is to be applied other positional data in this class.
+     * @return a new instance (copy) of the transformation matrix.
+     */
+    public Matrix getMatrix() {
+        return new Matrix(mMatrix);
+    }
+
+    /**
+     * Used to make this class parcelable.
+     */
+    public static final Parcelable.Creator<CursorAnchorInfo> CREATOR
+            = new Parcelable.Creator<CursorAnchorInfo>() {
+        @Override
+        public CursorAnchorInfo createFromParcel(Parcel source) {
+            return new CursorAnchorInfo(source);
+        }
+
+        @Override
+        public CursorAnchorInfo[] newArray(int size) {
+            return new CursorAnchorInfo[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index f8160c8..bc2d7ec 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -259,7 +259,7 @@
     public InputMethodInfo(String packageName, String className,
             CharSequence label, String settingsActivity) {
         this(buildDummyResolveInfo(packageName, className, label), false, settingsActivity, null,
-                0, false);
+                0, false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */);
     }
 
     /**
@@ -269,6 +269,17 @@
     public InputMethodInfo(ResolveInfo ri, boolean isAuxIme,
             String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId,
             boolean forceDefault) {
+        this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId,
+                forceDefault, true /* supportsSwitchingToNextInputMethod */);
+    }
+
+    /**
+     * Temporary API for creating a built-in input method for test.
+     * @hide
+     */
+    public InputMethodInfo(ResolveInfo ri, boolean isAuxIme,
+            String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId,
+            boolean forceDefault, boolean supportsSwitchingToNextInputMethod) {
         final ServiceInfo si = ri.serviceInfo;
         mService = ri;
         mId = new ComponentName(si.packageName, si.name).flattenToShortString();
@@ -277,7 +288,7 @@
         mIsAuxIme = isAuxIme;
         mSubtypes = new InputMethodSubtypeArray(subtypes);
         mForceDefault = forceDefault;
-        mSupportsSwitchingToNextInputMethod = true;
+        mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
     }
 
     private static ResolveInfo buildDummyResolveInfo(String packageName, String className,
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 0227873..f874eb7 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -56,6 +56,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -317,6 +318,12 @@
     int mCursorSelEnd;
     int mCursorCandStart;
     int mCursorCandEnd;
+
+    /**
+     * The instance that has previously been sent to the input method.
+     */
+    private CursorAnchorInfo mCursorAnchorInfo = null;
+
     /**
      * The buffer to retrieve the view location in screen coordinates in {@link #updateCursor}.
      */
@@ -490,6 +497,9 @@
                 case SET_CURSOR_ANCHOR_MONITOR_MODE: {
                     synchronized (mH) {
                         mCursorAnchorMonitorMode = msg.arg1;
+                        // Clear the cache.
+                        mCursorRect.setEmpty();
+                        mCursorAnchorInfo = null;
                     }
                     return;
                 }
@@ -1174,6 +1184,7 @@
                 mCursorCandStart = -1;
                 mCursorCandEnd = -1;
                 mCursorRect.setEmpty();
+                mCursorAnchorInfo = null;
                 servedContext = new ControlledInputConnectionWrapper(vh.getLooper(), ic, this);
             } else {
                 servedContext = null;
@@ -1435,7 +1446,7 @@
                     || mCurrentTextBoxAttribute == null || mCurMethod == null) {
                 return;
             }
-            
+
             if (mCursorSelStart != selStart || mCursorSelEnd != selEnd
                     || mCursorCandStart != candidatesStart
                     || mCursorCandEnd != candidatesEnd) {
@@ -1536,10 +1547,9 @@
                     || mCurrentTextBoxAttribute == null || mCurMethod == null) {
                 return;
             }
+            if (DEBUG) Log.d(TAG, "updateCursor");
             mTmpCursorRect.set(left, top, right, bottom);
-            if (!mCursorRect.equals(mTmpCursorRect)) {
-                if (DEBUG) Log.d(TAG, "updateCursor");
-
+            if (!Objects.equals(mCursorRect, mTmpCursorRect)) {
                 try {
                     if (DEBUG) Log.v(TAG, "CURSOR CHANGE: " + mCurMethod);
                     mCursorRect.set(mTmpCursorRect);
@@ -1556,6 +1566,35 @@
     }
 
     /**
+     * Report positional change of the text insertion point and/or characters in the composition
+     * string.
+     */
+    public void updateCursorAnchorInfo(View view, final CursorAnchorInfo cursorAnchorInfo) {
+        if (view == null || cursorAnchorInfo == null) {
+            return;
+        }
+        checkFocus();
+        synchronized (mH) {
+            if ((mServedView != view &&
+                    (mServedView == null || !mServedView.checkInputConnectionProxy(view)))
+                    || mCurrentTextBoxAttribute == null || mCurMethod == null) {
+                return;
+            }
+            if (Objects.equals(mCursorAnchorInfo, cursorAnchorInfo)) {
+                Log.w(TAG, "Ignoring redundant updateCursorAnchorInfo: info=" + cursorAnchorInfo);
+                return;
+            }
+            if (DEBUG) Log.v(TAG, "updateCursorAnchorInfo: " + cursorAnchorInfo);
+            try {
+                mCurMethod.updateCursorAnchorInfo(cursorAnchorInfo);
+                mCursorAnchorInfo = cursorAnchorInfo;
+            } catch (RemoteException e) {
+                Log.w(TAG, "IME died: " + mCurId, e);
+            }
+        }
+    }
+
+    /**
      * Call {@link InputMethodSession#appPrivateCommand(String, Bundle)
      * InputMethodSession.appPrivateCommand()} on the current Input Method.
      * @param view Optional View that is sending the command, or null if
diff --git a/core/java/android/view/inputmethod/InputMethodSession.java b/core/java/android/view/inputmethod/InputMethodSession.java
index 6386299..74fbbc7 100644
--- a/core/java/android/view/inputmethod/InputMethodSession.java
+++ b/core/java/android/view/inputmethod/InputMethodSession.java
@@ -165,7 +165,7 @@
     public void appPrivateCommand(String action, Bundle data);
     
     /**
-     * Toggle the soft input window. 
+     * Toggle the soft input window.
      * Applications can toggle the state of the soft input window.
      * @param showFlags Provides additional operating flags.  May be
      * 0 or have the {@link InputMethodManager#SHOW_IMPLICIT},
@@ -175,4 +175,14 @@
      * {@link  InputMethodManager#HIDE_NOT_ALWAYS} bit set.
      */
     public void toggleSoftInput(int showFlags, int hideFlags);
+
+    /**
+     * This method is called when the cursor and/or the character position relevant to text input
+     * is changed on the screen.  This is not called by default.  It will only be reported if
+     * requested by the input method.
+     *
+     * @param cursorAnchorInfo Positional information relevant to text input, such as text
+     * insertion point and composition string.
+     */
+    public void updateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo);
 }
diff --git a/core/java/android/view/inputmethod/SparseRectFArray.java b/core/java/android/view/inputmethod/SparseRectFArray.java
new file mode 100644
index 0000000..40cade7
--- /dev/null
+++ b/core/java/android/view/inputmethod/SparseRectFArray.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view.inputmethod;
+
+import android.graphics.RectF;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * An implementation of SparseArray specialized for {@link android.graphics.RectF}.
+ * <p>
+ * As this is a sparse array, it represents an array of {@link RectF} most of which are null. This
+ * class could be in some other packages like android.graphics or android.util but currently
+ * belong to android.view.inputmethod because this class is hidden and used only in input method
+ * framework.
+ * </p>
+ * @hide
+ */
+public final class SparseRectFArray implements Parcelable {
+    /**
+     * The keys, in ascending order, of those {@link RectF} that are not null. For example,
+     * {@code [null, null, null, Rect1, null, Rect2]} would be represented by {@code [3,5]}.
+     * @see #mCoordinates
+     */
+    private final int[] mKeys;
+
+    /**
+     * Stores coordinates of the rectangles, in the order of
+     * {@code rects[mKeys[0]].left}, {@code rects[mKeys[0]].top},
+     * {@code rects[mKeys[0]].right}, {@code rects[mKeys[0]].bottom},
+     * {@code rects[mKeys[1]].left}, {@code rects[mKeys[1]].top},
+     * {@code rects[mKeys[1]].right}, {@code rects[mKeys[1]].bottom},
+     * {@code rects[mKeys[2]].left}, {@code rects[mKeys[2]].top}, ....
+     */
+    private final float[] mCoordinates;
+
+    public SparseRectFArray(final Parcel source) {
+        mKeys = source.createIntArray();
+        mCoordinates = source.createFloatArray();
+    }
+
+    /**
+     * Used to package this object into a {@link Parcel}.
+     *
+     * @param dest The {@link Parcel} to be written.
+     * @param flags The flags used for parceling.
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeIntArray(mKeys);
+        dest.writeFloatArray(mCoordinates);
+    }
+
+    @Override
+    public int hashCode() {
+        // TODO: Improve the hash function.
+        if (mKeys == null || mKeys.length == 0) {
+            return 0;
+        }
+        int hash = mKeys.length;
+        // For performance reasons, only the first rectangle is used for the hash code now.
+        for (int i = 0; i < 4; i++) {
+            hash *= 31;
+            hash += mCoordinates[i];
+        }
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj){
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof SparseRectFArray)) {
+            return false;
+        }
+        final SparseRectFArray that = (SparseRectFArray) obj;
+
+        return Arrays.equals(mKeys, that.mKeys) && Arrays.equals(mCoordinates, that.mCoordinates);
+    }
+
+    @Override
+    public String toString() {
+        if (mKeys == null || mCoordinates == null) {
+            return "SparseRectFArray{}";
+        }
+        final StringBuilder sb = new StringBuilder();
+        sb.append("SparseRectFArray{");
+        for (int i = 0; i < mKeys.length; i++) {
+            if (i != 0) {
+                sb.append(", ");
+            }
+            final int baseIndex = i * 4;
+            sb.append(mKeys[i]);
+            sb.append(":[");
+            sb.append(mCoordinates[baseIndex + 0]);
+            sb.append(",");
+            sb.append(mCoordinates[baseIndex + 1]);
+            sb.append("],[");
+            sb.append(mCoordinates[baseIndex + 2]);
+            sb.append(",");
+            sb.append(mCoordinates[baseIndex + 3]);
+            sb.append("]");
+        }
+        sb.append("}");
+        return sb.toString();
+    }
+
+    /**
+     * Builder for {@link SparseRectFArray}. This class is not designed to be thread-safe.
+     * @hide
+     */
+    public static final class SparseRectFArrayBuilder {
+        /**
+         * Throws {@link IllegalArgumentException} to make sure that this class is correctly used.
+         * @param key key to be checked.
+         */
+        private void checkIndex(final int key) {
+            if (mCount == 0) {
+                return;
+            }
+            if (mKeys[mCount - 1] >= key) {
+                throw new IllegalArgumentException("key must be greater than all existing keys.");
+            }
+        }
+
+        /**
+         * Extends the internal array if necessary.
+         */
+        private void ensureBufferSize() {
+            if (mKeys == null) {
+                mKeys = new int[INITIAL_SIZE];
+            }
+            if (mCoordinates == null) {
+                mCoordinates = new float[INITIAL_SIZE * 4];
+            }
+            final int requiredIndexArraySize = mCount + 1;
+            if (mKeys.length <= requiredIndexArraySize) {
+                final int[] newArray = new int[requiredIndexArraySize * 2];
+                System.arraycopy(mKeys, 0, newArray, 0, mCount);
+                mKeys = newArray;
+            }
+            final int requiredCoordinatesArraySize = (mCount + 1) * 4;
+            if (mCoordinates.length <= requiredCoordinatesArraySize) {
+                final float[] newArray = new float[requiredCoordinatesArraySize * 2];
+                System.arraycopy(mCoordinates, 0, newArray, 0, mCount * 4);
+                mCoordinates = newArray;
+            }
+        }
+
+        /**
+         * Puts the rectangle with an integer key.
+         * @param key the key to be associated with the rectangle. It must be greater than all
+         * existing keys that have been previously specified.
+         * @param left left of the rectangle.
+         * @param top top of the rectangle.
+         * @param right right of the rectangle.
+         * @param bottom bottom of the rectangle.
+         * @return the receiver object itself for chaining method calls.
+         * @throws IllegalArgumentException If the index is not greater than all of existing keys.
+         */
+        public SparseRectFArrayBuilder append(final int key,
+                final float left, final float top, final float right, final float bottom) {
+            checkIndex(key);
+            ensureBufferSize();
+            final int baseCoordinatesIndex = mCount * 4;
+            mCoordinates[baseCoordinatesIndex + 0] = left;
+            mCoordinates[baseCoordinatesIndex + 1] = top;
+            mCoordinates[baseCoordinatesIndex + 2] = right;
+            mCoordinates[baseCoordinatesIndex + 3] = bottom;
+            mKeys[mCount] = key;
+            ++mCount;
+            return this;
+        }
+        private int mCount = 0;
+        private int[] mKeys = null;
+        private float[] mCoordinates = null;
+        private static int INITIAL_SIZE = 16;
+
+        /**
+         * @return {@link SparseRectFArray} using parameters in this {@link SparseRectFArray}.
+         */
+        public SparseRectFArray build() {
+            return new SparseRectFArray(this);
+        }
+
+        public void reset() {
+            if (mCount == 0) {
+                mKeys = null;
+                mCoordinates = null;
+            }
+            mCount = 0;
+        }
+    }
+
+    private SparseRectFArray(final SparseRectFArrayBuilder builder) {
+        if (builder.mCount == 0) {
+            mKeys = null;
+            mCoordinates = null;
+        } else {
+            mKeys = new int[builder.mCount];
+            mCoordinates = new float[builder.mCount * 4];
+            System.arraycopy(builder.mKeys, 0, mKeys, 0, builder.mCount);
+            System.arraycopy(builder.mCoordinates, 0, mCoordinates, 0, builder.mCount * 4);
+        }
+    }
+
+    public RectF get(final int index) {
+        if (mKeys == null) {
+            return null;
+        }
+        if (index < 0) {
+            return null;
+        }
+        final int arrayIndex = Arrays.binarySearch(mKeys, index);
+        if (arrayIndex < 0) {
+            return null;
+        }
+        final int baseCoordIndex = arrayIndex * 4;
+        return new RectF(mCoordinates[baseCoordIndex],
+                mCoordinates[baseCoordIndex + 1],
+                mCoordinates[baseCoordIndex + 2],
+                mCoordinates[baseCoordIndex + 3]);
+    }
+
+    /**
+     * Used to make this class parcelable.
+     */
+    public static final Parcelable.Creator<SparseRectFArray> CREATOR =
+            new Parcelable.Creator<SparseRectFArray>() {
+                @Override
+                public SparseRectFArray createFromParcel(Parcel source) {
+                    return new SparseRectFArray(source);
+                }
+                @Override
+                public SparseRectFArray[] newArray(int size) {
+                    return new SparseRectFArray[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
+
diff --git a/core/java/android/webkit/ClientCertRequest.java b/core/java/android/webkit/ClientCertRequest.java
index 8951786..588b868 100644
--- a/core/java/android/webkit/ClientCertRequest.java
+++ b/core/java/android/webkit/ClientCertRequest.java
@@ -36,8 +36,6 @@
  * host/port pair. The user can clear the cached data using
  * {@link WebView#clearClientCertPreferences}.
  *
- * TODO(sgurun) unhide
- * @hide
  */
 public interface ClientCertRequest {
     /**
diff --git a/core/java/android/webkit/EventLogTags.logtags b/core/java/android/webkit/EventLogTags.logtags
index b0b5493..a90aebd 100644
--- a/core/java/android/webkit/EventLogTags.logtags
+++ b/core/java/android/webkit/EventLogTags.logtags
@@ -8,3 +8,4 @@
 # 70103- used by the browser app itself
 
 70150 browser_snap_center
+70151 exp_det_attempt_to_call_object_getclass (app_signature|3)
diff --git a/core/java/android/webkit/PermissionRequest.java b/core/java/android/webkit/PermissionRequest.java
index 2f8850b..fa760b7 100644
--- a/core/java/android/webkit/PermissionRequest.java
+++ b/core/java/android/webkit/PermissionRequest.java
@@ -19,18 +19,16 @@
 import android.net.Uri;
 
 /**
- * This class wraps a permission request, and is used to request permission for
- * the web content to access the resources.
+ * This interface defines a permission request and is used when web content
+ * requests access to protected resources.
  *
- * Either {@link #grant(long) grant()} or {@link #deny()} must be called to response the
- * request, otherwise, {@link WebChromeClient#onPermissionRequest(PermissionRequest)} will
- * not be invoked again if there is other permission request in this WebView.
- *
- * @hide
+ * Either {@link #grant(long) grant()} or {@link #deny()} must be called in UI
+ * thread to respond to the request.
  */
 public interface PermissionRequest {
     /**
      * Resource belongs to geolocation service.
+     * @hide - see b/14668406
      */
     public final static long RESOURCE_GEOLOCATION = 1 << 0;
     /**
@@ -62,8 +60,6 @@
      *        must be equals or a subset of granted resources.
      *        This parameter is designed to avoid granting permission by accident
      *        especially when new resources are requested by web content.
-     *        Calling grant(getResources()) has security issue, the new permission
-     *        will be granted without being noticed.
      */
     public void grant(long resources);
 
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 60cba86..d630a9a 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -304,7 +304,6 @@
      * If this method isn't overridden, the permission is denied.
      *
      * @param request the PermissionRequest from current web content.
-     * @hide
      */
     public void onPermissionRequest(PermissionRequest request) {
         request.deny();
@@ -314,8 +313,7 @@
      * Notify the host application that the given permission request
      * has been canceled. Any related UI should therefore be hidden.
      *
-     * @param request the PermissionRequest need be canceled.
-     * @hide
+     * @param request the PermissionRequest that needs be canceled.
      */
     public void onPermissionRequestCanceled(PermissionRequest request) {}
 
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 98ef66e..7c32c5b 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -171,6 +171,38 @@
     }
 
     /**
+     * Used with {@link #setMixedContentMode}
+     *
+     * In this mode, the WebView will allow a secure origin to load content from any other origin,
+     * even if that origin is insecure. This is the least secure mode of operation for the WebView,
+     * and where possible apps should not set this mode.
+     */
+    public static final int MIXED_CONTENT_ALWAYS_ALLOW = 0;
+
+    /**
+     * Used with {@link #setMixedContentMode}
+     *
+     * In this mode, the WebView will not allow a secure origin to load content from an insecure
+     * origin. This is the preferred and most secure mode of operation for the WebView and apps are
+     * strongly advised to use this mode.
+     */
+    public static final int MIXED_CONTENT_NEVER_ALLOW = 1;
+
+    /**
+     * Used with {@link #setMixedContentMode}
+     *
+     * In this mode, the WebView will attempt to be compatible with the approach of a modern web
+     * browser with regard to mixed content. Some insecure content may be allowed to be loaded by
+     * a secure origin and other types of content will be blocked. The types of content are allowed
+     * or blocked may change release to release and are not explicitly defined.
+     *
+     * This mode is intended to be used by apps that are not in control of the content that they
+     * render but desire to operate in a reasonably secure environment. For highest security, apps
+     * are recommended to use {@link #MIXED_CONTENT_NEVER_ALLOW}.
+     */
+    public static final int MIXED_CONTENT_COMPATIBILITY_MODE = 2;
+
+    /**
      * Hidden constructor to prevent clients from creating a new settings
      * instance or deriving the class.
      *
@@ -1403,4 +1435,29 @@
     public int getCacheMode() {
         throw new MustOverrideException();
     }
+
+    /**
+     * Configures the WebView's behavior when a secure origin attempts to load a resource from an
+     * insecure origin.
+     *
+     * By default, apps that target {@link android.os.Build.VERSION_CODES#KITKAT} or below default
+     * to {@link #MIXED_CONTENT_ALWAYS_ALLOW}. Apps targeting
+     * {@link android.os.Build.VERSION_CODES#L} default to {@link #MIXED_CONTENT_NEVER_ALLOW}.
+     *
+     * The preferred and most secure mode of operation for the WebView is
+     * {@link #MIXED_CONTENT_NEVER_ALLOW} and use of {@link #MIXED_CONTENT_ALWAYS_ALLOW} is
+     * 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}.
+     */
+    public abstract void setMixedContentMode(int mode);
+
+    /**
+     * 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}.
+     */
+    public abstract int getMixedContentMode();
 }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index c914e52..91ca7b4 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -33,6 +33,7 @@
 import android.os.Message;
 import android.os.StrictMode;
 import android.print.PrintDocumentAdapter;
+import android.security.KeyChain;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -250,6 +251,15 @@
         implements ViewTreeObserver.OnGlobalFocusChangeListener,
         ViewGroup.OnHierarchyChangeListener, ViewDebug.HierarchyHandler {
 
+    /**
+     * Broadcast Action: Indicates the data reduction proxy setting changed.
+     * Sent by the settings app when user changes the data reduction proxy value. This intent will
+     * always stay as a hidden API.
+     * @hide
+     */
+    public static final String DATA_REDUCTION_PROXY_SETTING_CHANGED =
+            "android.webkit.DATA_REDUCTION_PROXY_SETTING_CHANGED";
+
     private static final String LOGTAG = "WebView";
 
     // Throwing an exception for incorrect thread usage if the
@@ -701,7 +711,7 @@
      */
     @Deprecated
     public static void enablePlatformNotifications() {
-        getFactory().getStatics().setPlatformNotificationsEnabled(true);
+        // noop
     }
 
     /**
@@ -713,7 +723,7 @@
      */
     @Deprecated
     public static void disablePlatformNotifications() {
-        getFactory().getStatics().setPlatformNotificationsEnabled(false);
+        // noop
     }
 
     /**
@@ -1479,18 +1489,16 @@
      * Clears the client certificate preferences table stored in response
      * to proceeding/cancelling client cert requests. Note that webview
      * automatically clears these preferences when it receives a
-     * {@link KeyChain.ACTION_STORAGE_CHANGED}
+     * {@link KeyChain#ACTION_STORAGE_CHANGED} intent. The client certificate
+     * preferences are global for all Webviews.
      *
-     * @param resultCallback A callback to be invoked when client certs are cleared.
-     *                       The embedder can pass null if not interested in the callback.
-     *
-     * TODO(sgurun) unhide
-     * @hide
+     * @param onCleared  A runnable to be invoked when client certs are cleared.
+     *                   The embedder can pass null if not interested in the
+     *                   callback. The runnable will be called in UI thread.
      */
-    public void clearClientCertPreferences(ValueCallback<Void> resultCallback) {
-        checkThread();
+    public static void clearClientCertPreferences(Runnable onCleared) {
         if (DebugFlags.TRACE_API) Log.d(LOGTAG, "clearClientCertPreferences");
-        mProvider.clearClientCertPreferences(resultCallback);
+        getFactory().getStatics().clearClientCertPreferences(onCleared);
     }
 
     /**
@@ -1610,6 +1618,8 @@
      * @return the address, or if no address is found, null
      */
     public static String findAddress(String addr) {
+        // TODO: Rewrite this in Java so it is not needed to start up chromium
+        // Could also be deprecated
         return getFactory().getStatics().findAddress(addr);
     }
 
@@ -1672,13 +1682,15 @@
 
     /**
      * Preauthorize the given origin to access resources.
-     * This authorization only valid for this WebView instance life cycle and
+     * The authorization only valid for this WebView instance's life cycle and
      * will not retained.
      *
+     * In the case that an origin has had resources preauthorized, calls to
+     * {@link WebChromeClient#onPermissionRequest(PermissionRequest)} will not be
+     * made for those resources from that origin.
+     *
      * @param origin the origin authorized to access resources
      * @param resources the resource authorized to be accessed by origin.
-     *
-     * @hide
      */
     public void preauthorizePermission(Uri origin, long resources) {
         checkThread();
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 688c251..62b80c4a 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -19,6 +19,7 @@
 import android.graphics.Bitmap;
 import android.net.http.SslError;
 import android.os.Message;
+import android.view.InputEvent;
 import android.view.KeyEvent;
 import android.view.ViewRootImpl;
 
@@ -223,8 +224,6 @@
      * @param view The WebView that is initiating the callback
      * @param request An instance of a {@link ClientCertRequest}
      *
-     * TODO(sgurun) unhide
-     * @hide
      */
     public void onReceivedClientCertRequest(WebView view, ClientCertRequest request) {
         request.cancel();
@@ -272,11 +271,43 @@
      *
      * @param view The WebView that is initiating the callback.
      * @param event The key event.
+     * @deprecated This method is subsumed by the more generic onUnhandledInputEvent.
      */
+    @Deprecated
     public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
+        onUnhandledInputEventInternal(view, event);
+    }
+
+    /**
+     * Notify the host application that a input event was not handled by the WebView.
+     * Except system keys, WebView always consumes input events in the normal flow
+     * or if shouldOverrideKeyEvent returns true. This is called asynchronously
+     * from where the event is dispatched. It gives the host application a chance
+     * to handle the unhandled input events.
+     *
+     * Note that if the event is a {@link android.view.MotionEvent}, then it's lifetime is only
+     * that of the function call. If the WebViewClient wishes to use the event beyond that, then it
+     * <i>must</i> create a copy of the event.
+     *
+     * It is the responsibility of overriders of this method to call
+     * {@link #onUnhandledKeyEvent(WebView, KeyEvent)}
+     * when appropriate if they wish to continue receiving events through it.
+     *
+     * @param view The WebView that is initiating the callback.
+     * @param event The input event.
+     */
+    public void onUnhandledInputEvent(WebView view, InputEvent event) {
+        if (event instanceof KeyEvent) {
+            onUnhandledKeyEvent(view, (KeyEvent) event);
+            return;
+        }
+        onUnhandledInputEventInternal(view, event);
+    }
+
+    private void onUnhandledInputEventInternal(WebView view, InputEvent event) {
         ViewRootImpl root = view.getViewRootImpl();
         if (root != null) {
-            root.dispatchUnhandledKey(event);
+            root.dispatchUnhandledInputEvent(event);
         }
     }
 
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 25bcd44..ac12357 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -50,28 +50,6 @@
     private static WebViewFactoryProvider sProviderInstance;
     private static final Object sProviderLock = new Object();
 
-    public static boolean isExperimentalWebViewAvailable() {
-        // TODO: Remove callers of this method then remove it.
-        return false;  // Hide the toggle in Developer Settings.
-    }
-
-    /** @hide */
-    public static void setUseExperimentalWebView(boolean enable) {
-        // TODO: Remove callers of this method then remove it.
-    }
-
-    /** @hide */
-    public static boolean useExperimentalWebView() {
-        // TODO: Remove callers of this method then remove it.
-        return true;
-    }
-
-    /** @hide */
-    public static boolean isUseExperimentalWebViewSet() {
-        // TODO: Remove callers of this method then remove it.
-        return false;  // User has not modifed Developer Settings
-    }
-
     static WebViewFactoryProvider getProvider() {
         synchronized (sProviderLock) {
             // For now the main purpose of this function (and the factory abstraction) is to keep
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index e391aaf..945e0e3 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -59,6 +59,13 @@
          * {@link android.webkit.WebView#setWebContentsDebuggingEnabled(boolean) }
          */
         void setWebContentsDebuggingEnabled(boolean enable);
+
+        /**
+         * Implements the API method:
+         * {@link android.webkit.WebView#clearClientCertPreferences(Runnable) }
+         */
+        void clearClientCertPreferences(Runnable onCleared);
+
     }
 
     Statics getStatics();
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index efa5497..5081ff5 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -198,8 +198,6 @@
 
     public void clearSslPreferences();
 
-    public void clearClientCertPreferences(ValueCallback<Void> resultCallback);
-
     public WebBackForwardList copyBackForwardList();
 
     public void setFindListener(WebView.FindListener listener);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index becda67..f91ef1a 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -110,6 +110,7 @@
      * @see #setTranscriptMode(int)
      */
     public static final int TRANSCRIPT_MODE_DISABLED = 0;
+
     /**
      * The list will automatically scroll to the bottom when a data set change
      * notification is received and only if the last item is already visible
@@ -118,6 +119,7 @@
      * @see #setTranscriptMode(int)
      */
     public static final int TRANSCRIPT_MODE_NORMAL = 1;
+
     /**
      * The list will automatically scroll to the bottom, no matter what items
      * are currently visible.
@@ -609,6 +611,9 @@
 
     final boolean[] mIsScrap = new boolean[1];
 
+    private final int[] mScrollOffset = new int[2];
+    private final int[] mScrollConsumed = new int[2];
+
     // True when the popup should be hidden because of a call to
     // dispatchDisplayHint()
     private boolean mPopupHidden;
@@ -738,7 +743,7 @@
          *
          * @param view The view whose scroll state is being reported
          *
-         * @param scrollState The current scroll state. One of 
+         * @param scrollState The current scroll state. One of
          * {@link #SCROLL_STATE_TOUCH_SCROLL} or {@link #SCROLL_STATE_IDLE}.
          */
         public void onScrollStateChanged(AbsListView view, int scrollState);
@@ -2489,8 +2494,30 @@
         }
     }
 
+    /**
+     * Positions the selector in a way that mimics keyboard focus. If the
+     * selector drawable supports hotspots, this manages the focus hotspot.
+     */
+    void positionSelectorLikeFocus(int position, View sel) {
+        positionSelector(position, sel);
+
+        final Drawable selector = mSelector;
+        if (selector != null && selector.supportsHotspots() && position != INVALID_POSITION) {
+            final Rect bounds = mSelectorRect;
+            final float x = bounds.exactCenterX();
+            final float y = bounds.exactCenterY();
+            selector.setHotspot(R.attr.state_focused, x, y);
+        }
+    }
+
     void positionSelector(int position, View sel) {
         if (position != INVALID_POSITION) {
+            if (mSelectorPosition != position) {
+                final Drawable selector = mSelector;
+                if (selector != null && selector.supportsHotspots()) {
+                    selector.clearHotspots();
+                }
+            }
             mSelectorPosition = position;
         }
 
@@ -3240,13 +3267,14 @@
         }
     }
 
-    private boolean startScrollIfNeeded(int y) {
+    private boolean startScrollIfNeeded(int x, int y, MotionEvent vtev) {
         // Check if we have moved far enough that it looks more like a
         // scroll than a tap
         final int deltaY = y - mMotionY;
         final int distance = Math.abs(deltaY);
         final boolean overscroll = mScrollY != 0;
-        if (overscroll || distance > mTouchSlop) {
+        if ((overscroll || distance > mTouchSlop) &&
+                (getNestedScrollAxes() & SCROLL_AXIS_VERTICAL) == 0) {
             createScrollingCache();
             if (overscroll) {
                 mTouchMode = TOUCH_MODE_OVERSCROLL;
@@ -3268,17 +3296,32 @@
             if (parent != null) {
                 parent.requestDisallowInterceptTouchEvent(true);
             }
-            scrollIfNeeded(y);
+            scrollIfNeeded(x, y, vtev);
             return true;
         }
 
         return false;
     }
 
-    private void scrollIfNeeded(int y) {
-        final int rawDeltaY = y - mMotionY;
-        final int deltaY = rawDeltaY - mMotionCorrection;
-        int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;
+    private void scrollIfNeeded(int x, int y, MotionEvent vtev) {
+        int rawDeltaY = y - mMotionY;
+        int scrollOffsetCorrection = 0;
+        int scrollConsumedCorrection = 0;
+        if (mLastY == Integer.MIN_VALUE) {
+            rawDeltaY -= mMotionCorrection;
+        }
+        if (dispatchNestedPreScroll(0, rawDeltaY, mScrollConsumed, mScrollOffset)) {
+            rawDeltaY -= mScrollConsumed[1];
+            scrollOffsetCorrection -= mScrollOffset[1];
+            scrollConsumedCorrection -= mScrollConsumed[1];
+            if (vtev != null) {
+                vtev.offsetLocation(0, mScrollOffset[1]);
+            }
+        }
+        final int deltaY = rawDeltaY;
+        int incrementalDeltaY =
+                mLastY != Integer.MIN_VALUE ? y - mLastY + scrollConsumedCorrection : deltaY;
+        int lastYCorrection = 0;
 
         if (mTouchMode == TOUCH_MODE_SCROLL) {
             if (PROFILE_SCROLLING) {
@@ -3337,39 +3380,53 @@
 
                         int overscroll = -incrementalDeltaY -
                                 (motionViewRealTop - motionViewPrevTop);
-                        overScrollBy(0, overscroll, 0, mScrollY, 0, 0,
-                                0, mOverscrollDistance, true);
-                        if (Math.abs(mOverscrollDistance) == Math.abs(mScrollY)) {
-                            // Don't allow overfling if we're at the edge.
-                            if (mVelocityTracker != null) {
+                        if (dispatchNestedScroll(0, overscroll - incrementalDeltaY, 0, overscroll,
+                                mScrollOffset)) {
+                            lastYCorrection -= mScrollOffset[1];
+                            if (vtev != null) {
+                                vtev.offsetLocation(0, mScrollOffset[1]);
+                            }
+                        } else {
+                            final boolean atOverscrollEdge = overScrollBy(0, overscroll,
+                                    0, mScrollY, 0, 0, 0, mOverscrollDistance, true);
+
+                            if (atOverscrollEdge && mVelocityTracker != null) {
+                                // Don't allow overfling if we're at the edge
                                 mVelocityTracker.clear();
                             }
-                        }
 
-                        final int overscrollMode = getOverScrollMode();
-                        if (overscrollMode == OVER_SCROLL_ALWAYS ||
-                                (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
-                                        !contentFits())) {
-                            mDirection = 0; // Reset when entering overscroll.
-                            mTouchMode = TOUCH_MODE_OVERSCROLL;
-                            if (rawDeltaY > 0) {
-                                mEdgeGlowTop.onPull((float) overscroll / getHeight());
-                                if (!mEdgeGlowBottom.isFinished()) {
-                                    mEdgeGlowBottom.onRelease();
+                            final int overscrollMode = getOverScrollMode();
+                            if (overscrollMode == OVER_SCROLL_ALWAYS ||
+                                    (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
+                                            !contentFits())) {
+                                if (!atOverscrollEdge) {
+                                    mDirection = 0; // Reset when entering overscroll.
+                                    mTouchMode = TOUCH_MODE_OVERSCROLL;
                                 }
-                                invalidate(mEdgeGlowTop.getBounds(false));
-                            } else if (rawDeltaY < 0) {
-                                mEdgeGlowBottom.onPull((float) overscroll / getHeight());
-                                if (!mEdgeGlowTop.isFinished()) {
-                                    mEdgeGlowTop.onRelease();
+                                if (incrementalDeltaY > 0) {
+                                    mEdgeGlowTop.onPull((float) -overscroll / getHeight(),
+                                            (float) x / getWidth());
+                                    if (!mEdgeGlowBottom.isFinished()) {
+                                        mEdgeGlowBottom.onRelease();
+                                    }
+                                    invalidate(0, 0, getWidth(),
+                                            mEdgeGlowTop.getMaxHeight() + getPaddingTop());
+                                } else if (incrementalDeltaY < 0) {
+                                    mEdgeGlowBottom.onPull((float) overscroll / getHeight(),
+                                            1.f - (float) x / getWidth());
+                                    if (!mEdgeGlowTop.isFinished()) {
+                                        mEdgeGlowTop.onRelease();
+                                    }
+                                    invalidate(0, getHeight() - getPaddingBottom() -
+                                            mEdgeGlowBottom.getMaxHeight(), getWidth(),
+                                            getHeight());
                                 }
-                                invalidate(mEdgeGlowBottom.getBounds(true));
                             }
                         }
                     }
-                    mMotionY = y;
+                    mMotionY = y + scrollOffsetCorrection;
                 }
-                mLastY = y;
+                mLastY = y + lastYCorrection + scrollOffsetCorrection;
             }
         } else if (mTouchMode == TOUCH_MODE_OVERSCROLL) {
             if (y != mLastY) {
@@ -3397,17 +3454,22 @@
                             (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
                                     !contentFits())) {
                         if (rawDeltaY > 0) {
-                            mEdgeGlowTop.onPull((float) overScrollDistance / getHeight());
+                            mEdgeGlowTop.onPull((float) overScrollDistance / getHeight(),
+                                    (float) x / getWidth());
                             if (!mEdgeGlowBottom.isFinished()) {
                                 mEdgeGlowBottom.onRelease();
                             }
-                            invalidate(mEdgeGlowTop.getBounds(false));
+                            invalidate(0, 0, getWidth(),
+                                    mEdgeGlowTop.getMaxHeight() + getPaddingTop());
                         } else if (rawDeltaY < 0) {
-                            mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight());
+                            mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight(),
+                                    1.f - (float) x / getWidth());
                             if (!mEdgeGlowTop.isFinished()) {
                                 mEdgeGlowTop.onRelease();
                             }
-                            invalidate(mEdgeGlowBottom.getBounds(true));
+                            invalidate(0, getHeight() - getPaddingBottom() -
+                                    mEdgeGlowBottom.getMaxHeight(), getWidth(),
+                                    getHeight());
                         }
                     }
                 }
@@ -3493,6 +3555,8 @@
             return false;
         }
 
+        startNestedScroll(SCROLL_AXIS_VERTICAL);
+
         if (mFastScroll != null) {
             boolean intercepted = mFastScroll.onTouchEvent(ev);
             if (intercepted) {
@@ -3501,7 +3565,7 @@
         }
 
         initVelocityTrackerIfNotExists();
-        mVelocityTracker.addMovement(ev);
+        final MotionEvent vtev = MotionEvent.obtain(ev);
 
         final int actionMasked = ev.getActionMasked();
         switch (actionMasked) {
@@ -3511,7 +3575,7 @@
             }
 
             case MotionEvent.ACTION_MOVE: {
-                onTouchMove(ev);
+                onTouchMove(ev, vtev);
                 break;
             }
 
@@ -3562,6 +3626,10 @@
             }
         }
 
+        if (mVelocityTracker != null) {
+            mVelocityTracker.addMovement(vtev);
+        }
+        vtev.recycle();
         return true;
     }
 
@@ -3628,7 +3696,7 @@
         }
     }
 
-    private void onTouchMove(MotionEvent ev) {
+    private void onTouchMove(MotionEvent ev, MotionEvent vtev) {
         int pointerIndex = ev.findPointerIndex(mActivePointerId);
         if (pointerIndex == -1) {
             pointerIndex = 0;
@@ -3649,7 +3717,7 @@
             case TOUCH_MODE_DONE_WAITING:
                 // Check if we have moved far enough that it looks more like a
                 // scroll than a tap. If so, we'll enter scrolling mode.
-                if (startScrollIfNeeded(y)) {
+                if (startScrollIfNeeded((int) ev.getX(pointerIndex), y, vtev)) {
                     break;
                 }
                 // Otherwise, check containment within list bounds. If we're
@@ -3669,7 +3737,7 @@
                 break;
             case TOUCH_MODE_SCROLL:
             case TOUCH_MODE_OVERSCROLL:
-                scrollIfNeeded(y);
+                scrollIfNeeded((int) ev.getX(pointerIndex), y, vtev);
                 break;
         }
     }
@@ -3911,6 +3979,49 @@
     }
 
     @Override
+    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
+        return ((nestedScrollAxes & SCROLL_AXIS_VERTICAL) != 0);
+    }
+
+    @Override
+    public void onNestedScrollAccepted(View child, View target, int axes) {
+        super.onNestedScrollAccepted(child, target, axes);
+        startNestedScroll(SCROLL_AXIS_VERTICAL);
+    }
+
+    @Override
+    public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
+            int dxUnconsumed, int dyUnconsumed) {
+        final int motionIndex = getChildCount() / 2;
+        final View motionView = getChildAt(motionIndex);
+        final int oldTop = motionView != null ? motionView.getTop() : 0;
+        if (motionView == null || trackMotionScroll(-dyUnconsumed, -dyUnconsumed)) {
+            int myUnconsumed = dyUnconsumed;
+            int myConsumed = 0;
+            if (motionView != null) {
+                myConsumed = motionView.getTop() - oldTop;
+                myUnconsumed -= myConsumed;
+            }
+            dispatchNestedScroll(0, myConsumed, 0, myUnconsumed, null);
+        }
+    }
+
+    @Override
+    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
+        final int childCount = getChildCount();
+        if (!consumed && childCount > 0 && canScrollList((int) velocityY) &&
+                Math.abs(velocityY) > mMinimumVelocity) {
+            reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
+            if (mFlingRunnable == null) {
+                mFlingRunnable = new FlingRunnable();
+            }
+            mFlingRunnable.start((int) velocityY);
+            return true;
+        }
+        return dispatchNestedFling(velocityX, velocityY, consumed);
+    }
+
+    @Override
     public void draw(Canvas canvas) {
         super.draw(canvas);
         if (mEdgeGlowTop != null) {
@@ -3925,8 +4036,8 @@
                 canvas.translate(leftPadding, edgeY);
                 mEdgeGlowTop.setSize(width, getHeight());
                 if (mEdgeGlowTop.draw(canvas)) {
-                    mEdgeGlowTop.setPosition(leftPadding, edgeY);
-                    invalidate(mEdgeGlowTop.getBounds(false));
+                    invalidate(0, 0, getWidth(),
+                            mEdgeGlowTop.getMaxHeight() + getPaddingTop());
                 }
                 canvas.restoreToCount(restoreCount);
             }
@@ -3943,9 +4054,9 @@
                 canvas.rotate(180, width, 0);
                 mEdgeGlowBottom.setSize(width, height);
                 if (mEdgeGlowBottom.draw(canvas)) {
-                    // Account for the rotation
-                    mEdgeGlowBottom.setPosition(edgeX + width, edgeY);
-                    invalidate(mEdgeGlowBottom.getBounds(true));
+                    invalidate(0, getHeight() - getPaddingBottom() -
+                            mEdgeGlowBottom.getMaxHeight(), getWidth(),
+                            getHeight());
                 }
                 canvas.restoreToCount(restoreCount);
             }
@@ -4046,6 +4157,7 @@
             mLastY = Integer.MIN_VALUE;
             initOrResetVelocityTracker();
             mVelocityTracker.addMovement(ev);
+            startNestedScroll(SCROLL_AXIS_VERTICAL);
             if (touchMode == TOUCH_MODE_FLING) {
                 return true;
             }
@@ -4063,7 +4175,7 @@
                 final int y = (int) ev.getY(pointerIndex);
                 initVelocityTrackerIfNotExists();
                 mVelocityTracker.addMovement(ev);
-                if (startScrollIfNeeded(y)) {
+                if (startScrollIfNeeded((int) ev.getX(pointerIndex), y, null)) {
                     return true;
                 }
                 break;
@@ -4077,6 +4189,7 @@
             mActivePointerId = INVALID_POINTER;
             recycleVelocityTracker();
             reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
+            stopNestedScroll();
             break;
         }
 
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 225cd6d..4f2d9c6 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -19,7 +19,9 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
+import android.graphics.Insets;
 import android.graphics.Rect;
+import android.graphics.Region.Op;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.util.AttributeSet;
@@ -32,9 +34,12 @@
 import com.android.internal.R;
 
 public abstract class AbsSeekBar extends ProgressBar {
+    private final Rect mTempRect = new Rect();
+
     private Drawable mThumb;
     private int mThumbOffset;
-    
+    private boolean mSplitTrack;
+
     /**
      * On touch, this offset plus the scaled value from the position of the
      * touch will form the progress value. Usually 0.
@@ -51,10 +56,10 @@
      * progress.
      */
     private int mKeyProgressIncrement = 1;
-    
+
     private static final int NO_ALPHA = 0xFF;
     private float mDisabledAlpha;
-    
+
     private int mScaledTouchSlop;
     private float mTouchDownX;
     private boolean mIsDragging;
@@ -76,12 +81,16 @@
 
         TypedArray a = context.obtainStyledAttributes(
                 attrs, com.android.internal.R.styleable.SeekBar, defStyleAttr, defStyleRes);
-        Drawable thumb = a.getDrawable(com.android.internal.R.styleable.SeekBar_thumb);
-        setThumb(thumb); // will guess mThumbOffset if thumb != null...
-        // ...but allow layout to override this
-        int thumbOffset = a.getDimensionPixelOffset(
+
+        final Drawable thumb = a.getDrawable(com.android.internal.R.styleable.SeekBar_thumb);
+        setThumb(thumb);
+
+        // Guess thumb offset if thumb != null, but allow layout to override.
+        final int thumbOffset = a.getDimensionPixelOffset(
                 com.android.internal.R.styleable.SeekBar_thumbOffset, getThumbOffset());
         setThumbOffset(thumbOffset);
+
+        mSplitTrack = a.getBoolean(com.android.internal.R.styleable.SeekBar_splitTrack, false);
         a.recycle();
 
         a = context.obtainStyledAttributes(attrs,
@@ -97,7 +106,7 @@
      * <p>
      * If the thumb is a valid drawable (i.e. not null), half its width will be
      * used as the new thumb offset (@see #setThumbOffset(int)).
-     * 
+     *
      * @param thumb Drawable representing the thumb
      */
     public void setThumb(Drawable thumb) {
@@ -132,7 +141,7 @@
         mThumb = thumb;
         invalidate();
         if (needUpdate) {
-            updateThumbPos(getWidth(), getHeight());
+            updateThumbAndTrackPos(getWidth(), getHeight());
             if (thumb != null && thumb.isStateful()) {
                 // Note that if the states are different this won't work.
                 // For now, let's consider that an app bug.
@@ -162,7 +171,7 @@
     /**
      * Sets the thumb offset that allows the thumb to extend out of the range of
      * the track.
-     * 
+     *
      * @param thumbOffset The offset amount in pixels.
      */
     public void setThumbOffset(int thumbOffset) {
@@ -171,8 +180,27 @@
     }
 
     /**
+     * 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.
+     *
+     * @param splitTrack Whether the track should be split by the thumb
+     */
+    public void setSplitTrack(boolean splitTrack) {
+        mSplitTrack = splitTrack;
+        invalidate();
+    }
+
+    /**
+     * Returns whether the track should be split by the thumb.
+     */
+    public boolean getSplitTrack() {
+        return mSplitTrack;
+    }
+
+    /**
      * Sets the amount of progress changed via the arrow keys.
-     * 
+     *
      * @param increment The amount to increment or decrement when the user
      *            presses the arrow keys.
      */
@@ -184,14 +212,14 @@
      * Returns the amount of progress changed via the arrow keys.
      * <p>
      * By default, this will be a value that is derived from the max progress.
-     * 
+     *
      * @return The amount to increment or decrement when the user presses the
      *         arrow keys. This will be positive.
      */
     public int getKeyProgressIncrement() {
         return mKeyProgressIncrement;
     }
-    
+
     @Override
     public synchronized void setMax(int max) {
         super.setMax(max);
@@ -217,79 +245,85 @@
     @Override
     protected void drawableStateChanged() {
         super.drawableStateChanged();
-        
-        Drawable progressDrawable = getProgressDrawable();
+
+        final Drawable progressDrawable = getProgressDrawable();
         if (progressDrawable != null) {
             progressDrawable.setAlpha(isEnabled() ? NO_ALPHA : (int) (NO_ALPHA * mDisabledAlpha));
         }
-        
-        if (mThumb != null && mThumb.isStateful()) {
-            int[] state = getDrawableState();
-            mThumb.setState(state);
+
+        final Drawable thumb = mThumb;
+        if (thumb != null && thumb.isStateful()) {
+            thumb.setState(getDrawableState());
         }
     }
-    
+
     @Override
     void onProgressRefresh(float scale, boolean fromUser) {
         super.onProgressRefresh(scale, fromUser);
-        Drawable thumb = mThumb;
+
+        final Drawable thumb = mThumb;
         if (thumb != null) {
             setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE);
-            /*
-             * Since we draw translated, the drawable's bounds that it signals
-             * for invalidation won't be the actual bounds we want invalidated,
-             * so just invalidate this whole view.
-             */
+
+            // Since we draw translated, the drawable's bounds that it signals
+            // for invalidation won't be the actual bounds we want invalidated,
+            // so just invalidate this whole view.
             invalidate();
         }
     }
-    
-    
+
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
-        updateThumbPos(w, h);
+
+        updateThumbAndTrackPos(w, h);
     }
 
-    private void updateThumbPos(int w, int h) {
-        Drawable d = getCurrentDrawable();
-        Drawable thumb = mThumb;
-        int thumbHeight = thumb == null ? 0 : thumb.getIntrinsicHeight();
+    private void updateThumbAndTrackPos(int w, int h) {
+        final Drawable track = getCurrentDrawable();
+        final Drawable thumb = mThumb;
+
         // The max height does not incorporate padding, whereas the height
-        // parameter does
-        int trackHeight = Math.min(mMaxHeight, h - mPaddingTop - mPaddingBottom);
-        
-        int max = getMax();
-        float scale = max > 0 ? (float) getProgress() / (float) max : 0;
-        
+        // parameter does.
+        final int trackHeight = Math.min(mMaxHeight, h - mPaddingTop - mPaddingBottom);
+        final int thumbHeight = thumb == null ? 0 : thumb.getIntrinsicHeight();
+
+        // Apply offset to whichever item is taller.
+        final int trackOffset;
+        final int thumbOffset;
         if (thumbHeight > trackHeight) {
-            if (thumb != null) {
-                setThumbPos(w, thumb, scale, 0);
-            }
-            int gapForCenteringTrack = (thumbHeight - trackHeight) / 2;
-            if (d != null) {
-                // Canvas will be translated by the padding, so 0,0 is where we start drawing
-                d.setBounds(0, gapForCenteringTrack, 
-                        w - mPaddingRight - mPaddingLeft, h - mPaddingBottom - gapForCenteringTrack
-                        - mPaddingTop);
-            }
+            trackOffset = (thumbHeight - trackHeight) / 2;
+            thumbOffset = 0;
         } else {
-            if (d != null) {
-                // Canvas will be translated by the padding, so 0,0 is where we start drawing
-                d.setBounds(0, 0, w - mPaddingRight - mPaddingLeft, h - mPaddingBottom
-                        - mPaddingTop);
-            }
-            int gap = (trackHeight - thumbHeight) / 2;
-            if (thumb != null) {
-                setThumbPos(w, thumb, scale, gap);
-            }
+            trackOffset = 0;
+            thumbOffset = (trackHeight - thumbHeight) / 2;
+        }
+
+        if (track != null) {
+            track.setBounds(0, trackOffset, w - mPaddingRight - mPaddingLeft,
+                    h - mPaddingBottom - trackOffset - mPaddingTop);
+        }
+
+        if (thumb != null) {
+            setThumbPos(w, thumb, getScale(), thumbOffset);
         }
     }
 
+    private float getScale() {
+        final int max = getMax();
+        return max > 0 ? getProgress() / (float) max : 0;
+    }
+
     /**
-     * @param gap If set to {@link Integer#MIN_VALUE}, this will be ignored and
+     * Updates the thumb drawable bounds.
+     *
+     * @param w Width of the view, including padding
+     * @param thumb Drawable used for the thumb
+     * @param scale Current progress between 0 and 1
+     * @param offset Vertical offset for centering. If set to
+     *            {@link Integer#MIN_VALUE}, the current offset will be used.
      */
-    private void setThumbPos(int w, Drawable thumb, float scale, int gap) {
+    private void setThumbPos(int w, Drawable thumb, float scale, int offset) {
         int available = w - mPaddingLeft - mPaddingRight;
         final int thumbWidth = thumb.getIntrinsicWidth();
         final int thumbHeight = thumb.getIntrinsicHeight();
@@ -301,13 +335,13 @@
         final int thumbPos = (int) (scale * available + 0.5f);
 
         final int top, bottom;
-        if (gap == Integer.MIN_VALUE) {
+        if (offset == Integer.MIN_VALUE) {
             final Rect oldBounds = thumb.getBounds();
             top = oldBounds.top;
             bottom = oldBounds.bottom;
         } else {
-            top = gap;
-            bottom = gap + thumbHeight;
+            top = offset;
+            bottom = offset + thumbHeight;
         }
 
         final int left = (isLayoutRtl() && mMirrorForRtl) ? available - thumbPos : thumbPos;
@@ -342,6 +376,33 @@
     protected synchronized void onDraw(Canvas canvas) {
         super.onDraw(canvas);
 
+        drawThumb(canvas);
+    }
+
+    @Override
+    void drawTrack(Canvas canvas) {
+        final Drawable thumbDrawable = mThumb;
+        if (thumbDrawable != null && mSplitTrack) {
+            final Insets insets = thumbDrawable.getOpticalInsets();
+            final Rect tempRect = mTempRect;
+            thumbDrawable.copyBounds(tempRect);
+            tempRect.offset(mPaddingLeft - mThumbOffset, mPaddingTop);
+            tempRect.left += insets.left;
+            tempRect.right -= insets.right;
+
+            final int saveCount = canvas.save();
+            canvas.clipRect(tempRect, Op.DIFFERENCE);
+            super.drawTrack(canvas);
+            canvas.restoreToCount(saveCount);
+        } else {
+            super.drawTrack(canvas);
+        }
+    }
+
+    /**
+     * Draw the thumb.
+     */
+    void drawThumb(Canvas canvas) {
         if (mThumb != null) {
             canvas.save();
             // Translate the padding. For the x, we need to allow the thumb to
@@ -366,17 +427,17 @@
         }
         dw += mPaddingLeft + mPaddingRight;
         dh += mPaddingTop + mPaddingBottom;
-        
+
         setMeasuredDimension(resolveSizeAndState(dw, widthMeasureSpec, 0),
                 resolveSizeAndState(dh, heightMeasureSpec, 0));
     }
-    
+
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         if (!mIsUserSeekable || !isEnabled()) {
             return false;
         }
-        
+
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 if (isInScrollingContainer()) {
@@ -391,7 +452,7 @@
                     attemptClaimDrag();
                 }
                 break;
-                
+
             case MotionEvent.ACTION_MOVE:
                 if (mIsDragging) {
                     trackTouchEvent(event);
@@ -408,7 +469,7 @@
                     }
                 }
                 break;
-                
+
             case MotionEvent.ACTION_UP:
                 if (mIsDragging) {
                     trackTouchEvent(event);
@@ -426,7 +487,7 @@
                 // value has not apparently changed)
                 invalidate();
                 break;
-                
+
             case MotionEvent.ACTION_CANCEL:
                 if (mIsDragging) {
                     onStopTrackingTouch();
@@ -493,7 +554,7 @@
             mParent.requestDisallowInterceptTouchEvent(true);
         }
     }
-    
+
     /**
      * This is called when the user has started touching this widget.
      */
@@ -526,7 +587,7 @@
                     setProgress(progress - mKeyProgressIncrement, true);
                     onKeyChange();
                     return true;
-            
+
                 case KeyEvent.KEYCODE_DPAD_RIGHT:
                     if (progress >= getMax()) break;
                     setProgress(progress + mKeyProgressIncrement, true);
@@ -595,17 +656,13 @@
     public void onRtlPropertiesChanged(int layoutDirection) {
         super.onRtlPropertiesChanged(layoutDirection);
 
-        int max = getMax();
-        float scale = max > 0 ? (float) getProgress() / (float) max : 0;
-
-        Drawable thumb = mThumb;
+        final Drawable thumb = mThumb;
         if (thumb != null) {
-            setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE);
-            /*
-             * Since we draw translated, the drawable's bounds that it signals
-             * for invalidation won't be the actual bounds we want invalidated,
-             * so just invalidate this whole view.
-             */
+            setThumbPos(getWidth(), thumb, getScale(), Integer.MIN_VALUE);
+
+            // Since we draw translated, the drawable's bounds that it signals
+            // for invalidation won't be the actual bounds we want invalidated,
+            // so just invalidate this whole view.
             invalidate();
         }
     }
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index e4575e5..51759c5 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -649,7 +649,8 @@
     private class OverflowPopup extends MenuPopupHelper {
         public OverflowPopup(Context context, MenuBuilder menu, View anchorView,
                 boolean overflowOnly) {
-            super(context, menu, anchorView, overflowOnly);
+            super(context, menu, anchorView, overflowOnly,
+                    com.android.internal.R.attr.actionOverflowMenuStyle);
             setGravity(Gravity.END);
             setCallback(mPopupPresenterCallback);
         }
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index fa37443..c4a40b4 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -16,13 +16,16 @@
 
 package android.widget;
 
+import android.content.res.TypedArray;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
-import com.android.internal.R;
+import android.graphics.RectF;
 
 import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
+import android.util.FloatMath;
 import android.view.animation.AnimationUtils;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
@@ -55,16 +58,11 @@
     // Time it will take before a pulled glow begins receding in ms
     private static final int PULL_TIME = 167;
 
-    // Time it will take in ms for a pulled glow to decay to partial strength before release
-    private static final int PULL_DECAY_TIME = 1000;
-
     private static final float MAX_ALPHA = 1.f;
-    private static final float HELD_EDGE_SCALE_Y = 0.5f;
 
-    private static final float MAX_GLOW_HEIGHT = 4.f;
+    private static final float MAX_GLOW_SCALE = 2.f;
 
-    private static final float PULL_GLOW_BEGIN = 1.f;
-    private static final float PULL_EDGE_BEGIN = 0.6f;
+    private static final float PULL_GLOW_BEGIN = 0.f;
 
     // Minimum velocity that will be absorbed
     private static final int MIN_VELOCITY = 100;
@@ -73,24 +71,13 @@
 
     private static final float EPSILON = 0.001f;
 
-    private final Drawable mEdge;
-    private final Drawable mGlow;
-    private int mWidth;
-    private int mHeight;
-    private int mX;
-    private int mY;
-    private static final int MIN_WIDTH = 300;
-    private final int mMinWidth;
+    private static final double ANGLE = Math.PI / 6;
+    private static final float SIN = (float) Math.sin(ANGLE);
+    private static final float COS = (float) Math.cos(ANGLE);
 
-    private float mEdgeAlpha;
-    private float mEdgeScaleY;
     private float mGlowAlpha;
     private float mGlowScaleY;
 
-    private float mEdgeAlphaStart;
-    private float mEdgeAlphaFinish;
-    private float mEdgeScaleYStart;
-    private float mEdgeScaleYFinish;
     private float mGlowAlphaStart;
     private float mGlowAlphaFinish;
     private float mGlowScaleYStart;
@@ -107,16 +94,11 @@
     private static final int STATE_RECEDE = 3;
     private static final int STATE_PULL_DECAY = 4;
 
-    // How much dragging should effect the height of the edge image.
-    // Number determined by user testing.
-    private static final int PULL_DISTANCE_EDGE_FACTOR = 7;
-
     // How much dragging should effect the height of the glow image.
     // Number determined by user testing.
     private static final int PULL_DISTANCE_GLOW_FACTOR = 7;
     private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 1.1f;
 
-    private static final int VELOCITY_EDGE_FACTOR = 8;
     private static final int VELOCITY_GLOW_FACTOR = 12;
 
     private int mState = STATE_IDLE;
@@ -124,30 +106,27 @@
     private float mPullDistance;
     
     private final Rect mBounds = new Rect();
-
-    private final int mEdgeHeight;
-    private final int mGlowHeight;
-    private final int mGlowWidth;
-    private final int mMaxEffectHeight;
+    private final RectF mArcRect = new RectF();
+    private final Paint mPaint = new Paint();
+    private float mRadius;
+    private float mBaseGlowHeight;
+    private float mDisplacement = 0.5f;
+    private float mTargetDisplacement = 0.5f;
 
     /**
      * Construct a new EdgeEffect with a theme appropriate for the provided context.
      * @param context Context used to provide theming and resource information for the EdgeEffect
      */
     public EdgeEffect(Context context) {
-        final Resources res = context.getResources();
-        mEdge = context.getDrawable(R.drawable.overscroll_edge);
-        mGlow = context.getDrawable(R.drawable.overscroll_glow);
-
-        mEdgeHeight = mEdge.getIntrinsicHeight();
-        mGlowHeight = mGlow.getIntrinsicHeight();
-        mGlowWidth = mGlow.getIntrinsicWidth();
-
-        mMaxEffectHeight = (int) (Math.min(
-                mGlowHeight * MAX_GLOW_HEIGHT * mGlowHeight / mGlowWidth * 0.6f,
-                mGlowHeight * MAX_GLOW_HEIGHT) + 0.5f);
-
-        mMinWidth = (int) (res.getDisplayMetrics().density * MIN_WIDTH + 0.5f);
+        mPaint.setAntiAlias(true);
+        final TypedArray a = context.obtainStyledAttributes(
+                com.android.internal.R.styleable.EdgeEffect);
+        final int themeColor = a.getColor(
+                com.android.internal.R.styleable.EdgeEffect_colorPrimaryLight, 0xff666666);
+        a.recycle();
+        mPaint.setColor((themeColor & 0xffffff) | 0x33000000);
+        mPaint.setStyle(Paint.Style.FILL);
+        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
         mInterpolator = new DecelerateInterpolator();
     }
 
@@ -158,20 +137,13 @@
      * @param height Effect height in pixels
      */
     public void setSize(int width, int height) {
-        mWidth = width;
-        mHeight = height;
-    }
+        final float r = width * 0.75f / SIN;
+        final float y = COS * r;
+        final float h = r - y;
+        mRadius = r;
+        mBaseGlowHeight = h;
 
-    /**
-     * Set the position of this edge effect in pixels. This position is
-     * only used by {@link #getBounds(boolean)}.
-     * 
-     * @param x The position of the edge effect on the X axis
-     * @param y The position of the edge effect on the Y axis
-     */
-    void setPosition(int x, int y) {
-        mX = x;
-        mY = y;
+        mBounds.set(mBounds.left, mBounds.top, width, (int) Math.min(height, h));
     }
 
     /**
@@ -199,17 +171,38 @@
      * The host view should always {@link android.view.View#invalidate()} after this
      * and draw the results accordingly.
      *
+     * <p>Views using EdgeEffect should favor {@link #onPull(float, float)} when the displacement
+     * of the pull point is known.</p>
+     *
      * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to
      *                      1.f (full length of the view) or negative values to express change
      *                      back toward the edge reached to initiate the effect.
      */
     public void onPull(float deltaDistance) {
+        onPull(deltaDistance, 0.5f);
+    }
+
+    /**
+     * A view should call this when content is pulled away from an edge by the user.
+     * This will update the state of the current visual effect and its associated animation.
+     * The host view should always {@link android.view.View#invalidate()} after this
+     * and draw the results accordingly.
+     *
+     * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to
+     *                      1.f (full length of the view) or negative values to express change
+     *                      back toward the edge reached to initiate the effect.
+     * @param displacement The displacement from the starting side of the effect of the point
+     *                     initiating the pull. In the case of touch this is the finger position.
+     *                     Values may be from 0-1.
+     */
+    public void onPull(float deltaDistance, float displacement) {
         final long now = AnimationUtils.currentAnimationTimeMillis();
+        mTargetDisplacement = displacement;
         if (mState == STATE_PULL_DECAY && now - mStartTime < mDuration) {
             return;
         }
         if (mState != STATE_PULL) {
-            mGlowScaleY = PULL_GLOW_BEGIN;
+            mGlowScaleY = Math.max(PULL_GLOW_BEGIN, mGlowScaleY);
         }
         mState = STATE_PULL;
 
@@ -217,30 +210,20 @@
         mDuration = PULL_TIME;
 
         mPullDistance += deltaDistance;
-        float distance = Math.abs(mPullDistance);
 
-        mEdgeAlpha = mEdgeAlphaStart = Math.max(PULL_EDGE_BEGIN, Math.min(distance, MAX_ALPHA));
-        mEdgeScaleY = mEdgeScaleYStart = Math.max(
-                HELD_EDGE_SCALE_Y, Math.min(distance * PULL_DISTANCE_EDGE_FACTOR, 1.f));
-
+        final float absdd = Math.abs(deltaDistance);
         mGlowAlpha = mGlowAlphaStart = Math.min(MAX_ALPHA,
-                mGlowAlpha +
-                (Math.abs(deltaDistance) * PULL_DISTANCE_ALPHA_GLOW_FACTOR));
+                mGlowAlpha + (absdd * PULL_DISTANCE_ALPHA_GLOW_FACTOR));
 
-        float glowChange = Math.abs(deltaDistance);
-        if (deltaDistance > 0 && mPullDistance < 0) {
-            glowChange = -glowChange;
-        }
         if (mPullDistance == 0) {
-            mGlowScaleY = 0;
+            mGlowScaleY = mGlowScaleYStart = 0;
+        } else {
+            final float scale = Math.max(0, 1 - 1 /
+                    FloatMath.sqrt(Math.abs(mPullDistance) * mBounds.height()) - 0.3f) / 0.7f;
+
+            mGlowScaleY = mGlowScaleYStart = scale;
         }
 
-        // Do not allow glow to get larger than MAX_GLOW_HEIGHT.
-        mGlowScaleY = mGlowScaleYStart = Math.min(MAX_GLOW_HEIGHT, Math.max(
-                0, mGlowScaleY + glowChange * PULL_DISTANCE_GLOW_FACTOR));
-
-        mEdgeAlphaFinish = mEdgeAlpha;
-        mEdgeScaleYFinish = mEdgeScaleY;
         mGlowAlphaFinish = mGlowAlpha;
         mGlowScaleYFinish = mGlowScaleY;
     }
@@ -259,13 +242,9 @@
         }
 
         mState = STATE_RECEDE;
-        mEdgeAlphaStart = mEdgeAlpha;
-        mEdgeScaleYStart = mEdgeScaleY;
         mGlowAlphaStart = mGlowAlpha;
         mGlowScaleYStart = mGlowScaleY;
 
-        mEdgeAlphaFinish = 0.f;
-        mEdgeScaleYFinish = 0.f;
         mGlowAlphaFinish = 0.f;
         mGlowScaleYFinish = 0.f;
 
@@ -290,30 +269,21 @@
         mStartTime = AnimationUtils.currentAnimationTimeMillis();
         mDuration = 0.15f + (velocity * 0.02f);
 
-        // The edge should always be at least partially visible, regardless
-        // of velocity.
-        mEdgeAlphaStart = 0.f;
-        mEdgeScaleY = mEdgeScaleYStart = 0.f;
         // The glow depends more on the velocity, and therefore starts out
         // nearly invisible.
         mGlowAlphaStart = 0.3f;
-        mGlowScaleYStart = 0.f;
+        mGlowScaleYStart = Math.max(mGlowScaleY, 0.f);
 
-        // Factor the velocity by 8. Testing on device shows this works best to
-        // reflect the strength of the user's scrolling.
-        mEdgeAlphaFinish = Math.max(0, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1));
-        // Edge should never get larger than the size of its asset.
-        mEdgeScaleYFinish = Math.max(
-                HELD_EDGE_SCALE_Y, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1.f));
 
         // Growth for the size of the glow should be quadratic to properly
         // respond
         // to a user's scrolling speed. The faster the scrolling speed, the more
         // intense the effect should be for both the size and the saturation.
-        mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f), 1.75f);
+        mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f) / 2, 1.f);
         // Alpha should change for the glow as well as size.
         mGlowAlphaFinish = Math.max(
                 mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA));
+        mTargetDisplacement = 0.5f;
     }
 
 
@@ -330,52 +300,40 @@
     public boolean draw(Canvas canvas) {
         update();
 
-        mGlow.setAlpha((int) (Math.max(0, Math.min(mGlowAlpha, 1)) * 255));
+        final int count = canvas.save();
 
-        int glowBottom = (int) Math.min(
-                mGlowHeight * mGlowScaleY * mGlowHeight / mGlowWidth * 0.6f,
-                mGlowHeight * MAX_GLOW_HEIGHT);
-        if (mWidth < mMinWidth) {
-            // Center the glow and clip it.
-            int glowLeft = (mWidth - mMinWidth)/2;
-            mGlow.setBounds(glowLeft, 0, mWidth - glowLeft, glowBottom);
-        } else {
-            // Stretch the glow to fit.
-            mGlow.setBounds(0, 0, mWidth, glowBottom);
-        }
+        final float y = mBounds.height();
+        final float centerY = y - mRadius;
+        final float centerX = mBounds.centerX();
 
-        mGlow.draw(canvas);
+        mArcRect.set(centerX - mRadius, centerY - mRadius, centerX + mRadius, centerY + mRadius);
+        canvas.scale(1.f, Math.min(mGlowScaleY, 1.f), centerX, 0);
 
-        mEdge.setAlpha((int) (Math.max(0, Math.min(mEdgeAlpha, 1)) * 255));
+        final float displacement = Math.max(0, Math.min(mDisplacement, 1.f)) - 0.5f;
+        float translateX = mBounds.width() * displacement / 2;
 
-        int edgeBottom = (int) (mEdgeHeight * mEdgeScaleY);
-        if (mWidth < mMinWidth) {
-            // Center the edge and clip it.
-            int edgeLeft = (mWidth - mMinWidth)/2;
-            mEdge.setBounds(edgeLeft, 0, mWidth - edgeLeft, edgeBottom);
-        } else {
-            // Stretch the edge to fit.
-            mEdge.setBounds(0, 0, mWidth, edgeBottom);
-        }
-        mEdge.draw(canvas);
+        canvas.clipRect(Float.MIN_VALUE, mBounds.top,
+                Float.MAX_VALUE, Float.MAX_VALUE);
+        canvas.translate(translateX, 0);
+        canvas.drawArc(mArcRect, 45, 90, true, mPaint);
+        canvas.restoreToCount(count);
 
-        if (mState == STATE_RECEDE && glowBottom == 0 && edgeBottom == 0) {
+        boolean oneLastFrame = false;
+        if (mState == STATE_RECEDE && mGlowScaleY == 0) {
             mState = STATE_IDLE;
+            oneLastFrame = true;
         }
 
-        return mState != STATE_IDLE;
+        return mState != STATE_IDLE || oneLastFrame;
     }
 
     /**
-     * Returns the bounds of the edge effect.
-     * 
-     * @hide
+     * Return the maximum height that the edge effect will be drawn at given the original
+     * {@link #setSize(int, int) input size}.
+     * @return The maximum height of the edge effect
      */
-    public Rect getBounds(boolean reverse) {
-        mBounds.set(0, 0, mWidth, mMaxEffectHeight);
-        mBounds.offset(mX, mY - (reverse ? mMaxEffectHeight : 0));
-
-        return mBounds;
+    public int getMaxHeight() {
+        return (int) (mBounds.height() * MAX_GLOW_SCALE + 0.5f);
     }
 
     private void update() {
@@ -384,10 +342,9 @@
 
         final float interp = mInterpolator.getInterpolation(t);
 
-        mEdgeAlpha = mEdgeAlphaStart + (mEdgeAlphaFinish - mEdgeAlphaStart) * interp;
-        mEdgeScaleY = mEdgeScaleYStart + (mEdgeScaleYFinish - mEdgeScaleYStart) * interp;
         mGlowAlpha = mGlowAlphaStart + (mGlowAlphaFinish - mGlowAlphaStart) * interp;
         mGlowScaleY = mGlowScaleYStart + (mGlowScaleYFinish - mGlowScaleYStart) * interp;
+        mDisplacement = (mDisplacement + mTargetDisplacement) / 2;
 
         if (t >= 1.f - EPSILON) {
             switch (mState) {
@@ -396,42 +353,17 @@
                     mStartTime = AnimationUtils.currentAnimationTimeMillis();
                     mDuration = RECEDE_TIME;
 
-                    mEdgeAlphaStart = mEdgeAlpha;
-                    mEdgeScaleYStart = mEdgeScaleY;
                     mGlowAlphaStart = mGlowAlpha;
                     mGlowScaleYStart = mGlowScaleY;
 
-                    // After absorb, the glow and edge should fade to nothing.
-                    mEdgeAlphaFinish = 0.f;
-                    mEdgeScaleYFinish = 0.f;
+                    // After absorb, the glow should fade to nothing.
                     mGlowAlphaFinish = 0.f;
                     mGlowScaleYFinish = 0.f;
                     break;
                 case STATE_PULL:
-                    mState = STATE_PULL_DECAY;
-                    mStartTime = AnimationUtils.currentAnimationTimeMillis();
-                    mDuration = PULL_DECAY_TIME;
-
-                    mEdgeAlphaStart = mEdgeAlpha;
-                    mEdgeScaleYStart = mEdgeScaleY;
-                    mGlowAlphaStart = mGlowAlpha;
-                    mGlowScaleYStart = mGlowScaleY;
-
-                    // After pull, the glow and edge should fade to nothing.
-                    mEdgeAlphaFinish = 0.f;
-                    mEdgeScaleYFinish = 0.f;
-                    mGlowAlphaFinish = 0.f;
-                    mGlowScaleYFinish = 0.f;
+                    // Hold in this state until explicitly released.
                     break;
                 case STATE_PULL_DECAY:
-                    // When receding, we want edge to decrease more slowly
-                    // than the glow.
-                    float factor = mGlowScaleYFinish != 0 ? 1
-                            / (mGlowScaleYFinish * mGlowScaleYFinish)
-                            : Float.MAX_VALUE;
-                    mEdgeScaleY = mEdgeScaleYStart +
-                        (mEdgeScaleYFinish - mEdgeScaleYStart) *
-                            interp * factor;
                     mState = STATE_RECEDE;
                     break;
                 case STATE_RECEDE:
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index b0a4e24..27d6b82 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -39,6 +39,7 @@
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.Rect;
@@ -94,6 +95,8 @@
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.view.inputmethod.CorrectionInfo;
+import android.view.inputmethod.CursorAnchorInfo;
+import android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
@@ -215,6 +218,8 @@
 
     private TextView mTextView;
 
+    final CursorAnchorInfoNotifier mCursorAnchorInfoNotifier = new CursorAnchorInfoNotifier();
+
     Editor(TextView textView) {
         mTextView = textView;
     }
@@ -249,9 +254,13 @@
             // We had an active selection from before, start the selection mode.
             startSelectionActionMode();
         }
+
+        getPositionListener().addSubscriber(mCursorAnchorInfoNotifier, true);
     }
 
     void onDetachedFromWindow() {
+        getPositionListener().removeSubscriber(mCursorAnchorInfoNotifier);
+
         if (mError != null) {
             hideError();
         }
@@ -780,7 +789,7 @@
                 boolean parentPositionChanged, boolean parentScrolled);
     }
 
-    private boolean isPositionVisible(int positionX, int positionY) {
+    private boolean isPositionVisible(final float positionX, final float positionY) {
         synchronized (TEMP_POSITION) {
             final float[] position = TEMP_POSITION;
             position[0] = positionX;
@@ -2134,7 +2143,8 @@
     private class PositionListener implements ViewTreeObserver.OnPreDrawListener {
         // 3 handles
         // 3 ActionPopup [replace, suggestion, easyedit] (suggestionsPopup first hides the others)
-        private final int MAXIMUM_NUMBER_OF_LISTENERS = 6;
+        // 1 CursorAnchorInfoNotifier
+        private final int MAXIMUM_NUMBER_OF_LISTENERS = 7;
         private TextViewPositionListener[] mPositionListeners =
                 new TextViewPositionListener[MAXIMUM_NUMBER_OF_LISTENERS];
         private boolean mCanMove[] = new boolean[MAXIMUM_NUMBER_OF_LISTENERS];
@@ -2997,6 +3007,122 @@
         }
     }
 
+    /**
+     * A listener to call {@link InputMethodManager#updateCursorAnchorInfo(View, CursorAnchorInfo)}
+     * while the input method is requesting the cursor/anchor position. Does nothing as long as
+     * {@link InputMethodManager#isWatchingCursor(View)} returns false.
+     */
+    private final class CursorAnchorInfoNotifier implements TextViewPositionListener {
+        final CursorAnchorInfoBuilder mSelectionInfoBuilder = new CursorAnchorInfoBuilder();
+        final int[] mTmpIntOffset = new int[2];
+        final Matrix mViewToScreenMatrix = new Matrix();
+
+        @Override
+        public void updatePosition(int parentPositionX, int parentPositionY,
+                boolean parentPositionChanged, boolean parentScrolled) {
+            final InputMethodState ims = mInputMethodState;
+            if (ims == null || ims.mBatchEditNesting > 0) {
+                return;
+            }
+            final InputMethodManager imm = InputMethodManager.peekInstance();
+            if (null == imm) {
+                return;
+            }
+            // Skip if the IME has not requested the cursor/anchor position.
+            if (!imm.isWatchingCursor(mTextView)) {
+                return;
+            }
+            Layout layout = mTextView.getLayout();
+            if (layout == null) {
+                return;
+            }
+
+            final CursorAnchorInfoBuilder builder = mSelectionInfoBuilder;
+            builder.reset();
+
+            final int selectionStart = mTextView.getSelectionStart();
+            builder.setSelectionRange(selectionStart, mTextView.getSelectionEnd());
+
+            // Construct transformation matrix from view local coordinates to screen coordinates.
+            mViewToScreenMatrix.set(mTextView.getMatrix());
+            mTextView.getLocationOnScreen(mTmpIntOffset);
+            mViewToScreenMatrix.postTranslate(mTmpIntOffset[0], mTmpIntOffset[1]);
+            builder.setMatrix(mViewToScreenMatrix);
+
+            final float viewportToContentHorizontalOffset =
+                    mTextView.viewportToContentHorizontalOffset();
+            final float viewportToContentVerticalOffset =
+                    mTextView.viewportToContentVerticalOffset();
+
+            final CharSequence text = mTextView.getText();
+            if (text instanceof Spannable) {
+                final Spannable sp = (Spannable) text;
+                int composingTextStart = EditableInputConnection.getComposingSpanStart(sp);
+                int composingTextEnd = EditableInputConnection.getComposingSpanEnd(sp);
+                if (composingTextEnd < composingTextStart) {
+                    final int temp = composingTextEnd;
+                    composingTextEnd = composingTextStart;
+                    composingTextStart = temp;
+                }
+                final boolean hasComposingText =
+                        (0 <= composingTextStart) && (composingTextStart < composingTextEnd);
+                if (hasComposingText) {
+                    final CharSequence composingText = text.subSequence(composingTextStart,
+                            composingTextEnd);
+                    builder.setComposingText(composingTextStart, composingText);
+                }
+                for (int offset = composingTextStart; offset < composingTextEnd; offset++) {
+                    if (offset < 0) {
+                        continue;
+                    }
+                    final int line = layout.getLineForOffset(offset);
+                    final float left = layout.getPrimaryHorizontal(offset)
+                            + viewportToContentHorizontalOffset;
+                    final float top = layout.getLineTop(line) + viewportToContentVerticalOffset;
+                    // Here we are tentatively passing offset + 1 to calculate the other side of
+                    // the primary horizontal to preserve as many positions as possible so that
+                    // the IME can reconstruct the layout entirely. However, we should revisit this
+                    // to have a clear specification about the relationship between the index of
+                    // the character and its bounding box. See also the TODO comment below.
+                    final float right = layout.getPrimaryHorizontal(offset + 1)
+                            + viewportToContentHorizontalOffset;
+                    final float bottom = layout.getLineBottom(line)
+                            + viewportToContentVerticalOffset;
+                    // Take TextView's padding and scroll into account.
+                    if (isPositionVisible(left, top) && isPositionVisible(right, bottom)) {
+                        // Here offset is the index in Java chars.
+                        // TODO: We must have a well-defined specification. For example, how
+                        // RTL, surrogate pairs, and composition letters are handled must be
+                        // documented.
+                        builder.addCharacterRect(offset, left, top, right, bottom);
+                    }
+                }
+            }
+
+            // Treat selectionStart as the insertion point.
+            if (0 <= selectionStart) {
+                final int offset = selectionStart;
+                final int line = layout.getLineForOffset(offset);
+                final float insertionMarkerX = layout.getPrimaryHorizontal(offset)
+                        + viewportToContentHorizontalOffset;
+                final float insertionMarkerTop = layout.getLineTop(line)
+                        + viewportToContentVerticalOffset;
+                final float insertionMarkerBaseline = layout.getLineBaseline(line)
+                        + viewportToContentVerticalOffset;
+                final float insertionMarkerBottom = layout.getLineBottom(line)
+                        + viewportToContentVerticalOffset;
+                // Take TextView's padding and scroll into account.
+                if (isPositionVisible(insertionMarkerX, insertionMarkerTop) &&
+                        isPositionVisible(insertionMarkerX, insertionMarkerBottom)) {
+                    builder.setInsertionMarkerLocation(insertionMarkerX, insertionMarkerTop,
+                            insertionMarkerBaseline, insertionMarkerBottom);
+                }
+            }
+
+            imm.updateCursorAnchorInfo(mTextView, builder.build());
+        }
+    }
+
     private abstract class HandleView extends View implements TextViewPositionListener {
         protected Drawable mDrawable;
         protected Drawable mDrawableLtr;
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 25d4f42..0c65c50 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -616,12 +616,14 @@
                     if (canOverscroll) {
                         final int pulledToX = oldX + deltaX;
                         if (pulledToX < 0) {
-                            mEdgeGlowLeft.onPull((float) deltaX / getWidth());
+                            mEdgeGlowLeft.onPull((float) deltaX / getWidth(),
+                                    1.f - ev.getY(activePointerIndex) / getHeight());
                             if (!mEdgeGlowRight.isFinished()) {
                                 mEdgeGlowRight.onRelease();
                             }
                         } else if (pulledToX > range) {
-                            mEdgeGlowRight.onPull((float) deltaX / getWidth());
+                            mEdgeGlowRight.onPull((float) deltaX / getWidth(),
+                                    ev.getY(activePointerIndex) / getHeight());
                             if (!mEdgeGlowLeft.isFinished()) {
                                 mEdgeGlowLeft.onRelease();
                             }
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index b47177a..f91865b 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -622,8 +622,8 @@
             // only set this if the dropdown is not always visible
             mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible);
             mPopup.setTouchInterceptor(mTouchInterceptor);
-            mPopup.showAsDropDown(getAnchorView(),
-                    mDropDownHorizontalOffset, mDropDownVerticalOffset, mDropDownGravity);
+            mPopup.showAsDropDown(getAnchorView(), mDropDownHorizontalOffset,
+                    mDropDownVerticalOffset, mDropDownGravity);
             mDropDownList.setSelection(ListView.INVALID_POSITION);
             
             if (!mModal || mDropDownList.isInTouchMode()) {
@@ -1565,7 +1565,7 @@
 
             // Ensure that keyboard focus starts from the last touched position.
             setSelectedPositionInt(position);
-            positionSelector(position, child);
+            positionSelectorLikeFocus(position, child);
 
             // Refresh the drawable state to reflect the new pressed state,
             // which will also update the selector state.
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 5de67c8..eeb8015 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -2564,7 +2564,7 @@
 
         if (needToRedraw) {
             if (selectedView != null) {
-                positionSelector(selectedPos, selectedView);
+                positionSelectorLikeFocus(selectedPos, selectedView);
                 mSelectedTop = selectedView.getTop();
             }
             if (!awakenScrollBars()) {
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 6e71a5c..01632ae 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -18,6 +18,7 @@
 
 import com.android.internal.R;
 
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -116,6 +117,10 @@
     private Drawable mAboveAnchorBackgroundDrawable;
     private Drawable mBelowAnchorBackgroundDrawable;
 
+    // Temporary animation centers. Should be moved into window params?
+    private int mAnchorRelativeX;
+    private int mAnchorRelativeY;
+
     private boolean mAboveAnchor;
     private int mWindowLayoutType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
     
@@ -129,12 +134,14 @@
     };
 
     private WeakReference<View> mAnchor;
-    private OnScrollChangedListener mOnScrollChangedListener =
+
+    private final OnScrollChangedListener mOnScrollChangedListener =
         new OnScrollChangedListener() {
+            @Override
             public void onScrollChanged() {
-                View anchor = mAnchor != null ? mAnchor.get() : null;
+                final View anchor = mAnchor != null ? mAnchor.get() : null;
                 if (anchor != null && mPopupView != null) {
-                    WindowManager.LayoutParams p = (WindowManager.LayoutParams)
+                    final WindowManager.LayoutParams p = (WindowManager.LayoutParams)
                             mPopupView.getLayoutParams();
 
                     updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
@@ -143,7 +150,9 @@
                 }
             }
         };
+
     private int mAnchorXoff, mAnchorYoff, mAnchoredGravity;
+    private boolean mOverlapAnchor;
 
     private boolean mPopupViewInitialLayoutDirectionInherited;
 
@@ -187,6 +196,7 @@
                 attrs, com.android.internal.R.styleable.PopupWindow, defStyleAttr, defStyleRes);
 
         mBackground = a.getDrawable(R.styleable.PopupWindow_popupBackground);
+        mOverlapAnchor = a.getBoolean(R.styleable.PopupWindow_overlapAnchor, false);
 
         final int animStyle = a.getResourceId(R.styleable.PopupWindow_popupAnimationStyle, -1);
         mAnimationStyle = animStyle == com.android.internal.R.style.Animation_PopupWindow ? -1 :
@@ -934,9 +944,9 @@
                 // do the job.
                 if (mAboveAnchorBackgroundDrawable != null) {
                     if (mAboveAnchor) {
-                        mPopupView.setBackgroundDrawable(mAboveAnchorBackgroundDrawable);
+                        mPopupView.setBackground(mAboveAnchorBackgroundDrawable);
                     } else {
-                        mPopupView.setBackgroundDrawable(mBelowAnchorBackgroundDrawable);
+                        mPopupView.setBackground(mBelowAnchorBackgroundDrawable);
                     }
                 } else {
                     mPopupView.refreshDrawableState();
@@ -1114,36 +1124,43 @@
         }
         return mAnimationStyle;
     }
-    
+
     /**
-     * <p>Positions the popup window on screen. When the popup window is too
-     * tall to fit under the anchor, a parent scroll view is seeked and scrolled
-     * up to reclaim space. If scrolling is not possible or not enough, the
-     * popup window gets moved on top of the anchor.</p>
-     *
-     * <p>The height must have been set on the layout parameters prior to
-     * calling this method.</p>
-     *
+     * Positions the popup window on screen. When the popup window is too tall
+     * to fit under the anchor, a parent scroll view is seeked and scrolled up
+     * to reclaim space. If scrolling is not possible or not enough, the popup
+     * window gets moved on top of the anchor.
+     * <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
+     * @param yoff vertical offset used to adjust for background padding
+     * @param gravity horizontal gravity specifying popup alignment
      * @return true if the popup is translated upwards to fit on screen
      */
-    private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
-            int xoff, int yoff, int gravity) {
-
+    private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p, int xoff,
+            int yoff, int gravity) {
         final int anchorHeight = anchor.getHeight();
+        final int anchorWidth = anchor.getWidth();
+        if (mOverlapAnchor) {
+            yoff -= anchorHeight;
+        }
+
         anchor.getLocationInWindow(mDrawingLocation);
         p.x = mDrawingLocation[0] + xoff;
         p.y = mDrawingLocation[1] + anchorHeight + yoff;
 
-        final int hgrav = Gravity.getAbsoluteGravity(gravity, anchor.getLayoutDirection()) &
-                Gravity.HORIZONTAL_GRAVITY_MASK;
+        final int hgrav = Gravity.getAbsoluteGravity(gravity, anchor.getLayoutDirection())
+                & Gravity.HORIZONTAL_GRAVITY_MASK;
         if (hgrav == Gravity.RIGHT) {
-            // Flip the location to align the right sides of the popup and anchor instead of left
-            p.x -= mPopupWidth - anchor.getWidth();
+            // Flip the location to align the right sides of the popup and
+            // anchor instead of left.
+            p.x -= mPopupWidth - anchorWidth;
         }
-        
+
         boolean onTop = false;
 
         p.gravity = Gravity.LEFT | Gravity.TOP;
@@ -1152,60 +1169,58 @@
         final Rect displayFrame = new Rect();
         anchor.getWindowVisibleDisplayFrame(displayFrame);
 
-        int screenY = mScreenLocation[1] + anchorHeight + yoff;
-        
+        final int screenY = mScreenLocation[1] + anchorHeight + yoff;
         final View root = anchor.getRootView();
-        if (screenY + mPopupHeight > displayFrame.bottom ||
-                p.x + mPopupWidth - root.getWidth() > 0) {
-            // if the drop down disappears at the bottom of the screen. we try to
-            // scroll a parent scrollview or move the drop down back up on top of
-            // the edit box
+        if (screenY + mPopupHeight > displayFrame.bottom
+                || p.x + mPopupWidth - root.getWidth() > 0) {
+            // If the drop down disappears at the bottom of the screen, we try
+            // to scroll a parent scrollview or move the drop down back up on
+            // top of the edit box.
             if (mAllowScrollingAnchorParent) {
-                int scrollX = anchor.getScrollX();
-                int scrollY = anchor.getScrollY();
-                Rect r = new Rect(scrollX, scrollY,  scrollX + mPopupWidth + xoff,
-                        scrollY + mPopupHeight + anchor.getHeight() + yoff);
+                final int scrollX = anchor.getScrollX();
+                final int scrollY = anchor.getScrollY();
+                final Rect r = new Rect(scrollX, scrollY, scrollX + mPopupWidth + xoff,
+                        scrollY + mPopupHeight + anchorHeight + yoff);
                 anchor.requestRectangleOnScreen(r, true);
             }
 
-            // now we re-evaluate the space available, and decide from that
+            // Now we re-evaluate the space available, and decide from that
             // whether the pop-up will go above or below the anchor.
             anchor.getLocationInWindow(mDrawingLocation);
             p.x = mDrawingLocation[0] + xoff;
-            p.y = mDrawingLocation[1] + anchor.getHeight() + yoff;
+            p.y = mDrawingLocation[1] + anchorHeight + yoff;
 
-            // Preserve the gravity adjustment
+            // Preserve the gravity adjustment.
             if (hgrav == Gravity.RIGHT) {
-                p.x -= mPopupWidth - anchor.getWidth();
+                p.x -= mPopupWidth - anchorWidth;
             }
-            
-            // determine whether there is more space above or below the anchor
+
+            // Determine whether there is more space above or below the anchor.
             anchor.getLocationOnScreen(mScreenLocation);
-            
-            onTop = (displayFrame.bottom - mScreenLocation[1] - anchor.getHeight() - yoff) <
+            onTop = (displayFrame.bottom - mScreenLocation[1] - anchorHeight - yoff) <
                     (mScreenLocation[1] - yoff - displayFrame.top);
             if (onTop) {
                 p.gravity = Gravity.LEFT | Gravity.BOTTOM;
                 p.y = root.getHeight() - mDrawingLocation[1] + yoff;
             } else {
-                p.y = mDrawingLocation[1] + anchor.getHeight() + yoff;
+                p.y = mDrawingLocation[1] + anchorHeight + yoff;
             }
         }
 
         if (mClipToScreen) {
             final int displayFrameWidth = displayFrame.right - displayFrame.left;
-
-            int right = p.x + p.width;
+            final int right = p.x + p.width;
             if (right > displayFrameWidth) {
                 p.x -= right - displayFrameWidth;
             }
+
             if (p.x < displayFrame.left) {
                 p.x = displayFrame.left;
                 p.width = Math.min(p.width, displayFrameWidth);
             }
 
             if (onTop) {
-                int popupTop = mScreenLocation[1] + yoff - mPopupHeight;
+                final int popupTop = mScreenLocation[1] + yoff - mPopupHeight;
                 if (popupTop < 0) {
                     p.y += popupTop;
                 }
@@ -1215,7 +1230,11 @@
         }
 
         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;
     }
     
@@ -1503,7 +1522,8 @@
         }
 
         WeakReference<View> oldAnchor = mAnchor;
-        final boolean needsUpdate = updateLocation && (mAnchorXoff != xoff || mAnchorYoff != yoff);
+        final boolean needsUpdate = updateLocation
+                && (mAnchorXoff != xoff || mAnchorYoff != yoff);
         if (oldAnchor == null || oldAnchor.get() != anchor || (needsUpdate && !mIsDropdown)) {
             registerForScrollChanged(anchor, xoff, yoff, gravity);
         } else if (needsUpdate) {
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index f7e81b8..0c3715d 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -1066,21 +1066,30 @@
     protected synchronized void onDraw(Canvas canvas) {
         super.onDraw(canvas);
 
-        Drawable d = mCurrentDrawable;
+        drawTrack(canvas);
+    }
+
+    /**
+     * Draws the progress bar track.
+     */
+    void drawTrack(Canvas canvas) {
+        final Drawable d = mCurrentDrawable;
         if (d != null) {
             // Translate canvas so a indeterminate circular progress bar with padding
             // rotates properly in its animation
-            canvas.save();
+            final int saveCount = canvas.save();
+
             if(isLayoutRtl() && mMirrorForRtl) {
                 canvas.translate(getWidth() - mPaddingRight, mPaddingTop);
                 canvas.scale(-1.0f, 1.0f);
             } else {
                 canvas.translate(mPaddingLeft, mPaddingTop);
             }
-            long time = getDrawingTime();
+
+            final long time = getDrawingTime();
             if (mHasAnimation) {
                 mAnimation.getTransformation(time, mTransformation);
-                float scale = mTransformation.getAlpha();
+                final float scale = mTransformation.getAlpha();
                 try {
                     mInDrawing = true;
                     d.setLevel((int) (scale * MAX_LEVEL));
@@ -1089,8 +1098,10 @@
                 }
                 postInvalidateOnAnimation();
             }
+
             d.draw(canvas);
-            canvas.restore();
+            canvas.restoreToCount(saveCount);
+
             if (mShouldStartAnimationDrawable && d instanceof Animatable) {
                 ((Animatable) d).start();
                 mShouldStartAnimationDrawable = false;
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 7e8f6b4..fd04890 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -583,7 +583,8 @@
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         initVelocityTrackerIfNotExists();
-        mVelocityTracker.addMovement(ev);
+
+        MotionEvent vtev = MotionEvent.obtain(ev);
 
         final int action = ev.getAction();
 
@@ -627,7 +628,8 @@
                 final int y = (int) ev.getY(activePointerIndex);
                 int deltaY = mLastMotionY - y;
                 if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) {
-                    deltaY -= mScrollConsumed[1] + mScrollOffset[1];
+                    deltaY -= mScrollConsumed[1];
+                    vtev.offsetLocation(0, mScrollOffset[1]);
                 }
                 if (!mIsBeingDragged && Math.abs(deltaY) > mTouchSlop) {
                     final ViewParent parent = getParent();
@@ -643,7 +645,7 @@
                 }
                 if (mIsBeingDragged) {
                     // Scroll to follow the motion event
-                    mLastMotionY = y;
+                    mLastMotionY = y - mScrollOffset[1];
 
                     final int oldY = mScrollY;
                     final int range = getScrollRange();
@@ -663,15 +665,18 @@
                     final int unconsumedY = deltaY - scrolledDeltaY;
                     if (dispatchNestedScroll(0, scrolledDeltaY, 0, unconsumedY, mScrollOffset)) {
                         mLastMotionY -= mScrollOffset[1];
+                        vtev.offsetLocation(0, mScrollOffset[1]);
                     } else if (canOverscroll) {
                         final int pulledToY = oldY + deltaY;
                         if (pulledToY < 0) {
-                            mEdgeGlowTop.onPull((float) deltaY / getHeight());
+                            mEdgeGlowTop.onPull((float) deltaY / getHeight(),
+                                    ev.getX(activePointerIndex) / getWidth());
                             if (!mEdgeGlowBottom.isFinished()) {
                                 mEdgeGlowBottom.onRelease();
                             }
                         } else if (pulledToY > range) {
-                            mEdgeGlowBottom.onPull((float) deltaY / getHeight());
+                            mEdgeGlowBottom.onPull((float) deltaY / getHeight(),
+                                    1.f - ev.getX(activePointerIndex) / getWidth());
                             if (!mEdgeGlowTop.isFinished()) {
                                 mEdgeGlowTop.onRelease();
                             }
@@ -720,6 +725,11 @@
                 mLastMotionY = (int) ev.getY(ev.findPointerIndex(mActivePointerId));
                 break;
         }
+
+        if (mVelocityTracker != null) {
+            mVelocityTracker.addMovement(vtev);
+        }
+        vtev.recycle();
         return true;
     }
 
@@ -1565,10 +1575,10 @@
     }
 
     private void flingWithNestedDispatch(int velocityY) {
-        if (mScrollY == 0 && velocityY < 0 ||
-                mScrollY == getScrollRange() && velocityY > 0) {
-            dispatchNestedFling(0, velocityY);
-        } else {
+        final boolean canFling = (mScrollY > 0 || velocityY > 0) &&
+                (mScrollY < getScrollRange() || velocityY < 0);
+        dispatchNestedFling(0, velocityY, canFling);
+        if (canFling) {
             fling(velocityY);
         }
     }
@@ -1627,6 +1637,12 @@
         return (nestedScrollAxes & SCROLL_AXIS_VERTICAL) != 0;
     }
 
+    @Override
+    public void onNestedScrollAccepted(View child, View target, int axes) {
+        super.onNestedScrollAccepted(child, target, axes);
+        startNestedScroll(SCROLL_AXIS_VERTICAL);
+    }
+
     /**
      * @inheritDoc
      */
@@ -1638,16 +1654,23 @@
     @Override
     public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
             int dxUnconsumed, int dyUnconsumed) {
+        final int oldScrollY = mScrollY;
         scrollBy(0, dyUnconsumed);
+        final int myConsumed = mScrollY - oldScrollY;
+        final int myUnconsumed = dyUnconsumed - myConsumed;
+        dispatchNestedScroll(0, myConsumed, 0, myUnconsumed, null);
     }
 
     /**
      * @inheritDoc
      */
     @Override
-    public boolean onNestedFling(View target, float velocityX, float velocityY) {
-        flingWithNestedDispatch((int) velocityY);
-        return true;
+    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
+        if (!consumed) {
+            flingWithNestedDispatch((int) velocityY);
+            return true;
+        }
+        return false;
     }
 
     @Override
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index cde8080..99a7886 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -276,6 +276,13 @@
      * @see Intent#ACTION_SEND_MULTIPLE
      */
     public void setShareIntent(Intent shareIntent) {
+        if (shareIntent != null) {
+            final String action = shareIntent.getAction();
+            if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) {
+                shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
+                        Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
+            }
+        }
         ActivityChooserModel dataModel = ActivityChooserModel.get(mContext,
             mShareHistoryFileName);
         dataModel.setIntent(shareIntent);
@@ -292,7 +299,12 @@
             final int itemId = item.getItemId();
             Intent launchIntent = dataModel.chooseActivity(itemId);
             if (launchIntent != null) {
-                launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+                final String action = launchIntent.getAction();
+                if (Intent.ACTION_SEND.equals(action) ||
+                        Intent.ACTION_SEND_MULTIPLE.equals(action)) {
+                    launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
+                            Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
+                }
                 mContext.startActivity(launchIntent);
             }
             return true;
@@ -308,7 +320,7 @@
             return;
         }
         if (mOnChooseActivityListener == null) {
-            mOnChooseActivityListener = new ShareAcitivityChooserModelPolicy();
+            mOnChooseActivityListener = new ShareActivityChooserModelPolicy();
         }
         ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
         dataModel.setOnChooseActivityListener(mOnChooseActivityListener);
@@ -317,7 +329,7 @@
     /**
      * Policy that delegates to the {@link OnShareTargetSelectedListener}, if such.
      */
-    private class ShareAcitivityChooserModelPolicy implements OnChooseActivityListener {
+    private class ShareActivityChooserModelPolicy implements OnChooseActivityListener {
         @Override
         public boolean onChooseActivity(ActivityChooserModel host, Intent intent) {
             if (mOnShareTargetSelectedListener != null) {
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 08af4de..438e164 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -22,9 +22,11 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
+import android.graphics.Insets;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.Typeface;
+import android.graphics.Region.Op;
 import android.graphics.drawable.Drawable;
 import android.text.Layout;
 import android.text.StaticLayout;
@@ -85,6 +87,7 @@
     private int mThumbTextPadding;
     private int mSwitchMinWidth;
     private int mSwitchPadding;
+    private boolean mSplitTrack;
     private CharSequence mTextOn;
     private CharSequence mTextOff;
 
@@ -174,13 +177,13 @@
         super(context, attrs, defStyleAttr, defStyleRes);
 
         mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
-        Resources res = getResources();
+
+        final Resources res = getResources();
         mTextPaint.density = res.getDisplayMetrics().density;
         mTextPaint.setCompatibilityScaling(res.getCompatibilityInfo().applicationScale);
 
         final TypedArray a = context.obtainStyledAttributes(
                 attrs, com.android.internal.R.styleable.Switch, defStyleAttr, defStyleRes);
-
         mThumbDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_thumb);
         mTrackDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_track);
         mTextOn = a.getText(com.android.internal.R.styleable.Switch_textOn);
@@ -191,15 +194,16 @@
                 com.android.internal.R.styleable.Switch_switchMinWidth, 0);
         mSwitchPadding = a.getDimensionPixelSize(
                 com.android.internal.R.styleable.Switch_switchPadding, 0);
+        mSplitTrack = a.getBoolean(com.android.internal.R.styleable.Switch_splitTrack, false);
 
-        int appearance = a.getResourceId(
+        final int appearance = a.getResourceId(
                 com.android.internal.R.styleable.Switch_switchTextAppearance, 0);
         if (appearance != 0) {
             setSwitchTextAppearance(context, appearance);
         }
         a.recycle();
 
-        ViewConfiguration config = ViewConfiguration.get(context);
+        final ViewConfiguration config = ViewConfiguration.get(context);
         mTouchSlop = config.getScaledTouchSlop();
         mMinFlingVelocity = config.getScaledMinimumFlingVelocity();
 
@@ -469,6 +473,29 @@
     }
 
     /**
+     * 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.
+     *
+     * @param splitTrack Whether the track should be split by the thumb
+     *
+     * @attr ref android.R.styleable#Switch_splitTrack
+     */
+    public void setSplitTrack(boolean splitTrack) {
+        mSplitTrack = splitTrack;
+        invalidate();
+    }
+
+    /**
+     * Returns whether the track should be split by the thumb.
+     *
+     * @attr ref android.R.styleable#Switch_splitTrack
+     */
+    public boolean getSplitTrack() {
+        return mSplitTrack;
+    }
+
+    /**
      * Returns the text displayed when the button is in the checked state.
      *
      * @attr ref android.R.styleable#Switch_textOn
@@ -518,13 +545,15 @@
 
         mTrackDrawable.getPadding(mTempRect);
 
-        final int maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth());
+        final int maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth())
+                + mThumbTextPadding * 2;
+        mThumbWidth = Math.max(maxTextWidth, mThumbDrawable.getIntrinsicWidth());
+
         final int switchWidth = Math.max(mSwitchMinWidth,
-                maxTextWidth * 2 + mThumbTextPadding * 4 + mTempRect.left + mTempRect.right);
+                2 * mThumbWidth + mTempRect.left + mTempRect.right);
         final int switchHeight = Math.max(mTrackDrawable.getIntrinsicHeight(),
                 mThumbDrawable.getIntrinsicHeight());
 
-        mThumbWidth = maxTextWidth + mThumbTextPadding * 2;
 
         mSwitchWidth = switchWidth;
         mSwitchHeight = switchHeight;
@@ -777,7 +806,7 @@
         final Drawable trackDrawable = mTrackDrawable;
         final Drawable thumbDrawable = mThumbDrawable;
 
-        // Draw the switch
+        // Layout the track.
         final int switchLeft = mSwitchLeft;
         final int switchTop = mSwitchTop;
         final int switchRight = mSwitchRight;
@@ -793,9 +822,10 @@
         // Relies on mTempRect, MUST be called first!
         final int thumbPos = getThumbOffset();
 
+        // Layout the thumb.
         thumbDrawable.getPadding(tempRect);
-        int thumbLeft = switchInnerLeft - tempRect.left + thumbPos;
-        int thumbRight = switchInnerLeft + thumbPos + mThumbWidth + tempRect.right;
+        final int thumbLeft = switchInnerLeft - tempRect.left + thumbPos;
+        final int thumbRight = switchInnerLeft + thumbPos + mThumbWidth + tempRect.right;
         thumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom);
 
         final Drawable background = getBackground();
@@ -805,20 +835,32 @@
 
         super.onDraw(canvas);
 
-        trackDrawable.draw(canvas);
+        if (mSplitTrack) {
+            final Insets insets = thumbDrawable.getOpticalInsets();
+            thumbDrawable.copyBounds(tempRect);
+            tempRect.left += insets.left;
+            tempRect.right -= insets.right;
+
+            final int saveCount = canvas.save();
+            canvas.clipRect(tempRect, Op.DIFFERENCE);
+            trackDrawable.draw(canvas);
+            canvas.restoreToCount(saveCount);
+        } else {
+            trackDrawable.draw(canvas);
+        }
 
         final int saveCount = canvas.save();
         canvas.clipRect(switchInnerLeft, switchTop, switchInnerRight, switchBottom);
         thumbDrawable.draw(canvas);
 
-        final int drawableState[] = getDrawableState();
-        if (mTextColors != null) {
-            mTextPaint.setColor(mTextColors.getColorForState(drawableState, 0));
-        }
-        mTextPaint.drawableState = drawableState;
-
         final Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout;
         if (switchText != null) {
+            final int drawableState[] = getDrawableState();
+            if (mTextColors != null) {
+                mTextPaint.setColor(mTextColors.getColorForState(drawableState, 0));
+            }
+            mTextPaint.drawableState = drawableState;
+
             final int left = (thumbLeft + thumbRight) / 2 - switchText.getWidth() / 2;
             final int top = (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2;
             canvas.translate(left, top);
@@ -889,12 +931,16 @@
     protected void drawableStateChanged() {
         super.drawableStateChanged();
 
-        int[] myDrawableState = getDrawableState();
+        final int[] myDrawableState = getDrawableState();
 
-        // Set the state of the Drawable
-        // Drawable may be null when checked state is set from XML, from super constructor
-        if (mThumbDrawable != null) mThumbDrawable.setState(myDrawableState);
-        if (mTrackDrawable != null) mTrackDrawable.setState(myDrawableState);
+        if (mThumbDrawable != null && mThumbDrawable.setState(myDrawableState)) {
+            // Handle changes to thumb width and height.
+            requestLayout();
+        }
+
+        if (mTrackDrawable != null) {
+            mTrackDrawable.setState(myDrawableState);
+        }
 
         invalidate();
     }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index b91111d..8f073de 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -289,6 +289,8 @@
     private Spannable.Factory mSpannableFactory = Spannable.Factory.getInstance();
 
     private float mShadowRadius, mShadowDx, mShadowDy;
+    private int mShadowColor;
+
 
     private boolean mPreDrawRegistered;
 
@@ -2755,6 +2757,7 @@
         mShadowRadius = radius;
         mShadowDx = dx;
         mShadowDy = dy;
+        mShadowColor = color;
 
         // Will change text clip region
         if (mEditor != null) mEditor.invalidateTextDisplayList();
@@ -2804,7 +2807,7 @@
      * @attr ref android.R.styleable#TextView_shadowColor
      */
     public int getShadowColor() {
-        return mTextPaint.shadowColor;
+        return mShadowColor;
     }
 
     /**
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 075feba..928e34e 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -734,13 +734,13 @@
         addCustomViewsWithGravity(mTempViews, Gravity.LEFT);
         final int leftViewsCount = mTempViews.size();
         for (int i = 0; i < leftViewsCount; i++) {
-            left = layoutChildLeft(getChildAt(i), left);
+            left = layoutChildLeft(mTempViews.get(i), left);
         }
 
         addCustomViewsWithGravity(mTempViews, Gravity.RIGHT);
         final int rightViewsCount = mTempViews.size();
         for (int i = 0; i < rightViewsCount; i++) {
-            right = layoutChildRight(getChildAt(i), right);
+            right = layoutChildRight(mTempViews.get(i), right);
         }
 
         // Centered views try to center with respect to the whole bar, but views pinned
@@ -759,7 +759,7 @@
 
         final int centerViewsCount = mTempViews.size();
         for (int i = 0; i < centerViewsCount; i++) {
-            centerLeft = layoutChildLeft(getChildAt(i), centerLeft);
+            centerLeft = layoutChildLeft(mTempViews.get(i), centerLeft);
         }
         mTempViews.clear();
     }
@@ -778,18 +778,20 @@
     private int layoutChildLeft(View child, int left) {
         final LayoutParams lp = (LayoutParams) child.getLayoutParams();
         left += lp.leftMargin;
-        int top = getChildTop(child);
-        child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
-        left += lp.rightMargin;
+        final int top = getChildTop(child);
+        final int childWidth = child.getMeasuredWidth();
+        child.layout(left, top, left + childWidth, top + child.getMeasuredHeight());
+        left += childWidth + lp.rightMargin;
         return left;
     }
 
     private int layoutChildRight(View child, int right) {
         final LayoutParams lp = (LayoutParams) child.getLayoutParams();
         right -= lp.rightMargin;
-        int top = getChildTop(child);
-        child.layout(right - child.getMeasuredWidth(), top, right, top + child.getMeasuredHeight());
-        right -= lp.leftMargin;
+        final int top = getChildTop(child);
+        final int childWidth = child.getMeasuredWidth();
+        child.layout(right - childWidth, top, right, top + child.getMeasuredHeight());
+        right -= childWidth + lp.leftMargin;
         return right;
     }
 
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 4726da7..664f9db 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -26,6 +26,7 @@
 import android.content.res.TypedArray;
 import android.database.Cursor;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
 import android.text.TextUtils;
@@ -38,6 +39,7 @@
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.Window;
+import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
@@ -121,11 +123,14 @@
     private int mCheckedItem = -1;
 
     private int mAlertDialogLayout;
+    private int mButtonPanelSideLayout;
     private int mListLayout;
     private int mMultiChoiceItemLayout;
     private int mSingleChoiceItemLayout;
     private int mListItemLayout;
 
+    private int mButtonPanelLayoutHint = AlertDialog.LAYOUT_HINT_NONE;
+    
     private Handler mHandler;
 
     private final View.OnClickListener mButtonHandler = new View.OnClickListener() {
@@ -197,6 +202,9 @@
 
         mAlertDialogLayout = a.getResourceId(com.android.internal.R.styleable.AlertDialog_layout,
                 com.android.internal.R.layout.alert_dialog);
+        mButtonPanelSideLayout = a.getResourceId(
+                com.android.internal.R.styleable.AlertDialog_buttonPanelSideLayout, 0);
+
         mListLayout = a.getResourceId(
                 com.android.internal.R.styleable.AlertDialog_listLayout,
                 com.android.internal.R.layout.select_dialog);
@@ -238,8 +246,21 @@
     public void installContent() {
         /* We use a custom title so never request a window title */
         mWindow.requestFeature(Window.FEATURE_NO_TITLE);
-        mWindow.setContentView(mAlertDialogLayout);
+        int contentView = selectContentView();
+        mWindow.setContentView(contentView);
         setupView();
+        setupDecor();
+    }
+
+    private int selectContentView() {
+        if (mButtonPanelSideLayout == 0) {
+            return mAlertDialogLayout;
+        }
+        if (mButtonPanelLayoutHint == AlertDialog.LAYOUT_HINT_SIDE) {
+            return mButtonPanelSideLayout;
+        }
+        // TODO: use layout hint side for long messages/lists
+        return mAlertDialogLayout;
     }
     
     public void setTitle(CharSequence title) {
@@ -296,6 +317,13 @@
     }
 
     /**
+     * Sets a hint for the best button panel layout.
+     */
+    public void setButtonPanelLayoutHint(int layoutHint) {
+        mButtonPanelLayoutHint = layoutHint;
+    }
+
+    /**
      * Sets a click listener or a message to be sent when the button is clicked.
      * You only need to pass one of {@code listener} or {@code msg}.
      * 
@@ -415,7 +443,28 @@
     public boolean onKeyUp(int keyCode, KeyEvent event) {
         return mScrollView != null && mScrollView.executeKeyEvent(event);
     }
-    
+
+    private void setupDecor() {
+        final View decor = mWindow.getDecorView();
+        final View parent = mWindow.findViewById(R.id.parentPanel);
+        if (parent != null && decor != null) {
+            decor.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
+                @Override
+                public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) {
+                    if (insets.isRound()) {
+                        // TODO: Get the padding as a function of the window size.
+                        int roundOffset = mContext.getResources().getDimensionPixelOffset(
+                                R.dimen.alert_dialog_round_padding);
+                        parent.setPadding(roundOffset, roundOffset, roundOffset, roundOffset);
+                    }
+                    return insets.consumeSystemWindowInsets();
+                }
+            });
+            decor.setFitsSystemWindows(true);
+            decor.requestApplyInsets();
+        }
+    }
+
     private void setupView() {
         LinearLayout contentPanel = (LinearLayout) mWindow.findViewById(R.id.contentPanel);
         setupContent(contentPanel);
@@ -636,14 +685,31 @@
 
     private void setBackground(TypedArray a, View topPanel, View contentPanel, View customPanel,
             View buttonPanel, boolean hasTitle, boolean hasCustomView, boolean hasButtons) {
-        final int topBright = a.getResourceId(
-                R.styleable.AlertDialog_topBright, R.drawable.popup_top_bright);
-        final int topDark = a.getResourceId(
-                R.styleable.AlertDialog_topDark, R.drawable.popup_top_dark);
-        final int centerBright = a.getResourceId(
-                R.styleable.AlertDialog_centerBright, R.drawable.popup_center_bright);
-        final int centerDark = a.getResourceId(
-                R.styleable.AlertDialog_centerDark, R.drawable.popup_center_dark);
+        int fullDark = 0;
+        int topDark = 0;
+        int centerDark = 0;
+        int bottomDark = 0;
+        int fullBright = 0;
+        int topBright = 0;
+        int centerBright = 0;
+        int bottomBright = 0;
+        int bottomMedium = 0;
+        if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.KITKAT) {
+            fullDark = R.drawable.popup_full_dark;
+            topDark = R.drawable.popup_top_dark;
+            centerDark = R.drawable.popup_center_dark;
+            bottomDark = R.drawable.popup_bottom_dark;
+            fullBright = R.drawable.popup_full_bright;
+            topBright = R.drawable.popup_top_bright;
+            centerBright = R.drawable.popup_center_bright;
+            bottomBright = R.drawable.popup_bottom_bright;
+            bottomMedium = R.drawable.popup_bottom_medium;
+        }
+        topBright = a.getResourceId(R.styleable.AlertDialog_topBright, topBright);
+        topDark = a.getResourceId(R.styleable.AlertDialog_topDark, topDark);
+        centerBright = a.getResourceId(R.styleable.AlertDialog_centerBright, centerBright);
+        centerDark = a.getResourceId(R.styleable.AlertDialog_centerDark, centerDark);
+
 
         /* We now set the background of all of the sections of the alert.
          * First collect together each section that is being displayed along
@@ -707,22 +773,17 @@
 
         if (lastView != null) {
             if (setView) {
-                final int bottomBright = a.getResourceId(
-                        R.styleable.AlertDialog_bottomBright, R.drawable.popup_bottom_bright);
-                final int bottomMedium = a.getResourceId(
-                        R.styleable.AlertDialog_bottomMedium, R.drawable.popup_bottom_medium);
-                final int bottomDark = a.getResourceId(
-                        R.styleable.AlertDialog_bottomDark, R.drawable.popup_bottom_dark);
+                bottomBright = a.getResourceId(R.styleable.AlertDialog_bottomBright, bottomBright);
+                bottomMedium = a.getResourceId(R.styleable.AlertDialog_bottomMedium, bottomMedium);
+                bottomDark = a.getResourceId(R.styleable.AlertDialog_bottomDark, bottomDark);
 
                 // ListViews will use the Bright background, but buttons use the
                 // Medium background.
                 lastView.setBackgroundResource(
                         lastLight ? (hasButtons ? bottomMedium : bottomBright) : bottomDark);
             } else {
-                final int fullBright = a.getResourceId(
-                        R.styleable.AlertDialog_fullBright, R.drawable.popup_full_bright);
-                final int fullDark = a.getResourceId(
-                        R.styleable.AlertDialog_fullDark, R.drawable.popup_full_dark);
+                fullBright = a.getResourceId(R.styleable.AlertDialog_fullBright, fullBright);
+                fullDark = a.getResourceId(R.styleable.AlertDialog_fullDark, fullDark);
 
                 lastView.setBackgroundResource(lastLight ? fullBright : fullDark);
             }
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 1eda373..106ac0b 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -33,6 +33,14 @@
             return;
         }
         Intent target = (Intent)targetParcelable;
+        if (target != null) {
+            final String action = target.getAction();
+            if (Intent.ACTION_SEND.equals(action) ||
+                    Intent.ACTION_SEND_MULTIPLE.equals(action)) {
+                target.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
+                        Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
+            }
+        }
         CharSequence title = intent.getCharSequenceExtra(Intent.EXTRA_TITLE);
         if (title == null) {
             title = getResources().getText(com.android.internal.R.string.chooseActivity);
@@ -43,13 +51,19 @@
             initialIntents = new Intent[pa.length];
             for (int i=0; i<pa.length; i++) {
                 if (!(pa[i] instanceof Intent)) {
-                    Log.w("ChooserActivity", "Initial intent #" + i
-                            + " not an Intent: " + pa[i]);
+                    Log.w("ChooserActivity", "Initial intent #" + i + " not an Intent: " + pa[i]);
                     finish();
                     super.onCreate(null);
                     return;
                 }
-                initialIntents[i] = (Intent)pa[i];
+                final Intent in = (Intent) pa[i];
+                final String action = in.getAction();
+                if (Intent.ACTION_SEND.equals(action) ||
+                        Intent.ACTION_SEND_MULTIPLE.equals(action)) {
+                    in.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
+                            Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
+                }
+                initialIntents[i] = in;
             }
         }
         super.onCreate(savedInstanceState, target, title, initialIntents, null, false);
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 1bb577b..04547495 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -59,11 +59,10 @@
     void noteVibratorOff(int uid);
     void noteStartGps(int uid);
     void noteStopGps(int uid);
-    void noteScreenOn();
+    void noteScreenState(int state);
     void noteScreenBrightness(int brightness);
-    void noteScreenOff();
-    void noteInputEvent();
     void noteUserActivity(int uid, int event);
+    void noteInteractive(boolean interactive);
     void noteMobileRadioPowerState(int powerState, long timestampNs);
     void notePhoneOn();
     void notePhoneOff();
diff --git a/core/java/com/android/internal/app/IUsageStats.aidl b/core/java/com/android/internal/app/IUsageStats.aidl
index 1ea7409..7e7f0e1 100644
--- a/core/java/com/android/internal/app/IUsageStats.aidl
+++ b/core/java/com/android/internal/app/IUsageStats.aidl
@@ -16,13 +16,17 @@
 
 package com.android.internal.app;
 
+import android.app.UsageStats;
 import android.content.ComponentName;
-import com.android.internal.os.PkgUsageStats;
+import android.content.res.Configuration;
+import android.os.ParcelableParcel;
 
 interface IUsageStats {
     void noteResumeComponent(in ComponentName componentName);
     void notePauseComponent(in ComponentName componentName);
     void noteLaunchTime(in ComponentName componentName, int millis);
-    PkgUsageStats getPkgUsageStats(in ComponentName componentName);
-    PkgUsageStats[] getAllPkgUsageStats();
+    void noteStartConfig(in Configuration config);
+    UsageStats.PackageStats getPkgUsageStats(String callingPkg, in ComponentName componentName);
+    UsageStats.PackageStats[] getAllPkgUsageStats(String callingPkg);
+    ParcelableParcel getCurrentStats(String callingPkg);
 }
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 3219ddd..98e35dd 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -24,8 +24,9 @@
 import android.service.voice.IVoiceInteractionSession;
 
 interface IVoiceInteractionManagerService {
-    void startVoiceActivity(in Intent intent, String resolvedType, IVoiceInteractionService service,
-            in Bundle sessionArgs);
-    int deliverNewSession(IBinder token, IVoiceInteractionSession session,
+    void startSession(IVoiceInteractionService service, in Bundle sessionArgs);
+    boolean deliverNewSession(IBinder token, IVoiceInteractionSession session,
             IVoiceInteractor interactor);
+    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
new file mode 100644
index 0000000..47ef65a
--- /dev/null
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.AppGlobals;
+import android.os.Bundle;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.IPackageManager;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.app.ActivityManagerNative;
+import android.os.RemoteException;
+import android.util.Slog;
+import java.util.List;
+import java.util.Set;
+
+
+
+
+/*
+ * This is used in conjunction with DevicePolicyManager.setForwardingIntents to enable intents to be
+ * passed in and out of a managed profile.
+ */
+
+public class IntentForwarderActivity extends Activity  {
+
+    public static String TAG = "IntentForwarderActivity";
+
+    public static String FORWARD_INTENT_TO_USER_OWNER
+            = "com.android.internal.app.ForwardIntentToUserOwner";
+
+    public static String FORWARD_INTENT_TO_MANAGED_PROFILE
+            = "com.android.internal.app.ForwardIntentToManagedProfile";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Intent intentReceived = getIntent();
+
+        String className = intentReceived.getComponent().getClassName();
+        final UserHandle userDest;
+
+        if (className.equals(FORWARD_INTENT_TO_USER_OWNER)) {
+            userDest = UserHandle.OWNER;
+        } else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
+            userDest = getManagedProfile();
+        } else {
+            Slog.wtf(TAG, IntentForwarderActivity.class.getName() + " cannot be called directly");
+            userDest = null;
+        }
+        if (userDest == null) { // This covers the case where there is no managed profile.
+            finish();
+            return;
+        }
+        Intent newIntent = new Intent(intentReceived);
+        newIntent.setComponent(null);
+        newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
+                |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
+        int callingUserId = getUserId();
+        IPackageManager ipm = AppGlobals.getPackageManager();
+        String resolvedType = newIntent.resolveTypeIfNeeded(getContentResolver());
+        boolean canForward = false;
+        try {
+            canForward = ipm.canForwardTo(newIntent, resolvedType, callingUserId,
+                    userDest.getIdentifier());
+        } catch (RemoteException e) {
+            Slog.e(TAG, "PackageManagerService is dead?");
+        }
+        if (canForward) {
+            newIntent.prepareToLeaveUser(callingUserId);
+            startActivityAsUser(newIntent, userDest);
+        } else {
+            Slog.wtf(TAG, "the intent: " + newIntent + "cannot be forwarded from user "
+                    + callingUserId + " to user " + userDest.getIdentifier());
+        }
+        finish();
+    }
+
+    /**
+     * Returns the managed profile for this device or null if there is no managed
+     * profile.
+     *
+     * TODO: Remove the assumption that there is only one managed profile
+     * on the device.
+     */
+    private UserHandle getManagedProfile() {
+        UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
+        List<UserInfo> relatedUsers = userManager.getProfiles(UserHandle.USER_OWNER);
+        for (UserInfo userInfo : relatedUsers) {
+            if (userInfo.isManagedProfile()) return new UserHandle(userInfo.id);
+        }
+        Slog.wtf(TAG, FORWARD_INTENT_TO_MANAGED_PROFILE
+                + " has been called, but there is no managed profile");
+        return null;
+    }
+}
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index 8cdaf91..abd1791 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -18,156 +18,122 @@
 
 import android.app.Activity;
 import android.content.ActivityNotFoundException;
+import android.content.ContentResolver;
+import android.content.Context;
 import android.content.Intent;
+import android.graphics.Color;
 import android.graphics.Typeface;
-import android.provider.Settings;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.Handler;
-import android.text.method.AllCapsTransformationMethod;
+import android.provider.Settings;
+import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.view.Gravity;
 import android.view.View;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.AnticipateOvershootInterpolator;
-import android.view.animation.DecelerateInterpolator;
 import android.widget.FrameLayout;
-import android.widget.ImageView;
 import android.widget.TextView;
 
 public class PlatLogoActivity extends Activity {
-    FrameLayout mContent;
-    int mCount;
-    final Handler mHandler = new Handler();
-    static final int BGCOLOR = 0xffed1d24;
+    private static class Torso extends FrameLayout {
+        boolean mAnimate = false;
+        TextView mText;
+
+        public Torso(Context context) {
+            this(context, null);
+        }
+        public Torso(Context context, AttributeSet attrs) {
+            this(context, attrs, 0);
+        }
+        public Torso(Context context, AttributeSet attrs, int flags) {
+            super(context, attrs, flags);
+
+            for (int i=0; i<2; i++) {
+                final View v = new View(context);
+                v.setBackgroundColor(i % 2 == 0 ? Color.BLUE : Color.RED);
+                addView(v);
+            }
+
+            mText = new TextView(context);
+            mText.setTextColor(Color.BLACK);
+            mText.setTextSize(14 /* sp */);
+            mText.setTypeface(Typeface.create("monospace", Typeface.BOLD));
+
+            addView(mText, new FrameLayout.LayoutParams(
+                    FrameLayout.LayoutParams.MATCH_PARENT,
+                    FrameLayout.LayoutParams.WRAP_CONTENT,
+                    Gravity.BOTTOM | Gravity.LEFT
+            ));
+        }
+
+        private Runnable mRunnable = new Runnable() {
+            @Override
+            public void run() {
+                mText.setText(String.format("android_%s.flv - build %s",
+                        Build.VERSION.CODENAME,
+                        Build.VERSION.INCREMENTAL));
+                final int N = getChildCount();
+                final float parentw = getMeasuredWidth();
+                final float parenth = getMeasuredHeight();
+                for (int i=0; i<N; i++) {
+                    final View v = getChildAt(i);
+                    if (v instanceof TextView) continue;
+
+                    final int w = (int) (Math.random() * parentw);
+                    final int h = (int) (Math.random() * parenth);
+                    v.setLayoutParams(new FrameLayout.LayoutParams(w, h));
+
+                    v.setX((float) Math.random() * (parentw - w));
+                    v.setY((float) Math.random() * (parenth - h));
+                }
+
+                if (mAnimate) postDelayed(this, 1000);
+            }
+        };
+        @Override
+        protected void onAttachedToWindow() {
+            mAnimate = true;
+            post(mRunnable);
+        }
+        @Override
+        protected void onDetachedFromWindow() {
+            mAnimate = false;
+            removeCallbacks(mRunnable);
+        }
+    }
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        DisplayMetrics metrics = new DisplayMetrics();
-        getWindowManager().getDefaultDisplay().getMetrics(metrics);
+        final Torso t = new Torso(this);
+        t.setBackgroundColor(Color.WHITE);
 
-        Typeface bold = Typeface.create("sans-serif", Typeface.BOLD);
-        Typeface light = Typeface.create("sans-serif-light", Typeface.NORMAL);
+        t.getChildAt(0)
+                .setOnLongClickListener(new View.OnLongClickListener() {
+                    @Override
+                    public boolean onLongClick(View v) {
+                        final ContentResolver cr = getContentResolver();
+                        if (Settings.System.getLong(cr, Settings.System.EGG_MODE, 0)
+                                == 0) {
+                            // For posterity: the moment this user unlocked the easter egg
+                            Settings.System.putLong(cr,
+                                    Settings.System.EGG_MODE,
+                                    System.currentTimeMillis());
+                        }
+                        try {
+                            startActivity(new Intent(Intent.ACTION_MAIN)
+                                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                                            | Intent.FLAG_ACTIVITY_CLEAR_TASK
+                                            | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+                                    .addCategory("com.android.internal.category.PLATLOGO"));
+                        } catch (ActivityNotFoundException ex) {
+                            android.util.Log.e("PlatLogoActivity", "Couldn't catch a break.");
+                        }
+                        finish();
+                        return true;
+                    }
+                });
 
-        mContent = new FrameLayout(this);
-        mContent.setBackgroundColor(0xC0000000);
-        
-        final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
-                FrameLayout.LayoutParams.WRAP_CONTENT,
-                FrameLayout.LayoutParams.WRAP_CONTENT);
-        lp.gravity = Gravity.CENTER;
-
-        final ImageView logo = new ImageView(this);
-        logo.setImageResource(com.android.internal.R.drawable.platlogo);
-        logo.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-        logo.setVisibility(View.INVISIBLE);
-
-        final View bg = new View(this);
-        bg.setBackgroundColor(BGCOLOR);
-        bg.setAlpha(0f);
-
-        final TextView letter = new TextView(this);
-
-        letter.setTypeface(bold);
-        letter.setTextSize(300);
-        letter.setTextColor(0xFFFFFFFF);
-        letter.setGravity(Gravity.CENTER);
-        letter.setText(String.valueOf(Build.ID).substring(0, 1));
-
-        final int p = (int)(4 * metrics.density);
-
-        final TextView tv = new TextView(this);
-        if (light != null) tv.setTypeface(light);
-        tv.setTextSize(30);
-        tv.setPadding(p, p, p, p);
-        tv.setTextColor(0xFFFFFFFF);
-        tv.setGravity(Gravity.CENTER);
-        tv.setTransformationMethod(new AllCapsTransformationMethod(this));
-        tv.setText("Android " + Build.VERSION.RELEASE);
-        tv.setVisibility(View.INVISIBLE);
-
-        mContent.addView(bg);
-        mContent.addView(letter, lp);
-        mContent.addView(logo, lp);
-
-        final FrameLayout.LayoutParams lp2 = new FrameLayout.LayoutParams(lp);
-        lp2.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
-        lp2.bottomMargin = 10*p;
-
-        mContent.addView(tv, lp2);
-
-        mContent.setOnClickListener(new View.OnClickListener() {
-            int clicks;
-            @Override
-            public void onClick(View v) {
-                clicks++;
-                if (clicks >= 6) {
-                    mContent.performLongClick();
-                    return;
-                }
-                letter.animate().cancel();
-                final float offset = (int)letter.getRotation() % 360;
-                letter.animate()
-                    .rotationBy((Math.random() > 0.5f ? 360 : -360) - offset)
-                    .setInterpolator(new DecelerateInterpolator())
-                    .setDuration(700).start();
-            }
-        });
-
-        mContent.setOnLongClickListener(new View.OnLongClickListener() {
-            @Override
-            public boolean onLongClick(View v) {
-                if (logo.getVisibility() != View.VISIBLE) {
-                    bg.setScaleX(0.01f);
-                    bg.animate().alpha(1f).scaleX(1f).setStartDelay(500).start();
-                    letter.animate().alpha(0f).scaleY(0.5f).scaleX(0.5f)
-                            .rotationBy(360)
-                            .setInterpolator(new AccelerateInterpolator())
-                            .setDuration(1000)
-                            .start();
-                    logo.setAlpha(0f);
-                    logo.setVisibility(View.VISIBLE);
-                    logo.setScaleX(0.5f);
-                    logo.setScaleY(0.5f);
-                    logo.animate().alpha(1f).scaleX(1f).scaleY(1f)
-                        .setDuration(1000).setStartDelay(500)
-                        .setInterpolator(new AnticipateOvershootInterpolator())
-                        .start();
-                    tv.setAlpha(0f);
-                    tv.setVisibility(View.VISIBLE);
-                    tv.animate().alpha(1f).setDuration(1000).setStartDelay(1000).start();
-                    return true;
-                }
-                return false;
-            }
-        });
-
-        logo.setOnLongClickListener(new View.OnLongClickListener() {
-            @Override
-            public boolean onLongClick(View v) {
-                if (Settings.System.getLong(getContentResolver(), Settings.System.EGG_MODE, 0)
-                        == 0) {
-                    // For posterity: the moment this user unlocked the easter egg
-                    Settings.System.putLong(getContentResolver(),
-                            Settings.System.EGG_MODE,
-                            System.currentTimeMillis());
-                }
-                try {
-                    startActivity(new Intent(Intent.ACTION_MAIN)
-                        .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                            | Intent.FLAG_ACTIVITY_CLEAR_TASK
-                            | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
-                        .addCategory("com.android.internal.category.PLATLOGO"));
-                } catch (ActivityNotFoundException ex) {
-                    android.util.Log.e("PlatLogoActivity", "Couldn't catch a break.");
-                }
-                finish();
-                return true;
-            }
-        });
-        
-        setContentView(mContent);
+        setContentView(t);
     }
 }
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 882bec9..41f3337 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -1108,13 +1108,6 @@
                 mRuntime = runtime;
             }
         }
-        String webview = WebViewFactory.useExperimentalWebView() ? "chromeview" : "webview";
-        if (!Objects.equals(webview, mWebView)) {
-            changed = true;
-            if (update) {
-                mWebView = webview;
-            }
-        }
         return changed;
     }
 
diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java
index 131f828..66548f0 100644
--- a/core/java/com/android/internal/app/WindowDecorActionBar.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -17,7 +17,9 @@
 package com.android.internal.app;
 
 import android.animation.ValueAnimator;
+import android.content.res.TypedArray;
 import android.view.ViewParent;
+import com.android.internal.R;
 import com.android.internal.view.ActionBarPolicy;
 import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.view.menu.MenuPopupHelper;
@@ -41,7 +43,6 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
-import android.os.Handler;
 import android.util.TypedValue;
 import android.view.ActionMode;
 import android.view.ContextThemeWrapper;
@@ -57,7 +58,6 @@
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
-import java.util.Map;
 
 /**
  * WindowDecorActionBar is the ActionBar implementation used
@@ -66,7 +66,8 @@
  * across both the ActionBarView at the top of the screen and
  * a horizontal LinearLayout at the bottom which is normally hidden.
  */
-public class WindowDecorActionBar extends ActionBar {
+public class WindowDecorActionBar extends ActionBar implements
+        ActionBarOverlayLayout.ActionBarVisibilityCallback {
     private static final String TAG = "WindowDecorActionBar";
 
     private Context mContext;
@@ -116,6 +117,7 @@
 
     private Animator mCurrentShowAnim;
     private boolean mShowHideAnimationEnabled;
+    boolean mHideOnContentScroll;
 
     final AnimatorListener mHideListener = new AnimatorListenerAdapter() {
         @Override
@@ -132,7 +134,7 @@
             mCurrentShowAnim = null;
             completeDeferredDestroyActionMode();
             if (mOverlayLayout != null) {
-                mOverlayLayout.requestFitSystemWindows();
+                mOverlayLayout.requestApplyInsets();
             }
         }
     };
@@ -183,7 +185,7 @@
         mOverlayLayout = (ActionBarOverlayLayout) decor.findViewById(
                 com.android.internal.R.id.action_bar_overlay_layout);
         if (mOverlayLayout != null) {
-            mOverlayLayout.setActionBar(this);
+            mOverlayLayout.setActionBarVisibilityCallback(this);
         }
         mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
         mContextView = (ActionBarContextView) decor.findViewById(
@@ -213,6 +215,14 @@
         ActionBarPolicy abp = ActionBarPolicy.get(mContext);
         setHomeButtonEnabled(abp.enableHomeButtonByDefault() || homeAsUp);
         setHasEmbeddedTabs(abp.hasEmbeddedTabs());
+
+        final TypedArray a = mContext.obtainStyledAttributes(null,
+                com.android.internal.R.styleable.ActionBar,
+                com.android.internal.R.attr.actionBarStyle, 0);
+        if (a.getBoolean(R.styleable.ActionBar_hideOnContentScroll, false)) {
+            setHideOnContentScrollEnabled(true);
+        }
+        a.recycle();
     }
 
     public void onConfigurationChanged(Configuration newConfig) {
@@ -234,17 +244,14 @@
             if (isInTabMode) {
                 mTabScrollView.setVisibility(View.VISIBLE);
                 if (mOverlayLayout != null) {
-                    mOverlayLayout.requestFitSystemWindows();
+                    mOverlayLayout.requestApplyInsets();
                 }
             } else {
                 mTabScrollView.setVisibility(View.GONE);
             }
         }
         mActionView.setCollapsable(!mHasEmbeddedTabs && isInTabMode);
-    }
-
-    public boolean hasNonEmbeddedTabs() {
-        return !mHasEmbeddedTabs && getNavigationMode() == NAVIGATION_MODE_TABS;
+        mOverlayLayout.setHasNonEmbeddedTabs(!mHasEmbeddedTabs && isInTabMode);
     }
 
     private void ensureTabsExist() {
@@ -279,7 +286,7 @@
         }
     }
 
-    public void setWindowVisibility(int visibility) {
+    public void onWindowVisibilityChanged(int visibility) {
         mCurWindowVisibility = visibility;
     }
 
@@ -453,6 +460,7 @@
             mActionMode.finish();
         }
 
+        mOverlayLayout.setHideOnContentScrollEnabled(false);
         mContextView.killMode();
         ActionModeImpl mode = new ActionModeImpl(callback);
         if (mode.dispatchOnCreate()) {
@@ -464,7 +472,7 @@
                 if (mSplitView.getVisibility() != View.VISIBLE) {
                     mSplitView.setVisibility(View.VISIBLE);
                     if (mOverlayLayout != null) {
-                        mOverlayLayout.requestFitSystemWindows();
+                        mOverlayLayout.requestApplyInsets();
                     }
                 }
             }
@@ -652,6 +660,35 @@
         }
     }
 
+    @Override
+    public void setHideOnContentScrollEnabled(boolean hideOnContentScroll) {
+        if (hideOnContentScroll && !mOverlayLayout.isInOverlayMode()) {
+            throw new IllegalStateException("Action bar must be in overlay mode " +
+                    "(Window.FEATURE_OVERLAY_ACTION_BAR) to enable hide on content scroll");
+        }
+        mHideOnContentScroll = hideOnContentScroll;
+        mOverlayLayout.setHideOnContentScrollEnabled(hideOnContentScroll);
+    }
+
+    @Override
+    public boolean isHideOnContentScrollEnabled() {
+        return mOverlayLayout.isHideOnContentScrollEnabled();
+    }
+
+    @Override
+    public int getHideOffset() {
+        return mOverlayLayout.getActionBarHideOffset();
+    }
+
+    @Override
+    public void setHideOffset(int offset) {
+        if (offset != 0 && !mOverlayLayout.isInOverlayMode()) {
+            throw new IllegalStateException("Action bar must be in overlay mode " +
+                    "(Window.FEATURE_OVERLAY_ACTION_BAR) to set a non-zero hide offset");
+        }
+        mOverlayLayout.setActionBarHideOffset(offset);
+    }
+
     private static boolean checkShowingFlags(boolean hiddenByApp, boolean hiddenBySystem,
             boolean showingForMode) {
         if (showingForMode) {
@@ -737,7 +774,7 @@
             mShowListener.onAnimationEnd(null);
         }
         if (mOverlayLayout != null) {
-            mOverlayLayout.requestFitSystemWindows();
+            mOverlayLayout.requestApplyInsets();
         }
     }
 
@@ -781,11 +818,7 @@
     }
 
     public boolean isShowing() {
-        return mNowShowing;
-    }
-
-    public boolean isSystemShowing() {
-        return !mHiddenBySystem;
+        return mNowShowing && getHideOffset() < getHeight();
     }
 
     void animateToMode(boolean toActionMode) {
@@ -844,6 +877,18 @@
         mActionView.setHomeActionContentDescription(resId);
     }
 
+    @Override
+    public void onContentScrollStarted() {
+        if (mCurrentShowAnim != null) {
+            mCurrentShowAnim.cancel();
+            mCurrentShowAnim = null;
+        }
+    }
+
+    @Override
+    public void onContentScrollStopped() {
+    }
+
     /**
      * @hide 
      */
@@ -894,6 +939,7 @@
             // Clear out the context mode views after the animation finishes
             mContextView.closeMode();
             mActionView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+            mOverlayLayout.setHideOnContentScrollEnabled(mHideOnContentScroll);
 
             mActionMode = null;
         }
@@ -1204,6 +1250,7 @@
                 break;
         }
         mActionView.setCollapsable(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
+        mOverlayLayout.setHasNonEmbeddedTabs(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
     }
 
     @Override
diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
index dcc0a4c..e3f21cf 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.inputmethod;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.inputmethod.InputMethodUtils.InputMethodSettings;
 
 import android.content.Context;
@@ -119,14 +120,14 @@
         }
     }
 
-    private static class InputMethodAndSubtypeCircularList {
+    private static class InputMethodAndSubtypeList {
         private final Context mContext;
         // Used to load label
         private final PackageManager mPm;
         private final String mSystemLocaleStr;
         private final InputMethodSettings mSettings;
 
-        public InputMethodAndSubtypeCircularList(Context context, InputMethodSettings settings) {
+        public InputMethodAndSubtypeList(Context context, InputMethodSettings settings) {
             mContext = context;
             mSettings = settings;
             mPm = context.getPackageManager();
@@ -152,38 +153,6 @@
                             }
                         });
 
-        public ImeSubtypeListItem getNextInputMethod(
-                boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype) {
-            if (imi == null) {
-                return null;
-            }
-            final List<ImeSubtypeListItem> imList =
-                    getSortedInputMethodAndSubtypeList();
-            if (imList.size() <= 1) {
-                return null;
-            }
-            final int N = imList.size();
-            final int currentSubtypeId =
-                    subtype != null ? InputMethodUtils.getSubtypeIdFromHashCode(imi,
-                            subtype.hashCode()) : NOT_A_SUBTYPE_ID;
-            for (int i = 0; i < N; ++i) {
-                final ImeSubtypeListItem isli = imList.get(i);
-                if (isli.mImi.equals(imi) && isli.mSubtypeId == currentSubtypeId) {
-                    if (!onlyCurrentIme) {
-                        return imList.get((i + 1) % N);
-                    }
-                    for (int j = 0; j < N - 1; ++j) {
-                        final ImeSubtypeListItem candidate = imList.get((i + j + 1) % N);
-                        if (candidate.mImi.equals(imi)) {
-                            return candidate;
-                        }
-                    }
-                    return null;
-                }
-            }
-            return null;
-        }
-
         public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList() {
             return getSortedInputMethodAndSubtypeList(true, false, false);
         }
@@ -247,7 +216,52 @@
     private final ArrayDeque<SubtypeParams> mTypedSubtypeHistory = new ArrayDeque<SubtypeParams>();
     private final Object mLock = new Object();
     private final InputMethodSettings mSettings;
-    private InputMethodAndSubtypeCircularList mSubtypeList;
+    private InputMethodAndSubtypeList mSubtypeList;
+
+    @VisibleForTesting
+    public static ImeSubtypeListItem getNextInputMethodImpl(List<ImeSubtypeListItem> imList,
+            boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype) {
+        if (imi == null) {
+            return null;
+        }
+        if (imList.size() <= 1) {
+            return null;
+        }
+        // Here we have two rotation groups, depending on the returned boolean value of
+        // {@link InputMethodInfo#supportsSwitchingToNextInputMethod()}.
+        final boolean expectedValueOfSupportsSwitchingToNextInputMethod =
+                imi.supportsSwitchingToNextInputMethod();
+        final int N = imList.size();
+        final int currentSubtypeId =
+                subtype != null ? InputMethodUtils.getSubtypeIdFromHashCode(imi,
+                        subtype.hashCode()) : NOT_A_SUBTYPE_ID;
+        for (int i = 0; i < N; ++i) {
+            final ImeSubtypeListItem isli = imList.get(i);
+            // Skip until the current IME/subtype is found.
+            if (!isli.mImi.equals(imi) || isli.mSubtypeId != currentSubtypeId) {
+                continue;
+            }
+            // Found the current IME/subtype. Start searching the next IME/subtype from here.
+            for (int j = 0; j < N - 1; ++j) {
+                final ImeSubtypeListItem candidate = imList.get((i + j + 1) % N);
+                // Skip if the candidate doesn't belong to the expected rotation group.
+                if (expectedValueOfSupportsSwitchingToNextInputMethod !=
+                        candidate.mImi.supportsSwitchingToNextInputMethod()) {
+                    continue;
+                }
+                // Skip if searching inside the current IME only, but the candidate is not
+                // the current IME.
+                if (onlyCurrentIme && !candidate.mImi.equals(imi)) {
+                    continue;
+                }
+                return candidate;
+            }
+            // No appropriate IME/subtype is found in the list. Give up.
+            return null;
+        }
+        // The current IME/subtype is not found in the list. Give up.
+        return null;
+    }
 
     public InputMethodSubtypeSwitchingController(InputMethodSettings settings) {
         mSettings = settings;
@@ -278,14 +292,15 @@
 
     public void resetCircularListLocked(Context context) {
         synchronized(mLock) {
-            mSubtypeList = new InputMethodAndSubtypeCircularList(context, mSettings);
+            mSubtypeList = new InputMethodAndSubtypeList(context, mSettings);
         }
     }
 
     public ImeSubtypeListItem getNextInputMethod(
             boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype) {
         synchronized(mLock) {
-            return mSubtypeList.getNextInputMethod(onlyCurrentIme, imi, subtype);
+            return getNextInputMethodImpl(mSubtypeList.getSortedInputMethodAndSubtypeList(),
+                    onlyCurrentIme, imi, subtype);
         }
     }
 
diff --git a/core/java/com/android/internal/notification/DemoContactNotificationScorer.java b/core/java/com/android/internal/notification/DemoContactNotificationScorer.java
deleted file mode 100644
index f484724..0000000
--- a/core/java/com/android/internal/notification/DemoContactNotificationScorer.java
+++ /dev/null
@@ -1,188 +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.notification;
-
-import android.app.Notification;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.ContactsContract;
-import android.provider.Settings;
-import android.text.SpannableString;
-import android.util.Slog;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * This NotificationScorer bumps up the priority of notifications that contain references to the
- * display names of starred contacts. The references it picks up are spannable strings which, in
- * their entirety, match the display name of some starred contact. The magnitude of the bump ranges
- * from 0 to 15 (assuming NOTIFICATION_PRIORITY_MULTIPLIER = 10) depending on the initial score, and
- * the mapping is defined by priorityBumpMap. In a production version of this scorer, a notification
- * extra will be used to specify contact identifiers.
- */
-
-public class DemoContactNotificationScorer implements NotificationScorer {
-    private static final String TAG = "DemoContactNotificationScorer";
-    private static final boolean DBG = false;
-
-    protected static final boolean ENABLE_CONTACT_SCORER = true;
-    private static final String SETTING_ENABLE_SCORER = "contact_scorer_enabled";
-    protected boolean mEnabled;
-
-    // see NotificationManagerService
-    private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
-
-    private Context mContext;
-
-    private static final List<String> RELEVANT_KEYS_LIST = Arrays.asList(
-            Notification.EXTRA_INFO_TEXT, Notification.EXTRA_TEXT, Notification.EXTRA_TEXT_LINES,
-            Notification.EXTRA_SUB_TEXT, Notification.EXTRA_TITLE
-    );
-
-    private static final String[] PROJECTION = new String[] {
-            ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME
-    };
-
-    private static final Uri CONTACTS_URI = ContactsContract.Contacts.CONTENT_URI;
-
-    private static List<String> extractSpannedStrings(CharSequence charSequence) {
-        if (charSequence == null) return Collections.emptyList();
-        if (!(charSequence instanceof SpannableString)) {
-            return Arrays.asList(charSequence.toString());
-        }
-        SpannableString spannableString = (SpannableString)charSequence;
-        // get all spans
-        Object[] ssArr = spannableString.getSpans(0, spannableString.length(), Object.class);
-        // spanned string sequences
-        ArrayList<String> sss = new ArrayList<String>();
-        for (Object spanObj : ssArr) {
-            try {
-                sss.add(spannableString.subSequence(spannableString.getSpanStart(spanObj),
-                        spannableString.getSpanEnd(spanObj)).toString());
-            } catch(StringIndexOutOfBoundsException e) {
-                Slog.e(TAG, "Bad indices when extracting spanned subsequence", e);
-            }
-        }
-        return sss;
-    };
-
-    private static String getQuestionMarksInParens(int n) {
-        StringBuilder sb = new StringBuilder("(");
-        for (int i = 0; i < n; i++) {
-            if (sb.length() > 1) sb.append(',');
-            sb.append('?');
-        }
-        sb.append(")");
-        return sb.toString();
-    }
-
-    private boolean hasStarredContact(Bundle extras) {
-        if (extras == null) return false;
-        ArrayList<String> qStrings = new ArrayList<String>();
-        // build list to query against the database for display names.
-        for (String rk: RELEVANT_KEYS_LIST) {
-            if (extras.get(rk) == null) {
-                continue;
-            } else if (extras.get(rk) instanceof CharSequence) {
-                qStrings.addAll(extractSpannedStrings((CharSequence) extras.get(rk)));
-            } else if (extras.get(rk) instanceof CharSequence[]) {
-                // this is intended for Notification.EXTRA_TEXT_LINES
-                for (CharSequence line: (CharSequence[]) extras.get(rk)){
-                    qStrings.addAll(extractSpannedStrings(line));
-                }
-            } else {
-                Slog.w(TAG, "Strange, the extra " + rk + " is of unexpected type.");
-            }
-        }
-        if (qStrings.isEmpty()) return false;
-        String[] qStringsArr = qStrings.toArray(new String[qStrings.size()]);
-
-        String selection = ContactsContract.Contacts.DISPLAY_NAME + " IN "
-                + getQuestionMarksInParens(qStringsArr.length) + " AND "
-                + ContactsContract.Contacts.STARRED+" ='1'";
-
-        Cursor c = null;
-        try {
-            c = mContext.getContentResolver().query(
-                    CONTACTS_URI, PROJECTION, selection, qStringsArr, null);
-            if (c != null) return c.getCount() > 0;
-        } catch(Throwable t) {
-            Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t);
-        } finally {
-            if (c != null) {
-                c.close();
-            }
-        }
-        return false;
-    }
-
-    private final static int clamp(int x, int low, int high) {
-        return (x < low) ? low : ((x > high) ? high : x);
-    }
-
-    private static int priorityBumpMap(int incomingScore) {
-        //assumption is that scale runs from [-2*pm, 2*pm]
-        int pm = NOTIFICATION_PRIORITY_MULTIPLIER;
-        int theScore = incomingScore;
-        // enforce input in range
-        theScore = clamp(theScore, -2 * pm, 2 * pm);
-        if (theScore != incomingScore) return incomingScore;
-        // map -20 -> -20 and -10 -> 5 (when pm = 10)
-        if (theScore <= -pm) {
-            theScore += 1.5 * (theScore + 2 * pm);
-        } else {
-            // map 0 -> 10, 10 -> 15, 20 -> 20;
-            theScore += 0.5 * (2 * pm - theScore);
-        }
-        if (DBG) Slog.v(TAG, "priorityBumpMap: score before: " + incomingScore
-                + ", score after " + theScore + ".");
-        return theScore;
-    }
-
-    @Override
-    public void initialize(Context context) {
-        if (DBG) Slog.v(TAG, "Initializing  " + getClass().getSimpleName() + ".");
-        mContext = context;
-        mEnabled = ENABLE_CONTACT_SCORER && 1 == Settings.Global.getInt(
-                mContext.getContentResolver(), SETTING_ENABLE_SCORER, 0);
-    }
-
-    @Override
-    public int getScore(Notification notification, int score) {
-        if (notification == null || !mEnabled) {
-            if (DBG) Slog.w(TAG, "empty notification? scorer disabled?");
-            return score;
-        }
-        boolean hasStarredPriority = hasStarredContact(notification.extras);
-
-        if (DBG) {
-            if (hasStarredPriority) {
-                Slog.v(TAG, "Notification references starred contact. Promoted!");
-            } else {
-                Slog.v(TAG, "Notification lacks any starred contact reference. Not promoted!");
-            }
-        }
-        if (hasStarredPriority) score = priorityBumpMap(score);
-        return score;
-    }
-}
-
diff --git a/core/java/com/android/internal/notification/NotificationScorer.java b/core/java/com/android/internal/notification/NotificationScorer.java
deleted file mode 100644
index 863c08c..0000000
--- a/core/java/com/android/internal/notification/NotificationScorer.java
+++ /dev/null
@@ -1,27 +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.notification;
-
-import android.app.Notification;
-import android.content.Context;
-
-public interface NotificationScorer {
-
-    public void initialize(Context context);
-    public int getScore(Notification notification, int score);
-
-}
diff --git a/core/java/com/android/internal/notification/PeopleNotificationScorer.java b/core/java/com/android/internal/notification/PeopleNotificationScorer.java
deleted file mode 100644
index efb5f63..0000000
--- a/core/java/com/android/internal/notification/PeopleNotificationScorer.java
+++ /dev/null
@@ -1,227 +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.notification;
-
-import android.app.Notification;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.Contacts;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.LruCache;
-import android.util.Slog;
-
-/**
- * This {@link NotificationScorer} attempts to validate people references.
- * Also elevates the priority of real people.
- */
-public class PeopleNotificationScorer implements NotificationScorer {
-    private static final String TAG = "PeopleNotificationScorer";
-    private static final boolean DBG = false;
-
-    private static final boolean ENABLE_PEOPLE_SCORER = true;
-    private static final String SETTING_ENABLE_PEOPLE_SCORER = "people_scorer_enabled";
-    private static final String[] LOOKUP_PROJECTION = { Contacts._ID };
-    private static final int MAX_PEOPLE = 10;
-    private static final int PEOPLE_CACHE_SIZE = 200;
-    // see NotificationManagerService
-    private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
-
-    protected boolean mEnabled;
-    private Context mContext;
-
-    // maps raw person handle to resolved person object
-    private LruCache<String, LookupResult> mPeopleCache;
-
-    private float findMaxContactScore(Bundle extras) {
-        if (extras == null) {
-            return 0f;
-        }
-
-        final String[] people = extras.getStringArray(Notification.EXTRA_PEOPLE);
-        if (people == null || people.length == 0) {
-            return 0f;
-        }
-
-        float rank = 0f;
-        for (int personIdx = 0; personIdx < people.length && personIdx < MAX_PEOPLE; personIdx++) {
-            final String handle = people[personIdx];
-            if (TextUtils.isEmpty(handle)) continue;
-
-            LookupResult lookupResult = mPeopleCache.get(handle);
-            if (lookupResult == null || lookupResult.isExpired()) {
-                final Uri uri = Uri.parse(handle);
-                if ("tel".equals(uri.getScheme())) {
-                    if (DBG) Slog.w(TAG, "checking telephone URI: " + handle);
-                    lookupResult = lookupPhoneContact(handle, uri.getSchemeSpecificPart());
-                } else if (handle.startsWith(Contacts.CONTENT_LOOKUP_URI.toString())) {
-                    if (DBG) Slog.w(TAG, "checking lookup URI: " + handle);
-                    lookupResult = resolveContactsUri(handle, uri);
-                } else {
-                    if (DBG) Slog.w(TAG, "unsupported URI " + handle);
-                }
-            } else {
-                if (DBG) Slog.w(TAG, "using cached lookupResult: " + lookupResult.mId);
-            }
-            if (lookupResult != null) {
-                rank = Math.max(rank, lookupResult.getRank());
-            }
-        }
-        return rank;
-    }
-
-    private LookupResult lookupPhoneContact(final String handle, final String number) {
-        LookupResult lookupResult = null;
-        Cursor c = null;
-        try {
-            Uri numberUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
-                    Uri.encode(number));
-            c = mContext.getContentResolver().query(numberUri, LOOKUP_PROJECTION, null, null, null);
-            if (c != null && c.getCount() > 0) {
-                c.moveToFirst();
-                final int idIdx = c.getColumnIndex(Contacts._ID);
-                final int id = c.getInt(idIdx);
-                if (DBG) Slog.w(TAG, "is valid: " + id);
-                lookupResult = new LookupResult(id);
-            }
-        } catch(Throwable t) {
-            Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t);
-        } finally {
-            if (c != null) {
-                c.close();
-            }
-        }
-        if (lookupResult == null) {
-            lookupResult = new LookupResult(LookupResult.INVALID_ID);
-        }
-        mPeopleCache.put(handle, lookupResult);
-        return lookupResult;
-    }
-
-    private LookupResult resolveContactsUri(String handle, final Uri personUri) {
-        LookupResult lookupResult = null;
-        Cursor c = null;
-        try {
-            c = mContext.getContentResolver().query(personUri, LOOKUP_PROJECTION, null, null, null);
-            if (c != null && c.getCount() > 0) {
-                c.moveToFirst();
-                final int idIdx = c.getColumnIndex(Contacts._ID);
-                final int id = c.getInt(idIdx);
-                if (DBG) Slog.w(TAG, "is valid: " + id);
-                lookupResult = new LookupResult(id);
-            }
-        } catch(Throwable t) {
-            Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t);
-        } finally {
-            if (c != null) {
-                c.close();
-            }
-        }
-        if (lookupResult == null) {
-            lookupResult = new LookupResult(LookupResult.INVALID_ID);
-        }
-        mPeopleCache.put(handle, lookupResult);
-        return lookupResult;
-    }
-
-    private final static int clamp(int x, int low, int high) {
-        return (x < low) ? low : ((x > high) ? high : x);
-    }
-
-    // TODO: rework this function before shipping
-    private static int priorityBumpMap(int incomingScore) {
-        //assumption is that scale runs from [-2*pm, 2*pm]
-        int pm = NOTIFICATION_PRIORITY_MULTIPLIER;
-        int theScore = incomingScore;
-        // enforce input in range
-        theScore = clamp(theScore, -2 * pm, 2 * pm);
-        if (theScore != incomingScore) return incomingScore;
-        // map -20 -> -20 and -10 -> 5 (when pm = 10)
-        if (theScore <= -pm) {
-            theScore += 1.5 * (theScore + 2 * pm);
-        } else {
-            // map 0 -> 10, 10 -> 15, 20 -> 20;
-            theScore += 0.5 * (2 * pm - theScore);
-        }
-        if (DBG) Slog.v(TAG, "priorityBumpMap: score before: " + incomingScore
-                + ", score after " + theScore + ".");
-        return theScore;
-    }
-
-    @Override
-    public void initialize(Context context) {
-        if (DBG) Slog.v(TAG, "Initializing  " + getClass().getSimpleName() + ".");
-        mContext = context;
-        mPeopleCache = new LruCache<String, LookupResult>(PEOPLE_CACHE_SIZE);
-        mEnabled = ENABLE_PEOPLE_SCORER && 1 == Settings.Global.getInt(
-                mContext.getContentResolver(), SETTING_ENABLE_PEOPLE_SCORER, 0);
-    }
-
-    @Override
-    public int getScore(Notification notification, int score) {
-        if (notification == null || !mEnabled) {
-            if (DBG) Slog.w(TAG, "empty notification? scorer disabled?");
-            return score;
-        }
-        float contactScore = findMaxContactScore(notification.extras);
-        if (contactScore > 0f) {
-            if (DBG) Slog.v(TAG, "Notification references a real contact. Promoted!");
-            score = priorityBumpMap(score);
-        } else {
-            if (DBG) Slog.v(TAG, "Notification lacks any valid contact reference. Not promoted!");
-        }
-        return score;
-    }
-
-    private static class LookupResult {
-        private static final long CONTACT_REFRESH_MILLIS = 60 * 60 * 1000;  // 1hr
-        public static final int INVALID_ID = -1;
-
-        private final long mExpireMillis;
-        private int mId;
-
-        public LookupResult(int id) {
-            mId = id;
-            mExpireMillis = System.currentTimeMillis() + CONTACT_REFRESH_MILLIS;
-        }
-
-        public boolean isExpired() {
-            return mExpireMillis < System.currentTimeMillis();
-        }
-
-        public boolean isInvalid() {
-            return mId == INVALID_ID || isExpired();
-        }
-
-        public float getRank() {
-            if (isInvalid()) {
-                return 0f;
-            } else {
-                return 1f;  // TODO: finer grained score
-            }
-        }
-
-        public LookupResult setId(int id) {
-            mId = id;
-            return this;
-        }
-    }
-}
-
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index f63fa8a..7bd5b12 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -51,6 +51,7 @@
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.util.TimeUtils;
+import android.view.Display;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.net.NetworkStatsFactory;
@@ -88,7 +89,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 104 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 105 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -187,8 +188,7 @@
 
     boolean mShuttingDown;
 
-    HashMap<String, SparseBooleanArray>[] mActiveEvents
-            = (HashMap<String, SparseBooleanArray>[]) new HashMap[HistoryItem.EVENT_COUNT];
+    final HistoryEventTracker mActiveEvents = new HistoryEventTracker();
 
     long mHistoryBaseTime;
     boolean mHaveBatteryLevel = false;
@@ -237,13 +237,14 @@
     int mWakeLockNesting;
     boolean mWakeLockImportant;
 
-    boolean mScreenOn;
+    int mScreenState = Display.STATE_UNKNOWN;
     StopwatchTimer mScreenOnTimer;
 
     int mScreenBrightnessBin = -1;
     final StopwatchTimer[] mScreenBrightnessTimer = new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS];
 
-    Counter mInputEventCounter;
+    boolean mInteractive;
+    StopwatchTimer mInteractiveTimer;
 
     boolean mPhoneOn;
     StopwatchTimer mPhoneOnTimer;
@@ -2295,44 +2296,8 @@
 
     public void noteEventLocked(int code, String name, int uid) {
         uid = mapUid(uid);
-        if ((code&HistoryItem.EVENT_FLAG_START) != 0) {
-            int idx = code&~HistoryItem.EVENT_FLAG_START;
-            HashMap<String, SparseBooleanArray> active = mActiveEvents[idx];
-            if (active == null) {
-                active = new HashMap<String, SparseBooleanArray>();
-                mActiveEvents[idx] = active;
-            }
-            SparseBooleanArray uids = active.get(name);
-            if (uids == null) {
-                uids = new SparseBooleanArray();
-                active.put(name, uids);
-            }
-            if (uids.get(uid)) {
-                // Already set, nothing to do!
-                return;
-            }
-            uids.put(uid, true);
-        } else if ((code&HistoryItem.EVENT_FLAG_FINISH) != 0) {
-            int idx = code&~HistoryItem.EVENT_FLAG_FINISH;
-            HashMap<String, SparseBooleanArray> active = mActiveEvents[idx];
-            if (active == null) {
-                // not currently active, nothing to do.
-                return;
-            }
-            SparseBooleanArray uids = active.get(name);
-            if (uids == null) {
-                // not currently active, nothing to do.
-                return;
-            }
-            idx = uids.indexOfKey(uid);
-            if (idx < 0 || !uids.valueAt(idx)) {
-                // not currently active, nothing to do.
-                return;
-            }
-            uids.removeAt(idx);
-            if (uids.size() <= 0) {
-                active.remove(name);
-            }
+        if (!mActiveEvents.updateState(code, name, uid, 0)) {
+            return;
         }
         final long elapsedRealtime = SystemClock.elapsedRealtime();
         final long uptime = SystemClock.uptimeMillis();
@@ -2346,6 +2311,9 @@
         }
     }
 
+    private String mInitialAcquireWakeName;
+    private int mInitialAcquireWakeUid = -1;
+
     public void noteStartWakeLocked(int uid, int pid, String name, String historyName, int type,
             boolean unimportantForLogging, long elapsedRealtime, long uptime) {
         uid = mapUid(uid);
@@ -2358,8 +2326,9 @@
                 if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: "
                         + Integer.toHexString(mHistoryCur.states));
                 mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
-                mHistoryCur.wakelockTag.string = historyName != null ? historyName : name;
-                mHistoryCur.wakelockTag.uid = uid;
+                mHistoryCur.wakelockTag.string = mInitialAcquireWakeName
+                        = historyName != null ? historyName : name;
+                mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
                 mWakeLockImportant = !unimportantForLogging;
                 addHistoryRecordLocked(elapsedRealtime, uptime);
             } else if (!mWakeLockImportant && !unimportantForLogging) {
@@ -2367,8 +2336,9 @@
                     // We'll try to update the last tag.
                     mHistoryLastWritten.wakelockTag = null;
                     mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
-                    mHistoryCur.wakelockTag.string = historyName != null ? historyName : name;
-                    mHistoryCur.wakelockTag.uid = uid;
+                    mHistoryCur.wakelockTag.string = mInitialAcquireWakeName
+                            = historyName != null ? historyName : name;
+                    mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
                     addHistoryRecordLocked(elapsedRealtime, uptime);
                 }
                 mWakeLockImportant = true;
@@ -2393,6 +2363,14 @@
                 mHistoryCur.states &= ~HistoryItem.STATE_WAKE_LOCK_FLAG;
                 if (DEBUG_HISTORY) Slog.v(TAG, "Stop wake lock to: "
                         + Integer.toHexString(mHistoryCur.states));
+                if ((name != null && !name.equals(mInitialAcquireWakeName))
+                        || uid != mInitialAcquireWakeUid) {
+                    mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
+                    mHistoryCur.wakelockTag.string = name;
+                    mHistoryCur.wakelockTag.uid = uid;
+                }
+                mInitialAcquireWakeName = null;
+                mInitialAcquireWakeUid = -1;
                 addHistoryRecordLocked(elapsedRealtime, uptime);
             }
         }
@@ -2661,58 +2639,61 @@
         getUidStatsLocked(uid).noteStopGps(elapsedRealtime);
     }
 
-    public void noteScreenOnLocked() {
-        if (!mScreenOn) {
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
-            final long uptime = SystemClock.uptimeMillis();
-            mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG;
-            if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
-                    + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
-            mScreenOn = true;
-            mScreenOnTimer.startRunningLocked(elapsedRealtime);
-            if (mScreenBrightnessBin >= 0) {
-                mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(elapsedRealtime);
-            }
+    public void noteScreenStateLocked(int state) {
+        if (mScreenState != state) {
+            final int oldState = mScreenState;
+            mScreenState = state;
+            if (DEBUG) Slog.v(TAG, "Screen state: oldState=" + Display.stateToString(oldState)
+                    + ", newState=" + Display.stateToString(state));
 
-            updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), false,
-                    SystemClock.uptimeMillis() * 1000, elapsedRealtime * 1000);
+            if (state == Display.STATE_ON) {
+                // Screen turning on.
+                final long elapsedRealtime = SystemClock.elapsedRealtime();
+                final long uptime = SystemClock.uptimeMillis();
+                mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG;
+                if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
+                        + Integer.toHexString(mHistoryCur.states));
+                addHistoryRecordLocked(elapsedRealtime, uptime);
+                mScreenOnTimer.startRunningLocked(elapsedRealtime);
+                if (mScreenBrightnessBin >= 0) {
+                    mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(elapsedRealtime);
+                }
 
-            // Fake a wake lock, so we consider the device waked as long
-            // as the screen is on.
-            noteStartWakeLocked(-1, -1, "screen", null, WAKE_TYPE_PARTIAL, false,
-                    elapsedRealtime, uptime);
+                updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), false,
+                        SystemClock.uptimeMillis() * 1000, elapsedRealtime * 1000);
 
-            // Update discharge amounts.
-            if (mOnBatteryInternal) {
-                updateDischargeScreenLevelsLocked(false, true);
-            }
-        }
-    }
+                // Fake a wake lock, so we consider the device waked as long
+                // as the screen is on.
+                noteStartWakeLocked(-1, -1, "screen", null, WAKE_TYPE_PARTIAL, false,
+                        elapsedRealtime, uptime);
 
-    public void noteScreenOffLocked() {
-        if (mScreenOn) {
-            final long elapsedRealtime = SystemClock.elapsedRealtime();
-            final long uptime = SystemClock.uptimeMillis();
-            mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG;
-            if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
-                    + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
-            mScreenOn = false;
-            mScreenOnTimer.stopRunningLocked(elapsedRealtime);
-            if (mScreenBrightnessBin >= 0) {
-                mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(elapsedRealtime);
-            }
+                // Update discharge amounts.
+                if (mOnBatteryInternal) {
+                    updateDischargeScreenLevelsLocked(false, true);
+                }
+            } else if (oldState == Display.STATE_ON) {
+                // Screen turning off or dozing.
+                final long elapsedRealtime = SystemClock.elapsedRealtime();
+                final long uptime = SystemClock.uptimeMillis();
+                mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG;
+                if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
+                        + Integer.toHexString(mHistoryCur.states));
+                addHistoryRecordLocked(elapsedRealtime, uptime);
+                mScreenOnTimer.stopRunningLocked(elapsedRealtime);
+                if (mScreenBrightnessBin >= 0) {
+                    mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(elapsedRealtime);
+                }
 
-            noteStopWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL,
-                    elapsedRealtime, uptime);
+                noteStopWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL,
+                        elapsedRealtime, uptime);
 
-            updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), true,
-                    SystemClock.uptimeMillis() * 1000, elapsedRealtime * 1000);
+                updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), true,
+                        SystemClock.uptimeMillis() * 1000, elapsedRealtime * 1000);
 
-            // Update discharge amounts.
-            if (mOnBatteryInternal) {
-                updateDischargeScreenLevelsLocked(true, false);
+                // Update discharge amounts.
+                if (mOnBatteryInternal) {
+                    updateDischargeScreenLevelsLocked(true, false);
+                }
             }
         }
     }
@@ -2730,7 +2711,7 @@
             if (DEBUG_HISTORY) Slog.v(TAG, "Screen brightness " + bin + " to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime, uptime);
-            if (mScreenOn) {
+            if (mScreenState == Display.STATE_ON) {
                 if (mScreenBrightnessBin >= 0) {
                     mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(elapsedRealtime);
                 }
@@ -2740,10 +2721,6 @@
         }
     }
 
-    public void noteInputEventAtomic() {
-        mInputEventCounter.stepAtomic();
-    }
-
     public void noteUserActivityLocked(int uid, int event) {
         if (mOnBatteryInternal) {
             uid = mapUid(uid);
@@ -2751,6 +2728,19 @@
         }
     }
 
+    public void noteInteractiveLocked(boolean interactive) {
+        if (mInteractive != interactive) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            mInteractive = interactive;
+            if (DEBUG) Slog.v(TAG, "Interactive: " + interactive);
+            if (interactive) {
+                mInteractiveTimer.startRunningLocked(elapsedRealtime);
+            } else {
+                mInteractiveTimer.stopRunningLocked(elapsedRealtime);
+            }
+        }
+    }
+
     public void noteMobileRadioPowerState(int powerState, long timestampNs) {
         final long elapsedRealtime = SystemClock.elapsedRealtime();
         final long uptime = SystemClock.uptimeMillis();
@@ -3449,8 +3439,8 @@
                 elapsedRealtimeUs, which);
     }
 
-    @Override public int getInputEventCount(int which) {
-        return mInputEventCounter.getCountLocked(which);
+    @Override public long getInteractiveTime(long elapsedRealtimeUs, int which) {
+        return mInteractiveTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
     }
 
     @Override public long getPhoneOnTime(long elapsedRealtimeUs, int which) {
@@ -5499,7 +5489,6 @@
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
             mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mOnBatteryTimeBase);
         }
-        mInputEventCounter = new Counter(mOnBatteryTimeBase);
         mPhoneOnTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
             mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i, null,
@@ -5530,6 +5519,7 @@
         }
         mAudioOnTimer = new StopwatchTimer(null, -6, null, mOnBatteryTimeBase);
         mVideoOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
+        mInteractiveTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
         mOnBattery = mOnBatteryInternal = false;
         long uptime = SystemClock.uptimeMillis() * 1000;
         long realtime = SystemClock.elapsedRealtime() * 1000;
@@ -5685,7 +5675,8 @@
         final long lastRealtime = out.time;
         final long lastWalltime = out.currentTime;
         readHistoryDelta(mHistoryBuffer, out);
-        if (out.cmd != HistoryItem.CMD_CURRENT_TIME && lastWalltime != 0) {
+        if (out.cmd != HistoryItem.CMD_CURRENT_TIME
+                && out.cmd != HistoryItem.CMD_RESET && lastWalltime != 0) {
             out.currentTime = lastWalltime + (out.time - lastRealtime);
         }
         return true;
@@ -5713,7 +5704,7 @@
     }
 
     public boolean isScreenOn() {
-        return mScreenOn;
+        return mScreenState == Display.STATE_ON;
     }
 
     void initTimes(long uptime, long realtime) {
@@ -5753,7 +5744,7 @@
         mOnBatteryTimeBase.reset(uptime, realtime);
         mOnBatteryScreenOffTimeBase.reset(uptime, realtime);
         if ((mHistoryCur.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) == 0) {
-            if (mScreenOn) {
+            if (mScreenState == Display.STATE_ON) {
                 mDischargeScreenOnUnplugLevel = mHistoryCur.batteryLevel;
                 mDischargeScreenOffUnplugLevel = 0;
             } else {
@@ -5773,7 +5764,7 @@
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
             mScreenBrightnessTimer[i].reset(false);
         }
-        mInputEventCounter.reset(false);
+        mInteractiveTimer.reset(false);
         mPhoneOnTimer.reset(false);
         mAudioOnTimer.reset(false);
         mVideoOnTimer.reset(false);
@@ -5831,17 +5822,15 @@
 
     private void initActiveHistoryEventsLocked(long elapsedRealtimeMs, long uptimeMs) {
         for (int i=0; i<HistoryItem.EVENT_COUNT; i++) {
-            HashMap<String, SparseBooleanArray> active = mActiveEvents[i];
+            HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(i);
             if (active == null) {
                 continue;
             }
-            for (HashMap.Entry<String, SparseBooleanArray> ent : active.entrySet()) {
-                SparseBooleanArray uids = ent.getValue();
+            for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) {
+                SparseIntArray uids = ent.getValue();
                 for (int j=0; j<uids.size(); j++) {
-                    if (uids.valueAt(j)) {
-                        addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, i, ent.getKey(),
-                                uids.keyAt(j));
-                    }
+                    addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, i, ent.getKey(),
+                            uids.keyAt(j));
                 }
             }
         }
@@ -5874,7 +5863,8 @@
         updateKernelWakelocksLocked();
         updateNetworkActivityLocked(NET_UPDATE_ALL, SystemClock.elapsedRealtime());
         if (mOnBatteryInternal) {
-            updateDischargeScreenLevelsLocked(mScreenOn, mScreenOn);
+            final boolean screenOn = mScreenState == Display.STATE_ON;
+            updateDischargeScreenLevelsLocked(screenOn, screenOn);
         }
     }
 
@@ -5888,6 +5878,7 @@
 
         final long uptime = mSecUptime * 1000;
         final long realtime = mSecRealtime * 1000;
+        final boolean screenOn = mScreenState == Display.STATE_ON;
         if (onBattery) {
             // We will reset our status if we are unplugging after the
             // battery was last full, or the level is at 100, or
@@ -5916,7 +5907,7 @@
             }
             addHistoryRecordLocked(mSecRealtime, mSecUptime);
             mDischargeCurrentLevel = mDischargeUnplugLevel = level;
-            if (mScreenOn) {
+            if (screenOn) {
                 mDischargeScreenOnUnplugLevel = level;
                 mDischargeScreenOffUnplugLevel = 0;
             } else {
@@ -5925,7 +5916,7 @@
             }
             mDischargeAmountScreenOn = 0;
             mDischargeAmountScreenOff = 0;
-            updateTimeBasesLocked(true, !mScreenOn, uptime, realtime);
+            updateTimeBasesLocked(true, !screenOn, uptime, realtime);
         } else {
             pullPendingStateUpdatesLocked();
             mHistoryCur.batteryLevel = (byte)level;
@@ -5938,8 +5929,8 @@
                 mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
                 mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
             }
-            updateDischargeScreenLevelsLocked(mScreenOn, mScreenOn);
-            updateTimeBasesLocked(false, !mScreenOn, uptime, realtime);
+            updateDischargeScreenLevelsLocked(screenOn, screenOn);
+            updateTimeBasesLocked(false, !screenOn, uptime, realtime);
             mNumChargeStepDurations = 0;
             mLastChargeStepLevel = level;
             mLastChargeStepTime = -1;
@@ -5955,7 +5946,8 @@
             boolean reset) {
         mRecordingHistory = true;
         mHistoryCur.currentTime = System.currentTimeMillis();
-        addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_CURRENT_TIME,
+        addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs,
+                reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME,
                 mHistoryCur);
         mHistoryCur.currentTime = 0;
         if (reset) {
@@ -6475,7 +6467,7 @@
     public int getDischargeAmountScreenOn() {
         synchronized(this) {
             int val = mDischargeAmountScreenOn;
-            if (mOnBattery && mScreenOn
+            if (mOnBattery && mScreenState == Display.STATE_ON
                     && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
                 val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
             }
@@ -6486,7 +6478,7 @@
     public int getDischargeAmountScreenOnSinceCharge() {
         synchronized(this) {
             int val = mDischargeAmountScreenOnSinceCharge;
-            if (mOnBattery && mScreenOn
+            if (mOnBattery && mScreenState == Display.STATE_ON
                     && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
                 val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
             }
@@ -6497,7 +6489,7 @@
     public int getDischargeAmountScreenOff() {
         synchronized(this) {
             int val = mDischargeAmountScreenOff;
-            if (mOnBattery && !mScreenOn
+            if (mOnBattery && mScreenState != Display.STATE_ON
                     && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
                 val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
             }
@@ -6508,7 +6500,7 @@
     public int getDischargeAmountScreenOffSinceCharge() {
         synchronized(this) {
             int val = mDischargeAmountScreenOffSinceCharge;
-            if (mOnBattery && !mScreenOn
+            if (mOnBattery && mScreenState != Display.STATE_ON
                     && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
                 val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
             }
@@ -6915,12 +6907,13 @@
 
         mStartCount++;
 
-        mScreenOn = false;
+        mScreenState = Display.STATE_UNKNOWN;
         mScreenOnTimer.readSummaryFromParcelLocked(in);
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
             mScreenBrightnessTimer[i].readSummaryFromParcelLocked(in);
         }
-        mInputEventCounter.readSummaryFromParcelLocked(in);
+        mInteractive = false;
+        mInteractiveTimer.readSummaryFromParcelLocked(in);
         mPhoneOn = false;
         mPhoneOnTimer.readSummaryFromParcelLocked(in);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
@@ -7175,7 +7168,7 @@
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
             mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         }
-        mInputEventCounter.writeSummaryFromParcelLocked(out);
+        mInteractiveTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
             mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
@@ -7431,13 +7424,12 @@
         mOnBatteryTimeBase.readFromParcel(in);
         mOnBatteryScreenOffTimeBase.readFromParcel(in);
 
-        mScreenOn = false;
+        mScreenState = Display.STATE_UNKNOWN;
         mScreenOnTimer = new StopwatchTimer(null, -1, null, mOnBatteryTimeBase, in);
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
             mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mOnBatteryTimeBase,
                     in);
         }
-        mInputEventCounter = new Counter(mOnBatteryTimeBase, in);
         mPhoneOn = false;
         mPhoneOnTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
@@ -7461,19 +7453,25 @@
         mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
         mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase, in);
         mWifiOn = false;
-        mWifiOnTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
+        mWifiOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase, in);
         mGlobalWifiRunning = false;
-        mGlobalWifiRunningTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
+        mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mOnBatteryTimeBase, in);
         for (int i=0; i<NUM_WIFI_STATES; i++) {
             mWifiStateTimer[i] = new StopwatchTimer(null, -600-i,
                     null, mOnBatteryTimeBase, in);
         }
         mBluetoothOn = false;
-        mBluetoothOnTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
+        mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mOnBatteryTimeBase, in);
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i,
                     null, mOnBatteryTimeBase, in);
         }
+        mAudioOn = false;
+        mAudioOnTimer = new StopwatchTimer(null, -6, null, mOnBatteryTimeBase);
+        mVideoOn = false;
+        mVideoOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
+        mInteractive = false;
+        mInteractiveTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase, in);
         mDischargeUnplugLevel = in.readInt();
         mDischargePlugLevel = in.readInt();
         mDischargeCurrentLevel = in.readInt();
@@ -7571,7 +7569,7 @@
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
             mScreenBrightnessTimer[i].writeToParcel(out, uSecRealtime);
         }
-        mInputEventCounter.writeToParcel(out);
+        mInteractiveTimer.writeToParcel(out, uSecRealtime);
         mPhoneOnTimer.writeToParcel(out, uSecRealtime);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
             mPhoneSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
@@ -7688,8 +7686,8 @@
                 pr.println("*** Screen brightness #" + i + ":");
                 mScreenBrightnessTimer[i].logState(pr, "  ");
             }
-            pr.println("*** Input event counter:");
-            mInputEventCounter.logState(pr, "  ");
+            pr.println("*** Interactive timer:");
+            mInteractiveTimer.logState(pr, "  ");
             pr.println("*** Phone timer:");
             mPhoneOnTimer.logState(pr, "  ");
             for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
diff --git a/core/java/com/android/internal/os/PkgUsageStats.aidl b/core/java/com/android/internal/os/PkgUsageStats.aidl
deleted file mode 100644
index 8305271..0000000
--- a/core/java/com/android/internal/os/PkgUsageStats.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/* //device/java/android/android/content/Intent.aidl
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
-
-package com.android.internal.os;
-
-parcelable PkgUsageStats;
diff --git a/core/java/com/android/internal/os/PkgUsageStats.java b/core/java/com/android/internal/os/PkgUsageStats.java
deleted file mode 100644
index 8c2c405..0000000
--- a/core/java/com/android/internal/os/PkgUsageStats.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.os;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * implementation of PkgUsageStats associated with an
- * application package.
- *  @hide
- */
-public class PkgUsageStats implements Parcelable {
-    public String packageName;
-    public int launchCount;
-    public long usageTime;
-    public Map<String, Long> componentResumeTimes;
-    
-    public static final Parcelable.Creator<PkgUsageStats> CREATOR
-    = new Parcelable.Creator<PkgUsageStats>() {
-        public PkgUsageStats createFromParcel(Parcel in) {
-            return new PkgUsageStats(in);
-        }
-
-        public PkgUsageStats[] newArray(int size) {
-            return new PkgUsageStats[size];
-        }
-    };
-    
-    public String toString() {
-        return "PkgUsageStats{"
-        + Integer.toHexString(System.identityHashCode(this))
-        + " " + packageName + "}";
-    }
-    
-    public PkgUsageStats(String pkgName, int count, long time, Map<String, Long> lastResumeTimes) {
-        packageName = pkgName;
-        launchCount = count;
-        usageTime = time;
-        componentResumeTimes = new HashMap<String, Long>(lastResumeTimes);
-    }
-    
-    public PkgUsageStats(Parcel source) {
-        packageName = source.readString();
-        launchCount = source.readInt();
-        usageTime = source.readLong();
-        final int N = source.readInt();
-        componentResumeTimes = new HashMap<String, Long>(N);
-        for (int i = 0; i < N; i++) {
-            String component = source.readString();
-            long lastResumeTime = source.readLong();
-            componentResumeTimes.put(component, lastResumeTime);
-        }
-    }
-    
-    public PkgUsageStats(PkgUsageStats pStats) {
-        packageName = pStats.packageName;
-        launchCount = pStats.launchCount;
-        usageTime = pStats.usageTime;
-        componentResumeTimes = new HashMap<String, Long>(pStats.componentResumeTimes);
-    }
-
-    public int describeContents() {
-        return 0;
-    }
-
-    public void writeToParcel(Parcel dest, int parcelableFlags) {
-        dest.writeString(packageName);
-        dest.writeInt(launchCount);
-        dest.writeLong(usageTime);
-        dest.writeInt(componentResumeTimes.size());
-        for (Map.Entry<String, Long> ent : componentResumeTimes.entrySet()) {
-            dest.writeString(ent.getKey());
-            dest.writeLong(ent.getValue());
-        }
-    }
-}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index d1d1a52..75feb5d 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -33,7 +33,8 @@
     void animateCollapsePanels();
     void setSystemUiVisibility(int vis, int mask);
     void topAppWindowChanged(boolean menuVisible);
-    void setImeWindowStatus(in IBinder token, int vis, int backDisposition);
+    void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
+            boolean showImeSwitcher);
     void setHardKeyboardStatus(boolean available, boolean enabled);
     void toggleRecentApps();
     void preloadRecentApps();
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 6428e15..cf334c3 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -31,7 +31,8 @@
     void setIconVisibility(String slot, boolean visible);
     void removeIcon(String slot);
     void topAppWindowChanged(boolean menuVisible);
-    void setImeWindowStatus(in IBinder token, int vis, int backDisposition);
+    void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
+            boolean showImeSwitcher);
     void expandSettingsPanel();
     void setCurrentUser(int newUserId);
 
@@ -42,7 +43,7 @@
             out int[] switches, out List<IBinder> binders);
     void onPanelRevealed();
     void onPanelHidden();
-    void onNotificationClick(String pkg, String tag, int id, int userId);
+    void onNotificationClick(String key);
     void onNotificationError(String pkg, String tag, int id,
             int uid, int initialPid, String message, int userId);
     void onClearAllNotifications(int userId);
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index d177410..a56fa36 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -117,6 +117,13 @@
     }
 
     /**
+     * Checks if given array is null or has zero elements.
+     */
+    public static <T> boolean isEmpty(T[] array) {
+        return array == null || array.length == 0;
+    }
+
+    /**
      * Checks that value is present as at least one of the elements of the array.
      * @param array the array to check in
      * @param value the value to check for
diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java
index 52281d9..34f62ba 100644
--- a/core/java/com/android/internal/util/AsyncChannel.java
+++ b/core/java/com/android/internal/util/AsyncChannel.java
@@ -450,6 +450,7 @@
     public void disconnect() {
         if ((mConnection != null) && (mSrcContext != null)) {
             mSrcContext.unbindService(mConnection);
+            mConnection = null;
         }
         try {
             // Send the DISCONNECTED, although it may not be received
@@ -463,10 +464,12 @@
         // Tell source we're disconnected.
         if (mSrcHandler != null) {
             replyDisconnected(STATUS_SUCCESSFUL);
+            mSrcHandler = null;
         }
         // Unlink only when bindService isn't used
         if (mConnection == null && mDstMessenger != null && mDeathMonitor!= null) {
             mDstMessenger.getBinder().unlinkToDeath(mDeathMonitor, 0);
+            mDeathMonitor = null;
         }
     }
 
diff --git a/core/java/com/android/internal/util/LegacyNotificationUtil.java b/core/java/com/android/internal/util/LegacyNotificationUtil.java
deleted file mode 100644
index 0394bbc..0000000
--- a/core/java/com/android/internal/util/LegacyNotificationUtil.java
+++ /dev/null
@@ -1,193 +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.util;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.drawable.AnimationDrawable;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
-import android.text.style.TextAppearanceSpan;
-import android.util.Log;
-import android.util.Pair;
-
-import java.util.Arrays;
-import java.util.WeakHashMap;
-
-/**
- * Helper class to process legacy (Holo) notifications to make them look like quantum notifications.
- *
- * @hide
- */
-public class LegacyNotificationUtil {
-
-    private static final String TAG = "LegacyNotificationUtil";
-
-    private static final Object sLock = new Object();
-    private static LegacyNotificationUtil sInstance;
-
-    private final ImageUtils mImageUtils = new ImageUtils();
-    private final WeakHashMap<Bitmap, Pair<Boolean, Integer>> mGrayscaleBitmapCache =
-            new WeakHashMap<Bitmap, Pair<Boolean, Integer>>();
-
-    public static LegacyNotificationUtil getInstance() {
-        synchronized (sLock) {
-            if (sInstance == null) {
-                sInstance = new LegacyNotificationUtil();
-            }
-            return sInstance;
-        }
-    }
-
-    /**
-     * Checks whether a bitmap is grayscale. Grayscale here means "very close to a perfect
-     * gray".
-     *
-     * @param bitmap The bitmap to test.
-     * @return Whether the bitmap is grayscale.
-     */
-    public boolean isGrayscale(Bitmap bitmap) {
-        synchronized (sLock) {
-            Pair<Boolean, Integer> cached = mGrayscaleBitmapCache.get(bitmap);
-            if (cached != null) {
-                if (cached.second == bitmap.getGenerationId()) {
-                    return cached.first;
-                }
-            }
-        }
-        boolean result;
-        int generationId;
-        synchronized (mImageUtils) {
-            result = mImageUtils.isGrayscale(bitmap);
-
-            // generationId and the check whether the Bitmap is grayscale can't be read atomically
-            // here. However, since the thread is in the process of posting the notification, we can
-            // assume that it doesn't modify the bitmap while we are checking the pixels.
-            generationId = bitmap.getGenerationId();
-        }
-        synchronized (sLock) {
-            mGrayscaleBitmapCache.put(bitmap, Pair.create(result, generationId));
-        }
-        return result;
-    }
-
-    /**
-     * Checks whether a drawable is grayscale. Grayscale here means "very close to a perfect
-     * gray".
-     *
-     * @param d The drawable to test.
-     * @return Whether the drawable is grayscale.
-     */
-    public boolean isGrayscale(Drawable d) {
-        if (d == null) {
-            return false;
-        } else if (d instanceof BitmapDrawable) {
-            BitmapDrawable bd = (BitmapDrawable) d;
-            return bd.getBitmap() != null && isGrayscale(bd.getBitmap());
-        } else if (d instanceof AnimationDrawable) {
-            AnimationDrawable ad = (AnimationDrawable) d;
-            int count = ad.getNumberOfFrames();
-            return count > 0 && isGrayscale(ad.getFrame(0));
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * Checks whether a drawable with a resoure id is grayscale. Grayscale here means "very close
-     * to a perfect gray".
-     *
-     * @param context The context to load the drawable from.
-     * @return Whether the drawable is grayscale.
-     */
-    public boolean isGrayscale(Context context, int drawableResId) {
-        if (drawableResId != 0) {
-            try {
-                return isGrayscale(context.getDrawable(drawableResId));
-            } catch (Resources.NotFoundException ex) {
-                Log.e(TAG, "Drawable not found: " + drawableResId);
-                return false;
-            }
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * Inverts all the grayscale colors set by {@link android.text.style.TextAppearanceSpan}s on
-     * the text.
-     *
-     * @param charSequence The text to process.
-     * @return The color inverted text.
-     */
-    public CharSequence invertCharSequenceColors(CharSequence charSequence) {
-        if (charSequence instanceof Spanned) {
-            Spanned ss = (Spanned) charSequence;
-            Object[] spans = ss.getSpans(0, ss.length(), Object.class);
-            SpannableStringBuilder builder = new SpannableStringBuilder(ss.toString());
-            for (Object span : spans) {
-                Object resultSpan = span;
-                if (span instanceof TextAppearanceSpan) {
-                    resultSpan = processTextAppearanceSpan((TextAppearanceSpan) span);
-                }
-                builder.setSpan(resultSpan, ss.getSpanStart(span), ss.getSpanEnd(span),
-                        ss.getSpanFlags(span));
-            }
-            return builder;
-        }
-        return charSequence;
-    }
-
-    private TextAppearanceSpan processTextAppearanceSpan(TextAppearanceSpan span) {
-        ColorStateList colorStateList = span.getTextColor();
-        if (colorStateList != null) {
-            int[] colors = colorStateList.getColors();
-            boolean changed = false;
-            for (int i = 0; i < colors.length; i++) {
-                if (ImageUtils.isGrayscale(colors[i])) {
-
-                    // Allocate a new array so we don't change the colors in the old color state
-                    // list.
-                    if (!changed) {
-                        colors = Arrays.copyOf(colors, colors.length);
-                    }
-                    colors[i] = processColor(colors[i]);
-                    changed = true;
-                }
-            }
-            if (changed) {
-                return new TextAppearanceSpan(
-                        span.getFamily(), span.getTextStyle(), span.getTextSize(),
-                        new ColorStateList(colorStateList.getStates(), colors),
-                        span.getLinkTextColor());
-            }
-        }
-        return span;
-    }
-
-    private int processColor(int color) {
-        return Color.argb(Color.alpha(color),
-                255 - Color.red(color),
-                255 - Color.green(color),
-                255 - Color.blue(color));
-    }
-}
diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
new file mode 100644
index 0000000..f38cbde
--- /dev/null
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.internal.util;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.drawable.AnimationDrawable;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.VectorDrawable;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.style.TextAppearanceSpan;
+import android.util.Log;
+import android.util.Pair;
+
+import java.util.Arrays;
+import java.util.WeakHashMap;
+
+/**
+ * Helper class to process legacy (Holo) notifications to make them look like quantum notifications.
+ *
+ * @hide
+ */
+public class NotificationColorUtil {
+
+    private static final String TAG = "NotificationColorUtil";
+
+    private static final Object sLock = new Object();
+    private static NotificationColorUtil sInstance;
+
+    private final ImageUtils mImageUtils = new ImageUtils();
+    private final WeakHashMap<Bitmap, Pair<Boolean, Integer>> mGrayscaleBitmapCache =
+            new WeakHashMap<Bitmap, Pair<Boolean, Integer>>();
+
+    public static NotificationColorUtil getInstance() {
+        synchronized (sLock) {
+            if (sInstance == null) {
+                sInstance = new NotificationColorUtil();
+            }
+            return sInstance;
+        }
+    }
+
+    /**
+     * Checks whether a bitmap is grayscale. Grayscale here means "very close to a perfect
+     * gray".
+     *
+     * @param bitmap The bitmap to test.
+     * @return Whether the bitmap is grayscale.
+     */
+    public boolean isGrayscale(Bitmap bitmap) {
+        synchronized (sLock) {
+            Pair<Boolean, Integer> cached = mGrayscaleBitmapCache.get(bitmap);
+            if (cached != null) {
+                if (cached.second == bitmap.getGenerationId()) {
+                    return cached.first;
+                }
+            }
+        }
+        boolean result;
+        int generationId;
+        synchronized (mImageUtils) {
+            result = mImageUtils.isGrayscale(bitmap);
+
+            // generationId and the check whether the Bitmap is grayscale can't be read atomically
+            // here. However, since the thread is in the process of posting the notification, we can
+            // assume that it doesn't modify the bitmap while we are checking the pixels.
+            generationId = bitmap.getGenerationId();
+        }
+        synchronized (sLock) {
+            mGrayscaleBitmapCache.put(bitmap, Pair.create(result, generationId));
+        }
+        return result;
+    }
+
+    /**
+     * Checks whether a drawable is grayscale. Grayscale here means "very close to a perfect
+     * gray".
+     *
+     * @param d The drawable to test.
+     * @return Whether the drawable is grayscale.
+     */
+    public boolean isGrayscale(Drawable d) {
+        if (d == null) {
+            return false;
+        } else if (d instanceof BitmapDrawable) {
+            BitmapDrawable bd = (BitmapDrawable) d;
+            return bd.getBitmap() != null && isGrayscale(bd.getBitmap());
+        } else if (d instanceof AnimationDrawable) {
+            AnimationDrawable ad = (AnimationDrawable) d;
+            int count = ad.getNumberOfFrames();
+            return count > 0 && isGrayscale(ad.getFrame(0));
+        } else if (d instanceof VectorDrawable) {
+            // We just assume you're doing the right thing if using vectors
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Checks whether a drawable with a resoure id is grayscale. Grayscale here means "very close
+     * to a perfect gray".
+     *
+     * @param context The context to load the drawable from.
+     * @return Whether the drawable is grayscale.
+     */
+    public boolean isGrayscale(Context context, int drawableResId) {
+        if (drawableResId != 0) {
+            try {
+                return isGrayscale(context.getDrawable(drawableResId));
+            } catch (Resources.NotFoundException ex) {
+                Log.e(TAG, "Drawable not found: " + drawableResId);
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Inverts all the grayscale colors set by {@link android.text.style.TextAppearanceSpan}s on
+     * the text.
+     *
+     * @param charSequence The text to process.
+     * @return The color inverted text.
+     */
+    public CharSequence invertCharSequenceColors(CharSequence charSequence) {
+        if (charSequence instanceof Spanned) {
+            Spanned ss = (Spanned) charSequence;
+            Object[] spans = ss.getSpans(0, ss.length(), Object.class);
+            SpannableStringBuilder builder = new SpannableStringBuilder(ss.toString());
+            for (Object span : spans) {
+                Object resultSpan = span;
+                if (span instanceof TextAppearanceSpan) {
+                    resultSpan = processTextAppearanceSpan((TextAppearanceSpan) span);
+                }
+                builder.setSpan(resultSpan, ss.getSpanStart(span), ss.getSpanEnd(span),
+                        ss.getSpanFlags(span));
+            }
+            return builder;
+        }
+        return charSequence;
+    }
+
+    private TextAppearanceSpan processTextAppearanceSpan(TextAppearanceSpan span) {
+        ColorStateList colorStateList = span.getTextColor();
+        if (colorStateList != null) {
+            int[] colors = colorStateList.getColors();
+            boolean changed = false;
+            for (int i = 0; i < colors.length; i++) {
+                if (ImageUtils.isGrayscale(colors[i])) {
+
+                    // Allocate a new array so we don't change the colors in the old color state
+                    // list.
+                    if (!changed) {
+                        colors = Arrays.copyOf(colors, colors.length);
+                    }
+                    colors[i] = processColor(colors[i]);
+                    changed = true;
+                }
+            }
+            if (changed) {
+                return new TextAppearanceSpan(
+                        span.getFamily(), span.getTextStyle(), span.getTextSize(),
+                        new ColorStateList(colorStateList.getStates(), colors),
+                        span.getLinkTextColor());
+            }
+        }
+        return span;
+    }
+
+    private int processColor(int color) {
+        return Color.argb(Color.alpha(color),
+                255 - Color.red(color),
+                255 - Color.green(color),
+                255 - Color.blue(color));
+    }
+}
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index a54b364..f6722a6 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -30,7 +30,7 @@
      * @return the non-null reference that was validated
      * @throws NullPointerException if {@code reference} is null
      */
-    public static <T> T checkNotNull(T reference) {
+    public static <T> T checkNotNull(final T reference) {
         if (reference == null) {
             throw new NullPointerException();
         }
@@ -47,7 +47,7 @@
      * @return the non-null reference that was validated
      * @throws NullPointerException if {@code reference} is null
      */
-    public static <T> T checkNotNull(T reference, Object errorMessage) {
+    public static <T> T checkNotNull(final T reference, final Object errorMessage) {
         if (reference == null) {
             throw new NullPointerException(String.valueOf(errorMessage));
         }
@@ -61,7 +61,7 @@
      * @param expression a boolean expression
      * @throws IllegalStateException if {@code expression} is false
      */
-    public static void checkState(boolean expression) {
+    public static void checkState(final boolean expression) {
         if (!expression) {
             throw new IllegalStateException();
         }
@@ -71,11 +71,178 @@
      * Check the requested flags, throwing if any requested flags are outside
      * the allowed set.
      */
-    public static void checkFlagsArgument(int requestedFlags, int allowedFlags) {
+    public static void checkFlagsArgument(final int requestedFlags, final int allowedFlags) {
         if ((requestedFlags & allowedFlags) != requestedFlags) {
             throw new IllegalArgumentException("Requested flags 0x"
                     + Integer.toHexString(requestedFlags) + ", but only 0x"
                     + Integer.toHexString(allowedFlags) + " are allowed");
         }
     }
+
+    /**
+     * Ensures that that the argument numeric value is non-negative.
+     *
+     * @param value a numeric int value
+     * @param errorMessage the exception message to use if the check fails
+     * @return the validated numeric value
+     * @throws IllegalArgumentException if {@code value} was negative
+     */
+    public static int checkArgumentNonnegative(final int value, final String errorMessage) {
+        if (value < 0) {
+            throw new IllegalArgumentException(errorMessage);
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that that the argument numeric value is non-negative.
+     *
+     * @param value a numeric long value
+     * @param errorMessage the exception message to use if the check fails
+     * @return the validated numeric value
+     * @throws IllegalArgumentException if {@code value} was negative
+     */
+    public static long checkArgumentNonnegative(final long value, final String errorMessage) {
+        if (value < 0) {
+            throw new IllegalArgumentException(errorMessage);
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that that the argument numeric value is positive.
+     *
+     * @param value a numeric int value
+     * @param errorMessage the exception message to use if the check fails
+     * @return the validated numeric value
+     * @throws IllegalArgumentException if {@code value} was not positive
+     */
+    public static int checkArgumentPositive(final int value, final String errorMessage) {
+        if (value <= 0) {
+            throw new IllegalArgumentException(errorMessage);
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that the argument floating point value is a finite number.
+     *
+     * <p>A finite number is defined to be both representable (that is, not NaN) and
+     * not infinite (that is neither positive or negative infinity).</p>
+     *
+     * @param value a floating point value
+     * @param valueName the name of the argument to use if the check fails
+     *
+     * @return the validated floating point value
+     *
+     * @throws IllegalArgumentException if {@code value} was not finite
+     */
+    public static float checkArgumentFinite(final float value, final String valueName) {
+        if (Float.isNaN(value)) {
+            throw new IllegalArgumentException(valueName + " must not be NaN");
+        } else if (Float.isInfinite(value)) {
+            throw new IllegalArgumentException(valueName + " must not be infinite");
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that the argument floating point value is within the inclusive range.
+     *
+     * <p>While this can be used to range check against +/- infinity, note that all NaN numbers
+     * will always be out of range.</p>
+     *
+     * @param value a floating point value
+     * @param lower the lower endpoint of the inclusive range
+     * @param upper the upper endpoint of the inclusive range
+     * @param valueName the name of the argument to use if the check fails
+     *
+     * @return the validated floating point value
+     *
+     * @throws IllegalArgumentException if {@code value} was not within the range
+     */
+    public static float checkArgumentInRange(float value, float lower, float upper,
+            String valueName) {
+        if (Float.isNaN(value)) {
+            throw new IllegalArgumentException(valueName + " must not be NaN");
+        } else if (value < lower) {
+            throw new IllegalArgumentException(
+                    String.format(
+                            "%s is out of range of [%f, %f] (too low)", valueName, lower, upper));
+        } else if (value > upper) {
+            throw new IllegalArgumentException(
+                    String.format(
+                            "%s is out of range of [%f, %f] (too high)", valueName, lower, upper));
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that the array is not {@code null}, and none if its elements are {@code null}.
+     *
+     * @param value an array of boxed objects
+     * @param valueName the name of the argument to use if the check fails
+     *
+     * @return the validated array
+     *
+     * @throws NullPointerException if the {@code value} or any of its elements were {@code null}
+     */
+    public static <T> T[] checkArrayElementsNotNull(final T[] value, final String valueName) {
+        if (value == null) {
+            throw new NullPointerException(valueName + " must not be null");
+        }
+
+        for (int i = 0; i < value.length; ++i) {
+            if (value[i] == null) {
+                throw new NullPointerException(
+                        String.format("%s[%d] must not be null", valueName, i));
+            }
+        }
+
+        return value;
+    }
+
+    /**
+     * Ensures that all elements in the argument floating point array are within the inclusive range
+     *
+     * <p>While this can be used to range check against +/- infinity, note that all NaN numbers
+     * will always be out of range.</p>
+     *
+     * @param value a floating point array of values
+     * @param lower the lower endpoint of the inclusive range
+     * @param upper the upper endpoint of the inclusive range
+     * @param valueName the name of the argument to use if the check fails
+     *
+     * @return the validated floating point value
+     *
+     * @throws IllegalArgumentException if any of the elements in {@code value} were out of range
+     * @throws NullPointerException if the {@code value} was {@code null}
+     */
+    public static float[] checkArrayElementsInRange(float[] value, float lower, float upper,
+            String valueName) {
+        checkNotNull(value, valueName + " must not be null");
+
+        for (int i = 0; i < value.length; ++i) {
+            float v = value[i];
+
+            if (Float.isNaN(v)) {
+                throw new IllegalArgumentException(valueName + "[" + i + "] must not be NaN");
+            } else if (v < lower) {
+                throw new IllegalArgumentException(
+                        String.format("%s[%d] is out of range of [%f, %f] (too low)",
+                                valueName, i, lower, upper));
+            } else if (v > upper) {
+                throw new IllegalArgumentException(
+                        String.format("%s[%d] is out of range of [%f, %f] (too high)",
+                                valueName, i, lower, upper));
+            }
+        }
+
+        return value;
+    }
 }
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index b380403..4b84941 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -46,6 +46,8 @@
     public static final int BASE_WIFI_MONITOR                                       = 0x00024000;
     public static final int BASE_WIFI_MANAGER                                       = 0x00025000;
     public static final int BASE_WIFI_CONTROLLER                                    = 0x00026000;
+    public static final int BASE_WIFI_SCANNER                                       = 0x00027000;
+    public static final int BASE_WIFI_SCANNER_SERVICE                               = 0x00027100;
     public static final int BASE_DHCP                                               = 0x00030000;
     public static final int BASE_DATA_CONNECTION                                    = 0x00040000;
     public static final int BASE_DATA_CONNECTION_AC                                 = 0x00041000;
@@ -53,5 +55,9 @@
     public static final int BASE_DNS_PINGER                                         = 0x00050000;
     public static final int BASE_NSD_MANAGER                                        = 0x00060000;
     public static final int BASE_NETWORK_STATE_TRACKER                              = 0x00070000;
+    public static final int BASE_CONNECTIVITY_SERVICE                               = 0x00080000;
+    public static final int BASE_NETWORK_AGENT                                      = 0x00081000;
+    public static final int BASE_NETWORK_MONITOR                                    = 0x00082000;
+    public static final int BASE_CONNECTIVITY_MANAGER                               = 0x00083000;
     //TODO: define all used protocols
 }
diff --git a/core/java/com/android/internal/util/VirtualRefBasePtr.java b/core/java/com/android/internal/util/VirtualRefBasePtr.java
new file mode 100644
index 0000000..0bd4d3a
--- /dev/null
+++ b/core/java/com/android/internal/util/VirtualRefBasePtr.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+/**
+ * Helper class that contains a strong reference to a VirtualRefBase native
+ * object. This will incStrong in the ctor, and decStrong in the finalizer
+ */
+public final class VirtualRefBasePtr {
+    private long mNativePtr;
+
+    public VirtualRefBasePtr(long ptr) {
+        mNativePtr = ptr;
+        nIncStrong(mNativePtr);
+    }
+
+    public long get() {
+        return mNativePtr;
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            nDecStrong(mNativePtr);
+            mNativePtr = 0;
+        } finally {
+            super.finalize();
+        }
+    }
+
+    private static native void nIncStrong(long ptr);
+    private static native void nDecStrong(long ptr);
+}
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index b35de93..5b59599 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -912,6 +912,15 @@
         }
     }
 
+    public static int readIntAttribute(XmlPullParser in, String name, int defaultValue) {
+        final String value = in.getAttributeValue(null, name);
+        try {
+            return Integer.parseInt(value);
+        } catch (NumberFormatException e) {
+            return defaultValue;
+        }
+    }
+
     public static int readIntAttribute(XmlPullParser in, String name) throws IOException {
         final String value = in.getAttributeValue(null, name);
         try {
diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl
index 90210ce..367b713 100644
--- a/core/java/com/android/internal/view/IInputMethodSession.aidl
+++ b/core/java/com/android/internal/view/IInputMethodSession.aidl
@@ -21,6 +21,7 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.CursorAnchorInfo;
 import android.view.inputmethod.ExtractedText;
 
 /**
@@ -47,4 +48,6 @@
     void toggleSoftInput(int showFlags, int hideFlags);
 
     void finishSession();
+
+    void updateCursorAnchorInfo(in CursorAnchorInfo cursorAnchorInfo);
 }
diff --git a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
new file mode 100644
index 0000000..aec2b7e
--- /dev/null
+++ b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.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 and
+ * limitations under the License.
+ */
+
+package com.android.internal.view.animation;
+
+import android.animation.TimeInterpolator;
+import android.util.TimeUtils;
+import android.view.Choreographer;
+
+/**
+ * Interpolator that builds a lookup table to use. This is a fallback for
+ * building a native interpolator from a TimeInterpolator that is not marked
+ * with {@link HasNativeInterpolator}
+ */
+@HasNativeInterpolator
+public class FallbackLUTInterpolator implements NativeInterpolatorFactory {
+
+    private final float mLut[];
+
+    /**
+     * Used to cache the float[] LUT for use across multiple native
+     * interpolator creation
+     */
+    public FallbackLUTInterpolator(TimeInterpolator interpolator, int duration) {
+        mLut = createLUT(interpolator, duration);
+    }
+
+    private static float[] createLUT(TimeInterpolator interpolator, int duration) {
+        long frameIntervalNanos = Choreographer.getInstance().getFrameIntervalNanos();
+        int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS);
+        int numAnimFrames = (int) Math.ceil(duration / animIntervalMs);
+        float values[] = new float[numAnimFrames];
+        float lastFrame = numAnimFrames - 1;
+        for (int i = 0; i < numAnimFrames; i++) {
+            float inValue = i / lastFrame;
+            values[i] = interpolator.getInterpolation(inValue);
+        }
+        return values;
+    }
+
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactoryHelper.createLutInterpolator(mLut);
+    }
+
+    /**
+     * Used to create a one-shot float[] LUT & native interpolator
+     */
+    public static long createNativeInterpolator(TimeInterpolator interpolator, int duration) {
+        float[] lut = createLUT(interpolator, duration);
+        return NativeInterpolatorFactoryHelper.createLutInterpolator(lut);
+    }
+}
diff --git a/core/java/com/android/internal/view/animation/HasNativeInterpolator.java b/core/java/com/android/internal/view/animation/HasNativeInterpolator.java
new file mode 100644
index 0000000..48ea4da
--- /dev/null
+++ b/core/java/com/android/internal/view/animation/HasNativeInterpolator.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 com.android.internal.view.animation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This is a class annotation that signals that it is safe to create
+ * a native interpolator counterpart via {@link NativeInterpolatorFactory}
+ *
+ * The idea here is to prevent subclasses of interpolators from being treated as a
+ * NativeInterpolatorFactory, and instead have them fall back to the LUT & LERP
+ * method like a custom interpolator.
+ *
+ * @hide
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface HasNativeInterpolator {
+}
diff --git a/core/java/com/android/internal/view/animation/NativeInterpolatorFactory.java b/core/java/com/android/internal/view/animation/NativeInterpolatorFactory.java
new file mode 100644
index 0000000..fcacd52
--- /dev/null
+++ b/core/java/com/android/internal/view/animation/NativeInterpolatorFactory.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view.animation;
+
+public interface NativeInterpolatorFactory {
+    long createNativeInterpolator();
+}
diff --git a/core/java/com/android/internal/view/animation/NativeInterpolatorFactoryHelper.java b/core/java/com/android/internal/view/animation/NativeInterpolatorFactoryHelper.java
new file mode 100644
index 0000000..7cd75f3
--- /dev/null
+++ b/core/java/com/android/internal/view/animation/NativeInterpolatorFactoryHelper.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view.animation;
+
+/**
+ * Static utility class for constructing native interpolators to keep the
+ * JNI simpler
+ */
+public final class NativeInterpolatorFactoryHelper {
+    private NativeInterpolatorFactoryHelper() {}
+
+    public static native long createAccelerateDecelerateInterpolator();
+    public static native long createAccelerateInterpolator(float factor);
+    public static native long createAnticipateInterpolator(float tension);
+    public static native long createAnticipateOvershootInterpolator(float tension);
+    public static native long createBounceInterpolator();
+    public static native long createCycleInterpolator(float cycles);
+    public static native long createDecelerateInterpolator(float factor);
+    public static native long createLinearInterpolator();
+    public static native long createOvershootInterpolator(float tension);
+    public static native long createLutInterpolator(float[] values);
+}
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index d664058..5a12893 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -53,6 +53,7 @@
     private final MenuAdapter mAdapter;
     private final boolean mOverflowOnly;
     private final int mPopupMaxWidth;
+    private final int mPopupStyleAttr;
 
     private View mAnchorView;
     private ListPopupWindow mPopup;
@@ -72,20 +73,21 @@
     private int mDropDownGravity = Gravity.NO_GRAVITY;
 
     public MenuPopupHelper(Context context, MenuBuilder menu) {
-        this(context, menu, null, false);
+        this(context, menu, null, false, com.android.internal.R.attr.popupMenuStyle);
     }
 
     public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView) {
-        this(context, menu, anchorView, false);
+        this(context, menu, anchorView, false, com.android.internal.R.attr.popupMenuStyle);
     }
 
-    public MenuPopupHelper(Context context, MenuBuilder menu,
-            View anchorView, boolean overflowOnly) {
+    public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView,
+            boolean overflowOnly, int popupStyleAttr) {
         mContext = context;
         mInflater = LayoutInflater.from(context);
         mMenu = menu;
         mAdapter = new MenuAdapter(mMenu);
         mOverflowOnly = overflowOnly;
+        mPopupStyleAttr = popupStyleAttr;
 
         final Resources res = context.getResources();
         mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
@@ -119,7 +121,7 @@
     }
 
     public boolean tryShow() {
-        mPopup = new ListPopupWindow(mContext, null, com.android.internal.R.attr.popupMenuStyle);
+        mPopup = new ListPopupWindow(mContext, null, mPopupStyleAttr);
         mPopup.setOnDismissListener(this);
         mPopup.setOnItemClickListener(this);
         mPopup.setAdapter(mAdapter);
@@ -272,7 +274,7 @@
     @Override
     public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
         if (subMenu.hasVisibleItems()) {
-            MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView, false);
+            MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView);
             subPopup.setCallback(mPresenterCallback);
 
             boolean preserveIconSpacing = false;
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index c9dff1a..19d58bf 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -16,18 +16,22 @@
 
 package com.android.internal.widget;
 
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.view.ViewGroup;
-import android.view.WindowInsets;
-import com.android.internal.app.WindowDecorActionBar;
-
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.graphics.Canvas;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.util.AttributeSet;
+import android.util.IntProperty;
+import android.util.Property;
 import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewPropertyAnimator;
+import android.view.WindowInsets;
+import android.widget.OverScroller;
 
 /**
  * Special layout for the containing of an overlay action bar (and its
@@ -38,7 +42,7 @@
     private static final String TAG = "ActionBarOverlayLayout";
 
     private int mActionBarHeight;
-    private WindowDecorActionBar mActionBar;
+    //private WindowDecorActionBar mActionBar;
     private int mWindowVisibility = View.VISIBLE;
 
     // The main UI elements that we handle the layout of.
@@ -54,6 +58,10 @@
     private boolean mIgnoreWindowContentOverlay;
 
     private boolean mOverlayMode;
+    private boolean mHasNonEmbeddedTabs;
+    private boolean mHideOnContentScroll;
+    private boolean mAnimatingForFling;
+    private int mHideOnContentScrollReference;
     private int mLastSystemUiVisibility;
     private final Rect mBaseContentInsets = new Rect();
     private final Rect mLastBaseContentInsets = new Rect();
@@ -62,6 +70,84 @@
     private final Rect mInnerInsets = new Rect();
     private final Rect mLastInnerInsets = new Rect();
 
+    private ActionBarVisibilityCallback mActionBarVisibilityCallback;
+
+    private final int ACTION_BAR_ANIMATE_DELAY = 600; // ms
+
+    private OverScroller mFlingEstimator;
+
+    private ViewPropertyAnimator mCurrentActionBarTopAnimator;
+    private ViewPropertyAnimator mCurrentActionBarBottomAnimator;
+
+    private final Animator.AnimatorListener mTopAnimatorListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mCurrentActionBarTopAnimator = null;
+            mAnimatingForFling = false;
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mCurrentActionBarTopAnimator = null;
+            mAnimatingForFling = false;
+        }
+    };
+
+    private final Animator.AnimatorListener mBottomAnimatorListener =
+            new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mCurrentActionBarBottomAnimator = null;
+            mAnimatingForFling = false;
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mCurrentActionBarBottomAnimator = null;
+            mAnimatingForFling = false;
+        }
+    };
+
+    private final Runnable mRemoveActionBarHideOffset = new Runnable() {
+        public void run() {
+            haltActionBarHideOffsetAnimations();
+            mCurrentActionBarTopAnimator = mActionBarTop.animate().translationY(0)
+                    .setListener(mTopAnimatorListener);
+            if (mActionBarBottom != null && mActionBarBottom.getVisibility() != GONE) {
+                mCurrentActionBarBottomAnimator = mActionBarBottom.animate().translationY(0)
+                        .setListener(mBottomAnimatorListener);
+            }
+        }
+    };
+
+    private final Runnable mAddActionBarHideOffset = new Runnable() {
+        public void run() {
+            haltActionBarHideOffsetAnimations();
+            mCurrentActionBarTopAnimator = mActionBarTop.animate()
+                    .translationY(-mActionBarTop.getHeight())
+                    .setListener(mTopAnimatorListener);
+            if (mActionBarBottom != null && mActionBarBottom.getVisibility() != GONE) {
+                mCurrentActionBarBottomAnimator = mActionBarBottom.animate()
+                        .translationY(mActionBarBottom.getHeight())
+                        .setListener(mBottomAnimatorListener);
+            }
+        }
+    };
+
+    public static final Property<ActionBarOverlayLayout, Integer> ACTION_BAR_HIDE_OFFSET =
+            new IntProperty<ActionBarOverlayLayout>("actionBarHideOffset") {
+
+                @Override
+                public void setValue(ActionBarOverlayLayout object, int value) {
+                    object.setActionBarHideOffset(value);
+                }
+
+                @Override
+                public Integer get(ActionBarOverlayLayout object) {
+                    return object.getActionBarHideOffset();
+                }
+            };
+
     static final int[] ATTRS = new int [] {
             com.android.internal.R.attr.actionBarSize,
             com.android.internal.R.attr.windowContentOverlay
@@ -86,14 +172,22 @@
 
         mIgnoreWindowContentOverlay = context.getApplicationInfo().targetSdkVersion <
                 Build.VERSION_CODES.KITKAT;
+
+        mFlingEstimator = new OverScroller(context);
     }
 
-    public void setActionBar(WindowDecorActionBar impl) {
-        mActionBar = impl;
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        haltActionBarHideOffsetAnimations();
+    }
+
+    public void setActionBarVisibilityCallback(ActionBarVisibilityCallback cb) {
+        mActionBarVisibilityCallback = cb;
         if (getWindowToken() != null) {
             // This is being initialized after being added to a window;
             // make sure to update all state now.
-            mActionBar.setWindowVisibility(mWindowVisibility);
+            mActionBarVisibilityCallback.onWindowVisibilityChanged(mWindowVisibility);
             if (mLastSystemUiVisibility != 0) {
                 int newVis = mLastSystemUiVisibility;
                 onWindowSystemUiVisibilityChanged(newVis);
@@ -114,6 +208,14 @@
                         Build.VERSION_CODES.KITKAT;
     }
 
+    public boolean isInOverlayMode() {
+        return mOverlayMode;
+    }
+
+    public void setHasNonEmbeddedTabs(boolean hasNonEmbeddedTabs) {
+        mHasNonEmbeddedTabs = hasNonEmbeddedTabs;
+    }
+
     public void setShowingForActionMode(boolean showing) {
         if (showing) {
             // Here's a fun hack: if the status bar is currently being hidden,
@@ -140,19 +242,18 @@
         pullChildren();
         final int diff = mLastSystemUiVisibility ^ visible;
         mLastSystemUiVisibility = visible;
-        final boolean barVisible = (visible&SYSTEM_UI_FLAG_FULLSCREEN) == 0;
-        final boolean wasVisible = mActionBar != null ? mActionBar.isSystemShowing() : true;
-        final boolean stable = (visible&SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
-        if (mActionBar != null) {
+        final boolean barVisible = (visible & SYSTEM_UI_FLAG_FULLSCREEN) == 0;
+        final boolean stable = (visible & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
+        if (mActionBarVisibilityCallback != null) {
             // We want the bar to be visible if it is not being hidden,
             // or the app has not turned on a stable UI mode (meaning they
             // are performing explicit layout around the action bar).
-            mActionBar.enableContentAnimations(!stable);
-            if (barVisible || !stable) mActionBar.showForSystem();
-            else mActionBar.hideForSystem();
+            mActionBarVisibilityCallback.enableContentAnimations(!stable);
+            if (barVisible || !stable) mActionBarVisibilityCallback.showForSystem();
+            else mActionBarVisibilityCallback.hideForSystem();
         }
-        if ((diff&SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
-            if (mActionBar != null) {
+        if ((diff & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
+            if (mActionBarVisibilityCallback != null) {
                 requestApplyInsets();
             }
         }
@@ -162,8 +263,8 @@
     protected void onWindowVisibilityChanged(int visibility) {
         super.onWindowVisibilityChanged(visibility);
         mWindowVisibility = visibility;
-        if (mActionBar != null) {
-            mActionBar.setWindowVisibility(visibility);
+        if (mActionBarVisibilityCallback != null) {
+            mActionBarVisibilityCallback.onWindowVisibilityChanged(visibility);
         }
     }
 
@@ -279,8 +380,8 @@
             // This is the standard space needed for the action bar.  For stable measurement,
             // we can't depend on the size currently reported by it -- this must remain constant.
             topInset = mActionBarHeight;
-            if (mActionBar != null && mActionBar.hasNonEmbeddedTabs()) {
-                View tabs = mActionBarTop.getTabContainer();
+            if (mHasNonEmbeddedTabs) {
+                final View tabs = mActionBarTop.getTabContainer();
                 if (tabs != null) {
                     // If tabs are not embedded, increase space on top to account for them.
                     topInset += mActionBarHeight;
@@ -395,16 +496,138 @@
         return false;
     }
 
+    @Override
+    public boolean onStartNestedScroll(View child, View target, int axes) {
+        if ((axes & SCROLL_AXIS_VERTICAL) == 0 || mActionBarTop.getVisibility() != VISIBLE) {
+            return false;
+        }
+        return mHideOnContentScroll;
+    }
+
+    @Override
+    public void onNestedScrollAccepted(View child, View target, int axes) {
+        super.onNestedScrollAccepted(child, target, axes);
+        mHideOnContentScrollReference = getActionBarHideOffset();
+        haltActionBarHideOffsetAnimations();
+        if (mActionBarVisibilityCallback != null) {
+            mActionBarVisibilityCallback.onContentScrollStarted();
+        }
+    }
+
+    @Override
+    public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
+            int dxUnconsumed, int dyUnconsumed) {
+        mHideOnContentScrollReference += dyConsumed;
+        setActionBarHideOffset(mHideOnContentScrollReference);
+    }
+
+    @Override
+    public void onStopNestedScroll(View target) {
+        super.onStopNestedScroll(target);
+        if (mHideOnContentScroll && !mAnimatingForFling) {
+            if (mHideOnContentScrollReference <= mActionBarTop.getHeight()) {
+                postRemoveActionBarHideOffset();
+            } else {
+                postAddActionBarHideOffset();
+            }
+        }
+        if (mActionBarVisibilityCallback != null) {
+            mActionBarVisibilityCallback.onContentScrollStopped();
+        }
+    }
+
+    @Override
+    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
+        if (!mHideOnContentScroll || !consumed) {
+            return false;
+        }
+        if (shouldHideActionBarOnFling(velocityX, velocityY)) {
+            addActionBarHideOffset();
+        } else {
+            removeActionBarHideOffset();
+        }
+        mAnimatingForFling = true;
+        return true;
+    }
+
     void pullChildren() {
         if (mContent == null) {
             mContent = findViewById(com.android.internal.R.id.content);
-            mActionBarTop = (ActionBarContainer)findViewById(
+            mActionBarTop = (ActionBarContainer) findViewById(
                     com.android.internal.R.id.action_bar_container);
             mActionBarView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
             mActionBarBottom = findViewById(com.android.internal.R.id.split_action_bar);
         }
     }
 
+    public void setHideOnContentScrollEnabled(boolean hideOnContentScroll) {
+        if (hideOnContentScroll != mHideOnContentScroll) {
+            mHideOnContentScroll = hideOnContentScroll;
+            if (!hideOnContentScroll) {
+                stopNestedScroll();
+                haltActionBarHideOffsetAnimations();
+                setActionBarHideOffset(0);
+            }
+        }
+    }
+
+    public boolean isHideOnContentScrollEnabled() {
+        return mHideOnContentScroll;
+    }
+
+    public int getActionBarHideOffset() {
+        return mActionBarTop != null ? -((int) mActionBarTop.getTranslationY()) : 0;
+    }
+
+    public void setActionBarHideOffset(int offset) {
+        haltActionBarHideOffsetAnimations();
+        final int topHeight = mActionBarTop.getHeight();
+        offset = Math.max(0, Math.min(offset, topHeight));
+        mActionBarTop.setTranslationY(-offset);
+        if (mActionBarBottom != null && mActionBarBottom.getVisibility() != GONE) {
+            // Match the hide offset proportionally for a split bar
+            final float fOffset = (float) offset / topHeight;
+            final int bOffset = (int) (mActionBarBottom.getHeight() * fOffset);
+            mActionBarBottom.setTranslationY(bOffset);
+        }
+    }
+
+    private void haltActionBarHideOffsetAnimations() {
+        removeCallbacks(mRemoveActionBarHideOffset);
+        removeCallbacks(mAddActionBarHideOffset);
+        if (mCurrentActionBarTopAnimator != null) {
+            mCurrentActionBarTopAnimator.cancel();
+        }
+        if (mCurrentActionBarBottomAnimator != null) {
+            mCurrentActionBarBottomAnimator.cancel();
+        }
+    }
+
+    private void postRemoveActionBarHideOffset() {
+        haltActionBarHideOffsetAnimations();
+        postDelayed(mRemoveActionBarHideOffset, ACTION_BAR_ANIMATE_DELAY);
+    }
+
+    private void postAddActionBarHideOffset() {
+        haltActionBarHideOffsetAnimations();
+        postDelayed(mAddActionBarHideOffset, ACTION_BAR_ANIMATE_DELAY);
+    }
+
+    private void removeActionBarHideOffset() {
+        haltActionBarHideOffsetAnimations();
+        mRemoveActionBarHideOffset.run();
+    }
+
+    private void addActionBarHideOffset() {
+        haltActionBarHideOffsetAnimations();
+        mAddActionBarHideOffset.run();
+    }
+
+    private boolean shouldHideActionBarOnFling(float velocityX, float velocityY) {
+        mFlingEstimator.fling(0, 0, 0, (int) velocityY, 0, 0, Integer.MIN_VALUE, Integer.MAX_VALUE);
+        final int finalY = mFlingEstimator.getFinalY();
+        return finalY > mActionBarTop.getHeight();
+    }
 
     public static class LayoutParams extends MarginLayoutParams {
         public LayoutParams(Context c, AttributeSet attrs) {
@@ -423,4 +646,13 @@
             super(source);
         }
     }
+
+    public interface ActionBarVisibilityCallback {
+        void onWindowVisibilityChanged(int visibility);
+        void showForSystem();
+        void hideForSystem();
+        void enableContentAnimations(boolean enable);
+        void onContentScrollStarted();
+        void onContentScrollStopped();
+    }
 }
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
index 467d42e..bcfa036 100644
--- a/core/java/com/android/internal/widget/SwipeDismissLayout.java
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -35,7 +35,7 @@
 public class SwipeDismissLayout extends FrameLayout {
     private static final String TAG = "SwipeDismissLayout";
 
-    private static final float TRANSLATION_MIN_ALPHA = 0.5f;
+    private static final float DISMISS_MIN_DRAG_WIDTH_RATIO = .4f;
 
     public interface OnDismissedListener {
         void onDismissed(SwipeDismissLayout layout);
@@ -77,6 +77,8 @@
     private OnDismissedListener mDismissedListener;
     private OnSwipeProgressChangedListener mProgressListener;
 
+    private float mLastX;
+
     public SwipeDismissLayout(Context context) {
         super(context);
         init(context);
@@ -95,7 +97,7 @@
     private void init(Context context) {
         ViewConfiguration vc = ViewConfiguration.get(getContext());
         mSlop = vc.getScaledTouchSlop();
-        mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * 16;
+        mMinFlingVelocity = vc.getScaledMinimumFlingVelocity();
         mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
         mAnimationTime = getContext().getResources().getInteger(
                 android.R.integer.config_shortAnimTime);
@@ -193,8 +195,8 @@
 
             case MotionEvent.ACTION_MOVE:
                 mVelocityTracker.addMovement(ev);
+                mLastX = ev.getRawX();
                 updateSwiping(ev);
-                updateDismiss(ev);
                 if (mSwiping) {
                     setProgress(ev.getRawX() - mDownX);
                     break;
@@ -242,7 +244,11 @@
         if (!mSwiping) {
             float deltaX = ev.getRawX() - mDownX;
             float deltaY = ev.getRawY() - mDownY;
-            mSwiping = deltaX > mSlop * 2 && Math.abs(deltaY) < mSlop * 2;
+            if ((deltaX * deltaX) + (deltaY * deltaY) > mSlop * mSlop) {
+                mSwiping = deltaX > mSlop * 2 && Math.abs(deltaY) < mSlop * 2;
+            } else {
+                mSwiping = false;
+            }
         }
     }
 
@@ -252,24 +258,15 @@
             mVelocityTracker.addMovement(ev);
             mVelocityTracker.computeCurrentVelocity(1000);
 
-            float velocityX = mVelocityTracker.getXVelocity();
-            float absVelocityX = Math.abs(velocityX);
-            float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
-
-            if (deltaX > getWidth() / 2) {
-                mDismissed = true;
-            } else if (absVelocityX >= mMinFlingVelocity
-                    && absVelocityX <= mMaxFlingVelocity
-                    && absVelocityY < absVelocityX / 2
-                    && velocityX > 0
-                    && deltaX > 0) {
+            if (deltaX > (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO) &&
+                    ev.getRawX() >= mLastX) {
                 mDismissed = true;
             }
         }
         // Check if the user tried to undo this.
         if (mDismissed && mSwiping) {
             // Check if the user's finger is actually back
-            if (deltaX < getWidth() / 2) {
+            if (deltaX < (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO)) {
                 mDismissed = false;
             }
         }
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 8796126..07597a0 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -92,6 +92,7 @@
 	android/graphics/BitmapFactory.cpp \
 	android/graphics/Camera.cpp \
 	android/graphics/Canvas.cpp \
+	android/graphics/CanvasProperty.cpp \
 	android/graphics/ColorFilter.cpp \
 	android/graphics/DrawFilter.cpp \
 	android/graphics/FontFamily.cpp \
@@ -141,6 +142,7 @@
 	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 \
@@ -154,7 +156,9 @@
 	android_content_res_Configuration.cpp \
 	android_animation_PropertyValuesHolder.cpp \
 	com_android_internal_net_NetworkStatsFactory.cpp \
-	com_android_internal_os_Zygote.cpp
+	com_android_internal_os_Zygote.cpp \
+	com_android_internal_util_VirtualRefBasePtr.cpp \
+	com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
 
 LOCAL_C_INCLUDES += \
 	$(JNI_H_INCLUDE) \
@@ -241,8 +245,6 @@
 # <bionic_tls.h> in com_google_android_gles_jni_GLImpl.cpp
 LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
 
-LOCAL_LDLIBS += -lpthread -ldl
-
 ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
 	LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
 endif
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index d2f8062..767439a 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -105,6 +105,7 @@
 extern int register_android_content_XmlBlock(JNIEnv* env);
 extern int register_android_emoji_EmojiFactory(JNIEnv* env);
 extern int register_android_graphics_Canvas(JNIEnv* env);
+extern int register_android_graphics_CanvasProperty(JNIEnv* env);
 extern int register_android_graphics_ColorFilter(JNIEnv* env);
 extern int register_android_graphics_DrawFilter(JNIEnv* env);
 extern int register_android_graphics_FontFamily(JNIEnv* env);
@@ -131,6 +132,7 @@
 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_com_android_internal_view_animation_NativeInterpolatorFactoryHelper(JNIEnv *env);
 extern int register_android_database_CursorWindow(JNIEnv* env);
 extern int register_android_database_SQLiteConnection(JNIEnv* env);
 extern int register_android_database_SQLiteGlobal(JNIEnv* env);
@@ -181,6 +183,7 @@
 extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
 extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
 extern int register_com_android_internal_os_Zygote(JNIEnv *env);
+extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
 
 static AndroidRuntime* gCurRuntime = NULL;
 
@@ -470,6 +473,7 @@
     char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX];
     char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-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];
@@ -623,6 +627,13 @@
         mOptions.add(opt);
     }
 
+    strcpy(backgroundgcOptsBuf, "-XX:BackgroundGC=");
+    property_get("dalvik.vm.backgroundgctype", backgroundgcOptsBuf+sizeof("-XX:BackgroundGC=")-1, "");
+    if (backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1] != '\0') {
+        opt.optionString = backgroundgcOptsBuf;
+        mOptions.add(opt);
+    }
+
     /*
      * Enable or disable dexopt features, such as bytecode verification and
      * calculation of register maps for precise GC.
@@ -1205,6 +1216,7 @@
     REG_JNI(register_android_view_SurfaceControl),
     REG_JNI(register_android_view_SurfaceSession),
     REG_JNI(register_android_view_TextureView),
+    REG_JNI(register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper),
     REG_JNI(register_com_google_android_gles_jni_EGLImpl),
     REG_JNI(register_com_google_android_gles_jni_GLImpl),
     REG_JNI(register_android_opengl_jni_EGL14),
@@ -1222,6 +1234,7 @@
     REG_JNI(register_android_graphics_Camera),
     REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor),
     REG_JNI(register_android_graphics_Canvas),
+    REG_JNI(register_android_graphics_CanvasProperty),
     REG_JNI(register_android_graphics_ColorFilter),
     REG_JNI(register_android_graphics_DrawFilter),
     REG_JNI(register_android_graphics_FontFamily),
@@ -1262,6 +1275,7 @@
     REG_JNI(register_android_os_MemoryFile),
     REG_JNI(register_com_android_internal_os_ZygoteInit),
     REG_JNI(register_com_android_internal_os_Zygote),
+    REG_JNI(register_com_android_internal_util_VirtualRefBasePtr),
     REG_JNI(register_android_hardware_Camera),
     REG_JNI(register_android_hardware_camera2_CameraMetadata),
     REG_JNI(register_android_hardware_SensorManager),
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index e0fa9ba4..0328517 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -1,838 +1,838 @@
-#include "SkBitmap.h"

-#include "SkPixelRef.h"

-#include "SkImageEncoder.h"

-#include "SkColorPriv.h"

-#include "GraphicsJNI.h"

-#include "SkDither.h"

-#include "SkUnPreMultiply.h"

-#include "SkStream.h"

-

-#include <binder/Parcel.h>

-#include "android_os_Parcel.h"

-#include "android_util_Binder.h"

-#include "android_nio_utils.h"

-#include "CreateJavaOutputStreamAdaptor.h"

-

-#include <jni.h>

-

-#include <Caches.h>

-

-#if 0

-    #define TRACE_BITMAP(code)  code

-#else

-    #define TRACE_BITMAP(code)

-#endif

-

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

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

-// is basically like setPixels

-

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

-                              int x, int y);

-

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

-                          int, int) {

-    SkPMColor* d = (SkPMColor*)dst;

-

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

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

-    }

-}

-

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

-                          int, int) {

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

-    if (SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER) {

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

-        return;

-    }

-

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

-    SkPMColor* d = (SkPMColor*)dst;

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

-        SkColor c = *src++;

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

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

-    }

-}

-

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

-                           int x, int y) {

-    uint16_t* d = (uint16_t*)dst;

-

-    DITHER_565_SCAN(y);

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

-        SkColor c = *src++;

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

-                                DITHER_VALUE(x));

-    }

-}

-

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

-                            int x, int y) {

-    SkPMColor16* d = (SkPMColor16*)dst;

-

-    DITHER_4444_SCAN(y);

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

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

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

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

-    }

-}

-

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

-                            int x, int y) {

-    SkPMColor16* d = (SkPMColor16*)dst;

-

-    DITHER_4444_SCAN(y);

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

-        SkColor c = *src++;

-

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

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

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

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

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

-    }

-}

-

-// can return NULL

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

-    switch (config) {

-        case SkBitmap::kARGB_8888_Config:

-            return isPremultiplied ? FromColor_D32 : FromColor_D32_Raw;

-        case SkBitmap::kARGB_4444_Config:

-            return isPremultiplied ? FromColor_D4444 : FromColor_D4444_Raw;

-        case SkBitmap::kRGB_565_Config:

-            return FromColor_D565;

-        default:

-            break;

-    }

-    return NULL;

-}

-

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

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

-        const SkBitmap& dstBitmap, bool isPremultiplied) {

-    SkAutoLockPixels alp(dstBitmap);

-    void* dst = dstBitmap.getPixels();

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

-

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

-        return false;

-    }

-

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

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

-

-    // reset to to actual choice from caller

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

-    // now copy/convert each scanline

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

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

-        src += srcStride;

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

-    }

-

-    dstBitmap.notifyPixelsChanged();

-

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

-                                 JNI_ABORT);

-    return true;

-}

-

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

-

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

-                            SkColorTable*);

-

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

-                              SkColorTable*) {

-    SkASSERT(width > 0);

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

-    do {

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

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

-}

-

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

-                              SkColorTable*) {

-    SkASSERT(width > 0);

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

-    do {

-        SkPMColor c = *s++;

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

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

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

-}

-

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

-                               SkColorTable*) {

-    SkASSERT(width > 0);

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

-    do {

-        SkPMColor c = *s++;

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

-                               SkGetPackedB32(c));

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

-}

-

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

-                                SkColorTable*) {

-    SkASSERT(width > 0);

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

-    do {

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

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

-}

-

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

-                                SkColorTable*) {

-    SkASSERT(width > 0);

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

-    do {

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

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

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

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

-}

-

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

-                                 SkColorTable*) {

-    SkASSERT(width > 0);

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

-    do {

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

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

-                               SkGetPackedB32(c));

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

-}

-

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

-                         SkColorTable*) {

-    SkASSERT(width > 0);

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

-    do {

-        uint16_t c = *s++;

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

-                                SkPacked16ToB32(c));

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

-}

-

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

-                              SkColorTable* ctable) {

-    SkASSERT(width > 0);

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

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

-    do {

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

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

-    ctable->unlockColors();

-}

-

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

-                              SkColorTable* ctable) {

-    SkASSERT(width > 0);

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

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

-    do {

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

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

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

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

-    ctable->unlockColors();

-}

-

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

-                               SkColorTable* ctable) {

-    SkASSERT(width > 0);

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

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

-    do {

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

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

-                               SkGetPackedB32(c));

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

-    ctable->unlockColors();

-}

-

-// can return NULL

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

-    switch (src.config()) {

-        case SkBitmap::kARGB_8888_Config:

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

-            return isPremultiplied ? ToColor_S32_Alpha : ToColor_S32_Raw;

-        case SkBitmap::kARGB_4444_Config:

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

-            return isPremultiplied ? ToColor_S4444_Alpha : ToColor_S4444_Raw;

-        case SkBitmap::kRGB_565_Config:

-            return ToColor_S565;

-        case SkBitmap::kIndex8_Config:

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

-                return NULL;

-            }

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

-            return isPremultiplied ? ToColor_SI8_Raw : ToColor_SI8_Alpha;

-        default:

-            break;

-    }

-    return NULL;

-}

-

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

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

-

-static int getPremulBitmapCreateFlags(bool isMutable) {

-    int flags = GraphicsJNI::kBitmapCreateFlag_Premultiplied;

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

-    return flags;

-}

-

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

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

-                              jint configHandle, jboolean isMutable) {

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

-    if (NULL != jColors) {

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

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

-            doThrowAIOOBE(env);

-            return NULL;

-        }

-    }

-

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

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

-        config = SkBitmap::kARGB_8888_Config;

-    }

-

-    SkBitmap bitmap;

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

-

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

-    if (NULL == buff) {

-        return NULL;

-    }

-

-    if (jColors != NULL) {

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

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

-    }

-

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

-            getPremulBitmapCreateFlags(isMutable), NULL, NULL);

-}

-

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

-                           jint dstConfigHandle, jboolean isMutable) {

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

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

-    SkBitmap            result;

-    JavaPixelAllocator  allocator(env);

-

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

-    }

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

-            getPremulBitmapCreateFlags(isMutable), NULL, NULL);

-}

-

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

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

-#ifdef USE_OPENGL_RENDERER

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

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

-        return;

-    }

-#endif // USE_OPENGL_RENDERER

-    delete bitmap;

-}

-

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

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

-#ifdef USE_OPENGL_RENDERER

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

-        bool result;

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

-        return result ? JNI_TRUE : JNI_FALSE;

-    }

-#endif // USE_OPENGL_RENDERER

-    bitmap->setPixels(NULL, NULL);

-    return JNI_TRUE;

-}

-

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

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

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

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

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

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

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

-        return;

-    }

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

-    SkSafeRef(ref);

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

-    bitmap->setPixelRef(ref);

-

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

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

-    // and config) has changed.

-    ref->notifyPixelsChanged();

-    SkSafeUnref(ref);

-}

-

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

-enum JavaEncodeFormat {

-    kJPEG_JavaEncodeFormat = 0,

-    kPNG_JavaEncodeFormat = 1,

-    kWEBP_JavaEncodeFormat = 2

-};

-

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

-                                jint format, jint quality,

-                                jobject jstream, jbyteArray jstorage) {

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

-    SkImageEncoder::Type fm;

-

-    switch (format) {

-    case kJPEG_JavaEncodeFormat:

-        fm = SkImageEncoder::kJPEG_Type;

-        break;

-    case kPNG_JavaEncodeFormat:

-        fm = SkImageEncoder::kPNG_Type;

-        break;

-    case kWEBP_JavaEncodeFormat:

-        fm = SkImageEncoder::kWEBP_Type;

-        break;

-    default:

-        return JNI_FALSE;

-    }

-

-    bool success = false;

-    if (NULL != bitmap) {

-        SkAutoLockPixels alp(*bitmap);

-

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

-            return JNI_FALSE;

-        }

-

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

-        if (NULL == strm) {

-            return JNI_FALSE;

-        }

-

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

-        if (NULL != encoder) {

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

-            delete encoder;

-        }

-        delete strm;

-    }

-    return success ? JNI_TRUE : JNI_FALSE;

-}

-

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

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

-    bitmap->eraseColor(color);

-}

-

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

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

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

-}

-

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

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

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

-}

-

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

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

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

-}

-

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

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

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

-}

-

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

-                                            jboolean hasAlpha, jboolean isPremul) {

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

-    if (!hasAlpha) {

-        bitmap->setAlphaType(kOpaque_SkAlphaType);

-    } else if (isPremul) {

-        bitmap->setAlphaType(kPremul_SkAlphaType);

-    } else {

-        bitmap->setAlphaType(kUnpremul_SkAlphaType);

-    }

-}

-

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

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

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

-}

-

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

-                                jboolean hasMipMap) {

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

-    bitmap->setHasHardwareMipMap(hasMipMap);

-}

-

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

-

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

-    if (parcel == NULL) {

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

-        return NULL;

-    }

-

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

-

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

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

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

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

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

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

-

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

-            SkBitmap::kRGB_565_Config != config &&

-            SkBitmap::kARGB_4444_Config != config &&

-            SkBitmap::kIndex8_Config != config &&

-            SkBitmap::kA8_Config != config) {

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

-        return NULL;

-    }

-

-    SkBitmap* bitmap = new SkBitmap;

-

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

-

-    SkColorTable* ctable = NULL;

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

-        int count = p->readInt32();

-        if (count > 0) {

-            size_t size = count * sizeof(SkPMColor);

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

-            ctable = new SkColorTable(src, count);

-        }

-    }

-

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

-    if (NULL == buffer) {

-        SkSafeUnref(ctable);

-        delete bitmap;

-        return NULL;

-    }

-

-    SkSafeUnref(ctable);

-

-    size_t size = bitmap->getSize();

-

-    android::Parcel::ReadableBlob blob;

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

-    if (status) {

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

-        delete bitmap;

-        return NULL;

-    }

-

-    bitmap->lockPixels();

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

-    bitmap->unlockPixels();

-

-    blob.release();

-

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

-            NULL, NULL, density);

-}

-

-static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,

-                                     jlong bitmapHandle,

-                                     jboolean isMutable, jint density,

-                                     jobject parcel) {

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

-    if (parcel == NULL) {

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

-        return JNI_FALSE;

-    }

-

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

-

-    p->writeInt32(isMutable);

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

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

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

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

-    p->writeInt32(density);

-

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

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

-        if (ctable != NULL) {

-            int count = ctable->count();

-            p->writeInt32(count);

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

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

-            ctable->unlockColors();

-        } else {

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

-        }

-    }

-

-    size_t size = bitmap->getSize();

-

-    android::Parcel::WritableBlob blob;

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

-    if (status) {

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

-        return JNI_FALSE;

-    }

-

-    bitmap->lockPixels();

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

-    if (pSrc == NULL) {

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

-    } else {

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

-    }

-    bitmap->unlockPixels();

-

-    blob.release();

-    return JNI_TRUE;

-}

-

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

-                                   jlong srcHandle, jlong paintHandle,

-                                   jintArray offsetXY) {

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

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

-    SkIPoint  offset;

-    SkBitmap* dst = new SkBitmap;

-    JavaPixelAllocator allocator(env);

-

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

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

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

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

-        delete dst;

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

-        return NULL;

-    }

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

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

-        array[0] = offset.fX;

-        array[1] = offset.fY;

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

-    }

-

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

-            getPremulBitmapCreateFlags(true), NULL, NULL);

-}

-

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

-

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

-        jint x, jint y, jboolean isPremultiplied) {

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

-    SkAutoLockPixels alp(*bitmap);

-

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

-    if (NULL == proc) {

-        return 0;

-    }

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

-    if (NULL == src) {

-        return 0;

-    }

-

-    SkColor dst[1];

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

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

-}

-

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

-        jintArray pixelArray, jint offset, jint stride,

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

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

-    SkAutoLockPixels alp(*bitmap);

-

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

-    if (NULL == proc) {

-        return;

-    }

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

-    if (NULL == src) {

-        return;

-    }

-

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

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

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

-    while (--height >= 0) {

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

-        d += stride;

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

-    }

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

-}

-

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

-

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

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

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

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

-    SkAutoLockPixels alp(*bitmap);

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

-        return;

-    }

-

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

-    if (NULL == proc) {

-        return;

-    }

-

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

-    bitmap->notifyPixelsChanged();

-}

-

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

-        jintArray pixelArray, jint offset, jint stride,

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

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

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

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

-}

-

-static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,

-                                      jlong bitmapHandle, jobject jbuffer) {

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

-    SkAutoLockPixels alp(*bitmap);

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

-

-    if (NULL != src) {

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

-

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

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

-    }

-}

-

-static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,

-                                        jlong bitmapHandle, jobject jbuffer) {

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

-    SkAutoLockPixels alp(*bitmap);

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

-

-    if (NULL != dst) {

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

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

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

-        bitmap->notifyPixelsChanged();

-    }

-}

-

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

-                              jlong bm1Handle) {

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

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

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

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

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

-        return JNI_FALSE;

-    }

-

-    SkAutoLockPixels alp0(*bm0);

-    SkAutoLockPixels alp1(*bm1);

-

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

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

-        return JNI_FALSE;

-    }

-

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

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

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

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

-            return JNI_FALSE;

-        }

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

-            return JNI_FALSE;

-        }

-

-        SkAutoLockColors alc0(ct0);

-        SkAutoLockColors alc1(ct1);

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

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

-            return JNI_FALSE;

-        }

-    }

-

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

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

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

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

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

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

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

-            return JNI_FALSE;

-        }

-    }

-    return JNI_TRUE;

-}

-

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

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

-    bitmap->lockPixels();

-    bitmap->unlockPixels();

-}

-

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

-

-#include <android_runtime/AndroidRuntime.h>

-

-static JNINativeMethod gBitmapMethods[] = {

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

-        (void*)Bitmap_creator },

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

-        (void*)Bitmap_copy },

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

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

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

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

-        (void*)Bitmap_compress },

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

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

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

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

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

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

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

-    {   "nativeCreateFromParcel",

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

-        (void*)Bitmap_createFromParcel },

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

-        (void*)Bitmap_writeToParcel },

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

-        (void*)Bitmap_extractAlpha },

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

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

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

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

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

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

-                                            (void*)Bitmap_copyPixelsToBuffer },

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

-                                            (void*)Bitmap_copyPixelsFromBuffer },

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

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

-};

-

-#define kClassPathName  "android/graphics/Bitmap"

-

-int register_android_graphics_Bitmap(JNIEnv* env)

-{

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

-                                gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods));

-}

+        return NULL;
+    }
+    return GraphicsJNI::createBitmap(env, new SkBitmap(result), allocator.getStorageObj(),
+            getPremulBitmapCreateFlags(isMutable), NULL, NULL);
+}
+
+static void Bitmap_destructor(JNIEnv* env, jobject, jlong bitmapHandle) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+#ifdef USE_OPENGL_RENDERER
+    if (android::uirenderer::Caches::hasInstance()) {
+        android::uirenderer::Caches::getInstance().resourceCache.destructor(bitmap);
+        return;
+    }
+#endif // USE_OPENGL_RENDERER
+    delete bitmap;
+}
+
+static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+#ifdef USE_OPENGL_RENDERER
+    if (android::uirenderer::Caches::hasInstance()) {
+        bool result;
+        result = android::uirenderer::Caches::getInstance().resourceCache.recycle(bitmap);
+        return result ? JNI_TRUE : JNI_FALSE;
+    }
+#endif // USE_OPENGL_RENDERER
+    bitmap->setPixels(NULL, NULL);
+    return JNI_TRUE;
+}
+
+static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
+        jint width, jint height, jint configHandle, jint allocSize) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle);
+    if (width * height * SkBitmap::ComputeBytesPerPixel(config) > allocSize) {
+        // done in native as there's no way to get BytesPerPixel in Java
+        doThrowIAE(env, "Bitmap not large enough to support new configuration");
+        return;
+    }
+    SkPixelRef* ref = bitmap->pixelRef();
+    SkSafeRef(ref);
+    bitmap->setConfig(config, width, height);
+    bitmap->setPixelRef(ref);
+
+    // notifyPixelsChanged will increment the generation ID even though the actual pixel data
+    // hasn't been touched. This signals the renderer that the bitmap (including width, height,
+    // and config) has changed.
+    ref->notifyPixelsChanged();
+    SkSafeUnref(ref);
+}
+
+// These must match the int values in Bitmap.java
+enum JavaEncodeFormat {
+    kJPEG_JavaEncodeFormat = 0,
+    kPNG_JavaEncodeFormat = 1,
+    kWEBP_JavaEncodeFormat = 2
+};
+
+static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
+                                jint format, jint quality,
+                                jobject jstream, jbyteArray jstorage) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    SkImageEncoder::Type fm;
+
+    switch (format) {
+    case kJPEG_JavaEncodeFormat:
+        fm = SkImageEncoder::kJPEG_Type;
+        break;
+    case kPNG_JavaEncodeFormat:
+        fm = SkImageEncoder::kPNG_Type;
+        break;
+    case kWEBP_JavaEncodeFormat:
+        fm = SkImageEncoder::kWEBP_Type;
+        break;
+    default:
+        return JNI_FALSE;
+    }
+
+    bool success = false;
+    if (NULL != bitmap) {
+        SkAutoLockPixels alp(*bitmap);
+
+        if (NULL == bitmap->getPixels()) {
+            return JNI_FALSE;
+        }
+
+        SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
+        if (NULL == strm) {
+            return JNI_FALSE;
+        }
+
+        SkImageEncoder* encoder = SkImageEncoder::Create(fm);
+        if (NULL != encoder) {
+            success = encoder->encodeStream(strm, *bitmap, quality);
+            delete encoder;
+        }
+        delete strm;
+    }
+    return success ? JNI_TRUE : JNI_FALSE;
+}
+
+static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    bitmap->eraseColor(color);
+}
+
+static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    return static_cast<jint>(bitmap->rowBytes());
+}
+
+static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    return static_cast<jint>(bitmap->config());
+}
+
+static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    return static_cast<jint>(bitmap->getGenerationID());
+}
+
+static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    return !bitmap->isOpaque() ? JNI_TRUE : JNI_FALSE;
+}
+
+static void Bitmap_setAlphaAndPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
+                                            jboolean hasAlpha, jboolean isPremul) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    if (!hasAlpha) {
+        bitmap->setAlphaType(kOpaque_SkAlphaType);
+    } else if (isPremul) {
+        bitmap->setAlphaType(kPremul_SkAlphaType);
+    } else {
+        bitmap->setAlphaType(kUnpremul_SkAlphaType);
+    }
+}
+
+static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE;
+}
+
+static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
+                                jboolean hasMipMap) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    bitmap->setHasHardwareMipMap(hasMipMap);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
+    if (parcel == NULL) {
+        SkDebugf("-------- unparcel parcel is NULL\n");
+        return NULL;
+    }
+
+    android::Parcel* p = android::parcelForJavaObject(env, parcel);
+
+    const bool              isMutable = p->readInt32() != 0;
+    const SkBitmap::Config  config = (SkBitmap::Config)p->readInt32();
+    const int               width = p->readInt32();
+    const int               height = p->readInt32();
+    const int               rowBytes = p->readInt32();
+    const int               density = p->readInt32();
+
+    if (SkBitmap::kARGB_8888_Config != config &&
+            SkBitmap::kRGB_565_Config != config &&
+            SkBitmap::kARGB_4444_Config != config &&
+            SkBitmap::kIndex8_Config != config &&
+            SkBitmap::kA8_Config != config) {
+        SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config);
+        return NULL;
+    }
+
+    SkBitmap* bitmap = new SkBitmap;
+
+    bitmap->setConfig(config, width, height, rowBytes);
+
+    SkColorTable* ctable = NULL;
+    if (config == SkBitmap::kIndex8_Config) {
+        int count = p->readInt32();
+        if (count > 0) {
+            size_t size = count * sizeof(SkPMColor);
+            const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
+            ctable = new SkColorTable(src, count);
+        }
+    }
+
+    jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);
+    if (NULL == buffer) {
+        SkSafeUnref(ctable);
+        delete bitmap;
+        return NULL;
+    }
+
+    SkSafeUnref(ctable);
+
+    size_t size = bitmap->getSize();
+
+    android::Parcel::ReadableBlob blob;
+    android::status_t status = p->readBlob(size, &blob);
+    if (status) {
+        doThrowRE(env, "Could not read bitmap from parcel blob.");
+        delete bitmap;
+        return NULL;
+    }
+
+    bitmap->lockPixels();
+    memcpy(bitmap->getPixels(), blob.data(), size);
+    bitmap->unlockPixels();
+
+    blob.release();
+
+    return GraphicsJNI::createBitmap(env, bitmap, buffer, getPremulBitmapCreateFlags(isMutable),
+            NULL, NULL, density);
+}
+
+static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
+                                     jlong bitmapHandle,
+                                     jboolean isMutable, jint density,
+                                     jobject parcel) {
+    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    if (parcel == NULL) {
+        SkDebugf("------- writeToParcel null parcel\n");
+        return JNI_FALSE;
+    }
+
+    android::Parcel* p = android::parcelForJavaObject(env, parcel);
+
+    p->writeInt32(isMutable);
+    p->writeInt32(bitmap->config());
+    p->writeInt32(bitmap->width());
+    p->writeInt32(bitmap->height());
+    p->writeInt32(bitmap->rowBytes());
+    p->writeInt32(density);
+
+    if (bitmap->config() == SkBitmap::kIndex8_Config) {
+        SkColorTable* ctable = bitmap->getColorTable();
+        if (ctable != NULL) {
+            int count = ctable->count();
+            p->writeInt32(count);
+            memcpy(p->writeInplace(count * sizeof(SkPMColor)),
+                   ctable->lockColors(), count * sizeof(SkPMColor));
+            ctable->unlockColors();
+        } else {
+            p->writeInt32(0);   // indicate no ctable
+        }
+    }
+
+    size_t size = bitmap->getSize();
+
+    android::Parcel::WritableBlob blob;
+    android::status_t status = p->writeBlob(size, &blob);
+    if (status) {
+        doThrowRE(env, "Could not write bitmap to parcel blob.");
+        return JNI_FALSE;
+    }
+
+    bitmap->lockPixels();
+    const void* pSrc =  bitmap->getPixels();
+    if (pSrc == NULL) {
+        memset(blob.data(), 0, size);
+    } else {
+        memcpy(blob.data(), pSrc, size);
+    }
+    bitmap->unlockPixels();
+
+    blob.release();
+    return JNI_TRUE;
+}
+
+static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
+                                   jlong srcHandle, jlong paintHandle,
+                                   jintArray offsetXY) {
+    const SkBitmap* src = reinterpret_cast<SkBitmap*>(srcHandle);
+    const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+    SkIPoint  offset;
+    SkBitmap* dst = new SkBitmap;
+    JavaPixelAllocator allocator(env);
+
+    src->extractAlpha(dst, paint, &allocator, &offset);
+    // If Skia can't allocate pixels for destination bitmap, it resets
+    // it, that is set its pixels buffer to NULL, and zero width and height.
+    if (dst->getPixels() == NULL && src->getPixels() != NULL) {
+        delete dst;
+        doThrowOOME(env, "failed to allocate pixels for alpha");
+        return NULL;
+    }
+    if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
+        int* array = env->GetIntArrayElements(offsetXY, NULL);
+        array[0] = offset.fX;
+        array[1] = offset.fY;
+        env->ReleaseIntArrayElements(offsetXY, array, 0);
+    }
+
+    return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(),
+            getPremulBitmapCreateFlags(true), NULL, NULL);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
+        jint x, jint y, jboolean isPremultiplied) {
+    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    SkAutoLockPixels alp(*bitmap);
+
+    ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);
+    if (NULL == proc) {
+        return 0;
+    }
+    const void* src = bitmap->getAddr(x, y);
+    if (NULL == src) {
+        return 0;
+    }
+
+    SkColor dst[1];
+    proc(dst, src, 1, bitmap->getColorTable());
+    return static_cast<jint>(dst[0]);
+}
+
+static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
+        jintArray pixelArray, jint offset, jint stride,
+        jint x, jint y, jint width, jint height, jboolean isPremultiplied) {
+    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    SkAutoLockPixels alp(*bitmap);
+
+    ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);
+    if (NULL == proc) {
+        return;
+    }
+    const void* src = bitmap->getAddr(x, y);
+    if (NULL == src) {
+        return;
+    }
+
+    SkColorTable* ctable = bitmap->getColorTable();
+    jint* dst = env->GetIntArrayElements(pixelArray, NULL);
+    SkColor* d = (SkColor*)dst + offset;
+    while (--height >= 0) {
+        proc(d, src, width, ctable);
+        d += stride;
+        src = (void*)((const char*)src + bitmap->rowBytes());
+    }
+    env->ReleaseIntArrayElements(pixelArray, dst, 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
+        jint x, jint y, jint colorHandle, jboolean isPremultiplied) {
+    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    SkColor color = static_cast<SkColor>(colorHandle);
+    SkAutoLockPixels alp(*bitmap);
+    if (NULL == bitmap->getPixels()) {
+        return;
+    }
+
+    FromColorProc proc = ChooseFromColorProc(bitmap->config(), isPremultiplied);
+    if (NULL == proc) {
+        return;
+    }
+
+    proc(bitmap->getAddr(x, y), &color, 1, x, y);
+    bitmap->notifyPixelsChanged();
+}
+
+static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
+        jintArray pixelArray, jint offset, jint stride,
+        jint x, jint y, jint width, jint height, jboolean isPremultiplied) {
+    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
+            x, y, width, height, *bitmap, isPremultiplied);
+}
+
+static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
+                                      jlong bitmapHandle, jobject jbuffer) {
+    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    SkAutoLockPixels alp(*bitmap);
+    const void* src = bitmap->getPixels();
+
+    if (NULL != src) {
+        android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
+
+        // the java side has already checked that buffer is large enough
+        memcpy(abp.pointer(), src, bitmap->getSize());
+    }
+}
+
+static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
+                                        jlong bitmapHandle, jobject jbuffer) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    SkAutoLockPixels alp(*bitmap);
+    void* dst = bitmap->getPixels();
+
+    if (NULL != dst) {
+        android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
+        // the java side has already checked that buffer is large enough
+        memcpy(dst, abp.pointer(), bitmap->getSize());
+        bitmap->notifyPixelsChanged();
+    }
+}
+
+static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle,
+                              jlong bm1Handle) {
+    const SkBitmap* bm0 = reinterpret_cast<SkBitmap*>(bm0Handle);
+    const SkBitmap* bm1 = reinterpret_cast<SkBitmap*>(bm1Handle);
+    if (bm0->width() != bm1->width() ||
+        bm0->height() != bm1->height() ||
+        bm0->config() != bm1->config()) {
+        return JNI_FALSE;
+    }
+
+    SkAutoLockPixels alp0(*bm0);
+    SkAutoLockPixels alp1(*bm1);
+
+    // if we can't load the pixels, return false
+    if (NULL == bm0->getPixels() || NULL == bm1->getPixels()) {
+        return JNI_FALSE;
+    }
+
+    if (bm0->config() == SkBitmap::kIndex8_Config) {
+        SkColorTable* ct0 = bm0->getColorTable();
+        SkColorTable* ct1 = bm1->getColorTable();
+        if (NULL == ct0 || NULL == ct1) {
+            return JNI_FALSE;
+        }
+        if (ct0->count() != ct1->count()) {
+            return JNI_FALSE;
+        }
+
+        SkAutoLockColors alc0(ct0);
+        SkAutoLockColors alc1(ct1);
+        const size_t size = ct0->count() * sizeof(SkPMColor);
+        if (memcmp(alc0.colors(), alc1.colors(), size) != 0) {
+            return JNI_FALSE;
+        }
+    }
+
+    // now compare each scanline. We can't do the entire buffer at once,
+    // since we don't care about the pixel values that might extend beyond
+    // the width (since the scanline might be larger than the logical width)
+    const int h = bm0->height();
+    const size_t size = bm0->width() * bm0->bytesPerPixel();
+    for (int y = 0; y < h; y++) {
+        if (memcmp(bm0->getAddr(0, y), bm1->getAddr(0, y), size) != 0) {
+            return JNI_FALSE;
+        }
+    }
+    return JNI_TRUE;
+}
+
+static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapHandle) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    bitmap->lockPixels();
+    bitmap->unlockPixels();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include <android_runtime/AndroidRuntime.h>
+
+static JNINativeMethod gBitmapMethods[] = {
+    {   "nativeCreate",             "([IIIIIIZ)Landroid/graphics/Bitmap;",
+        (void*)Bitmap_creator },
+    {   "nativeCopy",               "(JIZ)Landroid/graphics/Bitmap;",
+        (void*)Bitmap_copy },
+    {   "nativeDestructor",         "(J)V", (void*)Bitmap_destructor },
+    {   "nativeRecycle",            "(J)Z", (void*)Bitmap_recycle },
+    {   "nativeReconfigure",        "(JIIII)V", (void*)Bitmap_reconfigure },
+    {   "nativeCompress",           "(JIILjava/io/OutputStream;[B)Z",
+        (void*)Bitmap_compress },
+    {   "nativeErase",              "(JI)V", (void*)Bitmap_erase },
+    {   "nativeRowBytes",           "(J)I", (void*)Bitmap_rowBytes },
+    {   "nativeConfig",             "(J)I", (void*)Bitmap_config },
+    {   "nativeHasAlpha",           "(J)Z", (void*)Bitmap_hasAlpha },
+    {   "nativeSetAlphaAndPremultiplied", "(JZZ)V", (void*)Bitmap_setAlphaAndPremultiplied},
+    {   "nativeHasMipMap",          "(J)Z", (void*)Bitmap_hasMipMap },
+    {   "nativeSetHasMipMap",       "(JZ)V", (void*)Bitmap_setHasMipMap },
+    {   "nativeCreateFromParcel",
+        "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
+        (void*)Bitmap_createFromParcel },
+    {   "nativeWriteToParcel",      "(JZILandroid/os/Parcel;)Z",
+        (void*)Bitmap_writeToParcel },
+    {   "nativeExtractAlpha",       "(JJ[I)Landroid/graphics/Bitmap;",
+        (void*)Bitmap_extractAlpha },
+    {   "nativeGenerationId",       "(J)I", (void*)Bitmap_getGenerationId },
+    {   "nativeGetPixel",           "(JIIZ)I", (void*)Bitmap_getPixel },
+    {   "nativeGetPixels",          "(J[IIIIIIIZ)V", (void*)Bitmap_getPixels },
+    {   "nativeSetPixel",           "(JIIIZ)V", (void*)Bitmap_setPixel },
+    {   "nativeSetPixels",          "(J[IIIIIIIZ)V", (void*)Bitmap_setPixels },
+    {   "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
+                                            (void*)Bitmap_copyPixelsToBuffer },
+    {   "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
+                                            (void*)Bitmap_copyPixelsFromBuffer },
+    {   "nativeSameAs",             "(JJ)Z", (void*)Bitmap_sameAs },
+    {   "nativePrepareToDraw",      "(J)V", (void*)Bitmap_prepareToDraw },
+};
+
+#define kClassPathName  "android/graphics/Bitmap"
+
+int register_android_graphics_Bitmap(JNIEnv* env)
+{
+    return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
+                                gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods));
+}
diff --git a/core/jni/android/graphics/CanvasProperty.cpp b/core/jni/android/graphics/CanvasProperty.cpp
new file mode 100644
index 0000000..cfa9cd8
--- /dev/null
+++ b/core/jni/android/graphics/CanvasProperty.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 20014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "GraphicsJNI.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include <utils/RefBase.h>
+#include <CanvasProperty.h>
+
+namespace android {
+
+using namespace uirenderer;
+
+#ifdef USE_OPENGL_RENDERER
+
+static jlong createFloat(JNIEnv* env, jobject clazz, jfloat initialValue) {
+    return reinterpret_cast<jlong>(new CanvasPropertyPrimitive(initialValue));
+}
+
+static jlong createPaint(JNIEnv* env, jobject clazz, jlong paintPtr) {
+    const SkPaint* paint = reinterpret_cast<const SkPaint*>(paintPtr);
+    return 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));
+}
+
+}; // namespace android
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index a4c2dd2..acfab56 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -33,6 +33,7 @@
 #include "SkXfermode.h"
 #include "unicode/uloc.h"
 #include "unicode/ushape.h"
+#include "utils/Blur.h"
 #include "TextLayout.h"
 
 #ifdef USE_MINIKIN
@@ -827,19 +828,23 @@
         env->ReleaseStringChars(text, textArray);
     }
 
-    static void setShadowLayer(JNIEnv* env, jobject jpaint, jfloat radius,
+    static void setShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat radius,
                                jfloat dx, jfloat dy, jint color) {
-        NPE_CHECK_RETURN_VOID(env, jpaint);
-
-        SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
+        SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
         if (radius <= 0) {
             paint->setLooper(NULL);
         }
         else {
-            paint->setLooper(new SkBlurDrawLooper(radius, dx, dy, (SkColor)color))->unref();
+            SkScalar sigma = android::uirenderer::Blur::convertRadiusToSigma(radius);
+            paint->setLooper(new SkBlurDrawLooper((SkColor)color, sigma, dx, dy))->unref();
         }
     }
 
+    static jboolean hasShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle) {
+        SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+        return paint->getLooper() && paint->getLooper()->asABlurShadow(NULL);
+    }
+
     static int breakText(JNIEnv* env, SkPaint& paint, const jchar text[],
                          int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
                          SkPaint::TextBufferDirection tbd) {
@@ -1019,7 +1024,8 @@
                                         (void*) SkPaintGlue::getStringBounds },
     {"nativeGetCharArrayBounds", "(J[CIIILandroid/graphics/Rect;)V",
                                     (void*) SkPaintGlue::getCharArrayBounds },
-    {"nSetShadowLayer", "(FFFI)V", (void*)SkPaintGlue::setShadowLayer}
+    {"native_setShadowLayer", "(JFFFI)V", (void*)SkPaintGlue::setShadowLayer},
+    {"native_hasShadowLayer", "(J)Z", (void*)SkPaintGlue::hasShadowLayer}
 };
 
 static jfieldID req_fieldID(jfieldID id) {
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index b78b131..621534e 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -221,7 +221,7 @@
     }
 
     fields.postEvent = env->GetStaticMethodID(clazz, "postEventFromNative",
-            "(Ljava/lang/Object;)V");
+            "(Ljava/lang/ref/WeakReference;)V");
     if (fields.postEvent == NULL) {
         ALOGE("can't find android/graphics/SurfaceTexture.postEventFromNative");
     }
@@ -338,7 +338,7 @@
 
 static JNINativeMethod gSurfaceTextureMethods[] = {
     {"nativeClassInit",            "()V",   (void*)SurfaceTexture_classInit },
-    {"nativeInit",                 "(IZLjava/lang/Object;)V", (void*)SurfaceTexture_init },
+    {"nativeInit",                 "(IZLjava/lang/ref/WeakReference;)V", (void*)SurfaceTexture_init },
     {"nativeFinalize",             "()V",   (void*)SurfaceTexture_finalize },
     {"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize },
     {"nativeUpdateTexImage",       "()V",   (void*)SurfaceTexture_updateTexImage },
diff --git a/core/jni/android/graphics/YuvToJpegEncoder.cpp b/core/jni/android/graphics/YuvToJpegEncoder.cpp
index 799782d..6591d60 100644
--- a/core/jni/android/graphics/YuvToJpegEncoder.cpp
+++ b/core/jni/android/graphics/YuvToJpegEncoder.cpp
@@ -226,16 +226,17 @@
     jint* imgOffsets = env->GetIntArrayElements(offsets, NULL);
     jint* imgStrides = env->GetIntArrayElements(strides, NULL);
     YuvToJpegEncoder* encoder = YuvToJpegEncoder::create(format, imgStrides);
-    if (encoder == NULL) {
-        return JNI_FALSE;
+    jboolean result = JNI_FALSE;
+    if (encoder != NULL) {
+        encoder->encode(strm, yuv, width, height, imgOffsets, jpegQuality);
+        delete encoder;
+        result = JNI_TRUE;
     }
-    encoder->encode(strm, yuv, width, height, imgOffsets, jpegQuality);
 
-    delete encoder;
     env->ReleaseByteArrayElements(inYuv, yuv, 0);
     env->ReleaseIntArrayElements(offsets, imgOffsets, 0);
     env->ReleaseIntArrayElements(strides, imgStrides, 0);
-    return JNI_TRUE;
+    return result;
 }
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index 957f95c..fa2cfe3 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -18,8 +18,12 @@
 // #define LOG_NDEBUG 0
 // #define LOG_NNDEBUG 0
 #define LOG_TAG "CameraMetadata-JNI"
+#include <utils/Errors.h>
 #include <utils/Log.h>
 #include <utils/RefBase.h>
+#include <utils/Vector.h>
+#include <utils/SortedVector.h>
+#include <utils/KeyedVector.h>
 #include <string.h>
 
 #include "jni.h"
@@ -483,12 +487,25 @@
 
     ALOGV("%s (key = '%s')", __FUNCTION__, key);
 
+    sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
+
+    SortedVector<String8> vendorSections;
+    size_t vendorSectionCount = 0;
+
+    if (vTags != 0) {
+        vendorSections = vTags->getAllSectionNames();
+        vendorSectionCount = vendorSections.size();
+    }
+
     // First, find the section by the longest string match
     const char *section = NULL;
     size_t sectionIndex = 0;
     size_t sectionLength = 0;
-    for (size_t i = 0; i < ANDROID_SECTION_COUNT; ++i) {
-        const char *str = camera_metadata_section_names[i];
+    size_t totalSectionCount = ANDROID_SECTION_COUNT + vendorSectionCount;
+    for (size_t i = 0; i < totalSectionCount; ++i) {
+
+        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 (strstr(key, str) == key) { // key begins with the section name
@@ -502,12 +519,11 @@
                 sectionIndex = i;
                 sectionLength = strLength;
 
-                ALOGVV("%s: Found new best section (idx %d)", __FUNCTION__, sectionIndex);
+                ALOGVV("%s: Found new best section (%s)", __FUNCTION__, section);
             }
         }
     }
 
-    // TODO: vendor ext
     // TODO: Make above get_camera_metadata_section_from_name ?
 
     if (section == NULL) {
@@ -524,33 +540,47 @@
     if (sectionLength + 1 >= keyLength) {
         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
                              "Key length too short for key '%s')", key);
+        return 0;
     }
 
     // Match rest of name against the tag names in that section only
-    uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
-    tagBegin = camera_metadata_section_bounds[sectionIndex][0];
-    tagEnd = camera_metadata_section_bounds[sectionIndex][1];
+    uint32_t tag = 0;
+    if (sectionIndex < ANDROID_SECTION_COUNT) {
+        // Match built-in tags (typically android.*)
+        uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
+        tagBegin = camera_metadata_section_bounds[sectionIndex][0];
+        tagEnd = camera_metadata_section_bounds[sectionIndex][1];
 
-    uint32_t tag;
-    for (tag = tagBegin; tag < tagEnd; ++tag) {
-        const char *tagName = get_camera_metadata_tag_name(tag);
+        for (tag = tagBegin; tag < tagEnd; ++tag) {
+            const char *tagName = get_camera_metadata_tag_name(tag);
 
-        if (strcmp(keyTagName, tagName) == 0) {
-            ALOGV("%s: Found matched tag '%s' (%d)",
-                  __FUNCTION__, tagName, tag);
-            break;
+            if (strcmp(keyTagName, tagName) == 0) {
+                ALOGV("%s: Found matched tag '%s' (%d)",
+                      __FUNCTION__, tagName, tag);
+                break;
+            }
+        }
+
+        if (tag == tagEnd) {
+            jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+                                 "Could not find tag name for key '%s')", key);
+            return 0;
+        }
+    } else if (vTags != 0) {
+        // Match vendor tags (typically com.*)
+        const String8 sectionName(section);
+        const String8 tagName(keyTagName);
+
+        status_t res = OK;
+        if ((res = vTags->lookupTag(tagName, sectionName, &tag)) != OK) {
+            jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+                    "%s: No vendor tag matches key '%s'", __FUNCTION__, key);
+            return 0;
         }
     }
 
-    // TODO: vendor ext
     // TODO: Make above get_camera_metadata_tag_from_name ?
 
-    if (tag == tagEnd) {
-        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
-                             "Could not find tag name for key '%s')", key);
-        return 0;
-    }
-
     return tag;
 }
 
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index f4bab26..fedb1b2 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -22,6 +22,7 @@
 // keep these values in sync with AudioFormat.java
 #define ENCODING_PCM_16BIT 2
 #define ENCODING_PCM_8BIT  3
+#define ENCODING_PCM_FLOAT 4
 
 static inline audio_format_t audioFormatToNative(int audioFormat)
 {
@@ -30,6 +31,8 @@
         return AUDIO_FORMAT_PCM_16_BIT;
     case ENCODING_PCM_8BIT:
         return AUDIO_FORMAT_PCM_8_BIT;
+    case ENCODING_PCM_FLOAT:
+        return AUDIO_FORMAT_PCM_FLOAT;
     default:
         return AUDIO_FORMAT_INVALID;
     }
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index d8faaf3..09bdc61 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -393,13 +393,46 @@
                                                         jshortArray javaAudioData,
                                                         jint offsetInShorts, jint sizeInShorts) {
 
-    jint read = android_media_AudioRecord_readInByteArray(env, thiz,
-                                                        (jbyteArray) javaAudioData,
-                                                        offsetInShorts*2, sizeInShorts*2);
-    if (read > 0) {
-        read /= 2;
+    jshort* recordBuff = NULL;
+    // get the audio recorder from which we'll read new audio samples
+    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
+    if (lpRecorder == NULL) {
+        ALOGE("Unable to retrieve AudioRecord object, can't record");
+        return 0;
     }
-    return read;
+
+    if (!javaAudioData) {
+        ALOGE("Invalid Java array to store recorded audio, can't record");
+        return 0;
+    }
+
+    // get the pointer to where we'll record the audio
+    // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
+    // a way that it becomes much more efficient. When doing so, we will have to prevent the
+    // AudioSystem callback to be called while in critical section (in case of media server
+    // process crash for instance)
+    recordBuff = (jshort *)env->GetShortArrayElements(javaAudioData, NULL);
+
+    if (recordBuff == NULL) {
+        ALOGE("Error retrieving destination for recorded audio data, can't record");
+        return 0;
+    }
+
+    // read the new audio data from the native AudioRecord object
+    const size_t recorderBuffSize = lpRecorder->frameCount()*lpRecorder->frameSize();
+    const size_t sizeInBytes = sizeInShorts * sizeof(short);
+    ssize_t readSize = lpRecorder->read(recordBuff + offsetInShorts * sizeof(short),
+                                        sizeInBytes > recorderBuffSize ?
+                                            recorderBuffSize : sizeInBytes);
+
+    env->ReleaseShortArrayElements(javaAudioData, recordBuff, 0);
+
+    if (readSize < 0) {
+        readSize = AUDIORECORD_ERROR_INVALID_OPERATION;
+    } else {
+        readSize /= sizeof(short);
+    }
+    return (jint) readSize;
 }
 
 // ----------------------------------------------------------------------------
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 162d0c4..463a0a8 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -526,12 +526,15 @@
         switch (format) {
 
         default:
-            // TODO Currently the only possible values for format are AUDIO_FORMAT_PCM_16_BIT
-            // and AUDIO_FORMAT_PCM_8_BIT, due to the limited set of values for audioFormat.
+            // TODO Currently the only possible values for format are AUDIO_FORMAT_PCM_16_BIT,
+            // AUDIO_FORMAT_PCM_8_BIT, and AUDIO_FORMAT_PCM_FLOAT,
+            // due to the limited set of values for audioFormat.
             // The next section of the switch will probably work for more formats, but it has only
-            // been tested for AUDIO_FORMAT_PCM_16_BIT, so that's why the "default" case fails.
+            // been tested for AUDIO_FORMAT_PCM_16_BIT and AUDIO_FORMAT_PCM_FLOAT,
+            // so that's why the "default" case fails.
             break;
 
+        case AUDIO_FORMAT_PCM_FLOAT:
         case AUDIO_FORMAT_PCM_16_BIT: {
             // writing to shared memory, check for capacity
             if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
@@ -637,14 +640,81 @@
                                                   jshortArray javaAudioData,
                                                   jint offsetInShorts, jint sizeInShorts,
                                                   jint javaAudioFormat) {
-    jint written = android_media_AudioTrack_write_byte(env, thiz,
-                                                 (jbyteArray) javaAudioData,
-                                                 offsetInShorts*2, sizeInShorts*2,
-                                                 javaAudioFormat,
-                                                 JNI_TRUE /*blocking write, legacy behavior*/);
-    if (written > 0) {
-        written /= 2;
+
+    //ALOGV("android_media_AudioTrack_write_short(offset=%d, sizeInShorts=%d) called",
+    //    offsetInShorts, sizeInShorts);
+    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+    if (lpTrack == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for write()");
+        return 0;
     }
+
+    // get the pointer for the audio data from the java array
+    // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
+    // a way that it becomes much more efficient. When doing so, we will have to prevent the
+    // AudioSystem callback to be called while in critical section (in case of media server
+    // process crash for instance)
+    jshort* cAudioData = NULL;
+    if (javaAudioData) {
+        cAudioData = (jshort *)env->GetShortArrayElements(javaAudioData, NULL);
+        if (cAudioData == NULL) {
+            ALOGE("Error retrieving source of audio data to play, can't play");
+            return 0; // out of memory or no data to load
+        }
+    } else {
+        ALOGE("NULL java array of audio data to play, can't play");
+        return 0;
+    }
+    jint written = writeToTrack(lpTrack, javaAudioFormat, (jbyte *)cAudioData,
+                                offsetInShorts * sizeof(short), sizeInShorts * sizeof(short),
+            true /*blocking write, legacy behavior*/);
+    env->ReleaseShortArrayElements(javaAudioData, cAudioData, 0);
+
+    if (written > 0) {
+        written /= sizeof(short);
+    }
+    //ALOGV("write wrote %d (tried %d) shorts in the native AudioTrack with offset %d",
+    //     (int)written, (int)(sizeInShorts), (int)offsetInShorts);
+
+    return written;
+}
+
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_write_float(JNIEnv *env,  jobject thiz,
+                                                  jfloatArray javaAudioData,
+                                                  jint offsetInFloats, jint sizeInFloats,
+                                                  jint javaAudioFormat,
+                                                  jboolean isWriteBlocking) {
+
+    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+    if (lpTrack == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for write()");
+        return 0;
+    }
+
+    jfloat* cAudioData = NULL;
+    if (javaAudioData) {
+        cAudioData = (jfloat *)env->GetFloatArrayElements(javaAudioData, NULL);
+        if (cAudioData == NULL) {
+            ALOGE("Error retrieving source of audio data to play, can't play");
+            return 0; // out of memory or no data to load
+        }
+    } else {
+        ALOGE("NULL java array of audio data to play, can't play");
+        return 0;
+    }
+    jint written = writeToTrack(lpTrack, javaAudioFormat, (jbyte *)cAudioData,
+                                offsetInFloats * sizeof(float), sizeInFloats * sizeof(float),
+                                isWriteBlocking == JNI_TRUE /* blocking */);
+    env->ReleaseFloatArrayElements(javaAudioData, cAudioData, 0);
+
+    if (written > 0) {
+        written /= sizeof(float);
+    }
+
     return written;
 }
 
@@ -934,6 +1004,7 @@
                              "(Ljava/lang/Object;IIIZ)I",
                                          (void *)android_media_AudioTrack_write_native_bytes},
     {"native_write_short",   "([SIII)I", (void *)android_media_AudioTrack_write_short},
+    {"native_write_float",   "([FIIIZ)I",(void *)android_media_AudioTrack_write_float},
     {"native_setVolume",     "(FF)V",    (void *)android_media_AudioTrack_set_volume},
     {"native_get_native_frame_count",
                              "()I",      (void *)android_media_AudioTrack_get_native_frame_count},
diff --git a/core/jni/android_server_FingerprintManager.cpp b/core/jni/android_server_FingerprintManager.cpp
new file mode 100644
index 0000000..f8a1fd9
--- /dev/null
+++ b/core/jni/android_server_FingerprintManager.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Fingerprint-JNI"
+
+#include "JNIHelp.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+#include <utils/Log.h>
+
+namespace android {
+
+static struct {
+    jclass clazz;
+    jmethodID notify;
+} gFingerprintManagerClassInfo;
+
+static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) {
+    return -1; // TODO
+}
+
+static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) {
+    return -1; // TODO
+}
+
+// ----------------------------------------------------------------------------
+
+static const JNINativeMethod g_methods[] = {
+    { "nativeEnroll", "(I)I", (void*)nativeEnroll },
+    { "nativeRemove", "(I)I", (void*)nativeRemove },
+};
+
+#define FIND_CLASS(var, className) \
+        var = env->FindClass(className); \
+        LOG_FATAL_IF(! var, "Unable to find class " className); \
+        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_server_FingerprintManager(JNIEnv* env) {
+    FIND_CLASS(gFingerprintManagerClassInfo.clazz,
+            "android/service/fingerprint/FingerprintManager");
+    GET_METHOD_ID(gFingerprintManagerClassInfo.notify, gFingerprintManagerClassInfo.clazz,
+            "notify", "(III)V");
+    return AndroidRuntime::registerNativeMethods(
+        env, "com/android/service/fingerprint/FingerprintManager", g_methods, NELEM(g_methods));
+}
+
+} // namespace android
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index eca2767..c3fe4a3 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -49,6 +49,7 @@
 #include <Stencil.h>
 #include <Rect.h>
 #include <RenderNode.h>
+#include <CanvasProperty.h>
 
 #ifdef USE_MINIKIN
 #include <minikin/Layout.h>
@@ -84,7 +85,6 @@
     #define RENDERER_LOGD(...)
 #endif
 
-#define MODIFIER_SHADOW 1
 #define MODIFIER_SHADER 2
 
 // ----------------------------------------------------------------------------
@@ -211,32 +211,6 @@
     return renderer->callDrawGLFunction(functor, dirty);
 }
 
-static void android_view_GLES20Canvas_detachFunctor(JNIEnv* env,
-        jobject clazz, jlong rendererPtr, jlong functorPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
-    renderer->detachFunctor(functor);
-}
-
-static void android_view_GLES20Canvas_attachFunctor(JNIEnv* env,
-        jobject clazz, jlong rendererPtr, jlong functorPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
-    renderer->attachFunctor(functor);
-}
-
-static jint android_view_GLES20Canvas_invokeFunctors(JNIEnv* env,
-        jobject clazz, jlong rendererPtr, jobject dirty) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    android::uirenderer::Rect bounds;
-    status_t status = renderer->invokeFunctors(bounds);
-    if (status != DrawGlInfo::kStatusDone && dirty != NULL) {
-        env->CallVoidMethod(dirty, gRectClassInfo.set,
-                int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom));
-    }
-    return status;
-}
-
 // ----------------------------------------------------------------------------
 // Misc
 // ----------------------------------------------------------------------------
@@ -550,6 +524,16 @@
     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) {
+    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(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) {
@@ -638,7 +622,6 @@
 static void android_view_GLES20Canvas_resetModifiers(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jint modifiers) {
     OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    if (modifiers & MODIFIER_SHADOW) renderer->resetShadow();
     if (modifiers & MODIFIER_SHADER) renderer->resetShader();
 }
 
@@ -650,12 +633,6 @@
 }
 
 
-static void android_view_GLES20Canvas_setupShadow(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jfloat radius, jfloat dx, jfloat dy, jint color) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    renderer->setupShadow(radius, dx, dy, color);
-}
-
 // ----------------------------------------------------------------------------
 // Draw filters
 // ----------------------------------------------------------------------------
@@ -1065,10 +1042,6 @@
     { "nGetStencilSize",    "()I",             (void*) android_view_GLES20Canvas_getStencilSize },
 
     { "nCallDrawGLFunction", "(JJ)I",          (void*) android_view_GLES20Canvas_callDrawGLFunction },
-    { "nDetachFunctor",      "(JJ)V",          (void*) android_view_GLES20Canvas_detachFunctor },
-    { "nAttachFunctor",      "(JJ)V",          (void*) android_view_GLES20Canvas_attachFunctor },
-    { "nInvokeFunctors",     "(JLandroid/graphics/Rect;)I",
-            (void*) android_view_GLES20Canvas_invokeFunctors },
 
     { "nSave",              "(JI)I",           (void*) android_view_GLES20Canvas_save },
     { "nRestore",           "(J)V",            (void*) android_view_GLES20Canvas_restore },
@@ -1110,6 +1083,7 @@
     { "nDrawRects",         "(J[FIJ)V",        (void*) android_view_GLES20Canvas_drawRects },
     { "nDrawRoundRect",     "(JFFFFFFJ)V",     (void*) android_view_GLES20Canvas_drawRoundRect },
     { "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 },
@@ -1119,7 +1093,6 @@
 
     { "nResetModifiers",    "(JI)V",           (void*) android_view_GLES20Canvas_resetModifiers },
     { "nSetupShader",       "(JJ)V",           (void*) android_view_GLES20Canvas_setupShader },
-    { "nSetupShadow",       "(JFFFI)V",        (void*) android_view_GLES20Canvas_setupShadow },
 
     { "nSetupPaintFilter",  "(JII)V",          (void*) android_view_GLES20Canvas_setupPaintFilter },
     { "nResetPaintFilter",  "(J)V",            (void*) android_view_GLES20Canvas_resetPaintFilter },
diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp
index 2e8dccf..8a426ac 100644
--- a/core/jni/android_view_GraphicBuffer.cpp
+++ b/core/jni/android_view_GraphicBuffer.cpp
@@ -74,15 +74,10 @@
 } gRectClassInfo;
 
 static struct {
-    jfieldID mFinalizer;
-    jfieldID mNativeCanvas;
     jfieldID mSurfaceFormat;
+    jmethodID safeCanvasSwap;
 } gCanvasClassInfo;
 
-static struct {
-    jfieldID mNativeCanvas;
-} gCanvasFinalizerClassInfo;
-
 #define GET_INT(object, field) \
     env->GetIntField(object, field)
 
@@ -146,15 +141,6 @@
 // Canvas management
 // ----------------------------------------------------------------------------
 
-static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
-    jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
-    SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
-            GET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas));
-    SET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas, (long) newCanvas);
-    SET_LONG(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (long) newCanvas);
-    SkSafeUnref(previousCanvas);
-}
-
 static inline SkBitmap::Config convertPixelFormat(int32_t format) {
     switch (format) {
         case PIXEL_FORMAT_RGBA_8888:
@@ -213,7 +199,7 @@
     SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer->getPixelFormat());
 
     SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
-    swapCanvasPtr(env, canvas, nativeCanvas);
+    INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
 
     SkRect clipRect;
     clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
@@ -233,7 +219,7 @@
     GraphicBufferWrapper* wrapper =
                 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
     SkCanvas* nativeCanvas = SkNEW(SkCanvas);
-    swapCanvasPtr(env, canvas, nativeCanvas);
+    INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
 
     if (wrapper) {
         status_t status = wrapper->buffer->unlock();
@@ -332,13 +318,8 @@
     GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I");
 
     FIND_CLASS(clazz, "android/graphics/Canvas");
-    GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer",
-            "Landroid/graphics/Canvas$CanvasFinalizer;");
-    GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
     GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I");
-
-    FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer");
-    GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
+    GET_METHOD_ID(gCanvasClassInfo.safeCanvasSwap, clazz, "safeCanvasSwap", "(JZ)V");
 
     return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
 }
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 4715c26..e45a901 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -119,7 +119,6 @@
         jint right, jint bottom, jfloat radius) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().mutableOutline().setRoundRect(left, top, right, bottom, radius);
-    renderNode->mutateStagingProperties().updateClipPath();
 }
 
 static void android_view_RenderNode_setOutlineConvexPath(JNIEnv* env,
@@ -127,21 +126,18 @@
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     SkPath* outlinePath = reinterpret_cast<SkPath*>(outlinePathPtr);
     renderNode->mutateStagingProperties().mutableOutline().setConvexPath(outlinePath);
-    renderNode->mutateStagingProperties().updateClipPath();
 }
 
 static void android_view_RenderNode_setOutlineEmpty(JNIEnv* env,
         jobject clazz, jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().mutableOutline().setEmpty();
-    renderNode->mutateStagingProperties().updateClipPath();
 }
 
 static void android_view_RenderNode_setClipToOutline(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, jboolean clipToOutline) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().mutableOutline().setShouldClip(clipToOutline);
-    renderNode->mutateStagingProperties().updateClipPath();
 }
 
 static void android_view_RenderNode_setRevealClip(JNIEnv* env,
@@ -150,7 +146,6 @@
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().mutableRevealClip().set(
             shouldClip, inverseClip, x, y, radius);
-    renderNode->mutateStagingProperties().updateClipPath();
 }
 
 static void android_view_RenderNode_setAlpha(JNIEnv* env,
diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp
index 35cdf60..5733f60 100644
--- a/core/jni/android_view_RenderNodeAnimator.cpp
+++ b/core/jni/android_view_RenderNodeAnimator.cpp
@@ -16,8 +16,6 @@
 
 #define LOG_TAG "OpenGLRenderer"
 
-#include "android_view_RenderNodeAnimator.h"
-
 #include "jni.h"
 #include "GraphicsJNI.h"
 #include <nativehelper/JNIHelp.h>
@@ -37,6 +35,8 @@
     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) {
@@ -45,54 +45,106 @@
     return env;
 }
 
-RenderNodeAnimator::RenderNodeAnimator(JNIEnv* env, jobject weakThis,
-                RenderProperty property, DeltaValueType deltaType, float delta)
-        : RenderPropertyAnimator(property, deltaType, delta) {
-    mWeakThis = env->NewGlobalRef(weakThis);
-    env->GetJavaVM(&mJvm);
-}
+class AnimationListenerBridge : public AnimationListener {
+public:
+    // This holds a strong reference to a Java WeakReference<T> object. This avoids
+    // cyclic-references-of-doom. If you think "I know, just use NewWeakGlobalRef!"
+    // then you end up with basically a PhantomReference, which is totally not
+    // what we want.
+    AnimationListenerBridge(JNIEnv* env, jobject weakThis) {
+        mWeakThis = env->NewGlobalRef(weakThis);
+        env->GetJavaVM(&mJvm);
+    }
 
-RenderNodeAnimator::~RenderNodeAnimator() {
-    JNIEnv* env = getEnv(mJvm);
-    env->DeleteGlobalRef(mWeakThis);
-    mWeakThis = NULL;
-}
+    virtual ~AnimationListenerBridge() {
+        JNIEnv* env = getEnv(mJvm);
+        env->DeleteGlobalRef(mWeakThis);
+        mWeakThis = NULL;
+    }
 
-void RenderNodeAnimator::callOnFinished() {
-    JNIEnv* env = getEnv(mJvm);
-    env->CallStaticVoidMethod(
-            gRenderNodeAnimatorClassInfo.clazz,
-            gRenderNodeAnimatorClassInfo.callOnFinished,
-            mWeakThis);
-}
+    virtual void onAnimationFinished(BaseAnimator*) {
+        JNIEnv* env = getEnv(mJvm);
+        env->CallStaticVoidMethod(
+                gRenderNodeAnimatorClassInfo.clazz,
+                gRenderNodeAnimatorClassInfo.callOnFinished,
+                mWeakThis);
+    }
 
-static jlong createAnimator(JNIEnv* env, jobject clazz, jobject weakThis,
-        jint property, jint deltaType, jfloat deltaValue) {
-    LOG_ALWAYS_FATAL_IF(property < 0 || property > RenderNodeAnimator::ALPHA,
+private:
+    JavaVM* mJvm;
+    jobject mWeakThis;
+};
+
+static inline RenderPropertyAnimator::RenderProperty toRenderProperty(jint property) {
+    LOG_ALWAYS_FATAL_IF(property < 0 || property > RenderPropertyAnimator::ALPHA,
             "Invalid property %d", property);
+    return static_cast<RenderPropertyAnimator::RenderProperty>(property);
+}
+
+static inline RenderPropertyAnimator::DeltaValueType toDeltaType(jint deltaType) {
     LOG_ALWAYS_FATAL_IF(deltaType != RenderPropertyAnimator::DELTA
             && deltaType != RenderPropertyAnimator::ABSOLUTE,
             "Invalid delta type %d", deltaType);
+    return static_cast<RenderPropertyAnimator::DeltaValueType>(deltaType);
+}
 
-    RenderNodeAnimator* animator = new RenderNodeAnimator(env, weakThis,
-            static_cast<RenderPropertyAnimator::RenderProperty>(property),
-            static_cast<RenderPropertyAnimator::DeltaValueType>(deltaType),
-            deltaValue);
-    animator->incStrong(0);
+static inline CanvasPropertyPaintAnimator::PaintField toPaintField(jint field) {
+    LOG_ALWAYS_FATAL_IF(field < 0
+            || field > CanvasPropertyPaintAnimator::ALPHA,
+            "Invalid paint field %d", field);
+    return static_cast<CanvasPropertyPaintAnimator::PaintField>(field);
+}
+
+static jlong createAnimator(JNIEnv* env, jobject clazz, jobject weakThis,
+        jint propertyRaw, jint deltaTypeRaw, jfloat deltaValue) {
+    RenderPropertyAnimator::RenderProperty property = toRenderProperty(propertyRaw);
+    RenderPropertyAnimator::DeltaValueType deltaType = toDeltaType(deltaTypeRaw);
+
+    BaseAnimator* animator = new RenderPropertyAnimator(property, deltaType, deltaValue);
+    animator->setListener(new AnimationListenerBridge(env, weakThis));
+    return reinterpret_cast<jlong>( animator );
+}
+
+static jlong createCanvasPropertyFloatAnimator(JNIEnv* env, jobject clazz,
+        jobject weakThis, jlong canvasPropertyPtr, jint deltaTypeRaw, jfloat deltaValue) {
+    RenderPropertyAnimator::DeltaValueType deltaType = toDeltaType(deltaTypeRaw);
+    CanvasPropertyPrimitive* canvasProperty = reinterpret_cast<CanvasPropertyPrimitive*>(canvasPropertyPtr);
+    BaseAnimator* animator = new CanvasPropertyPrimitiveAnimator(canvasProperty, deltaType, deltaValue);
+    animator->setListener(new AnimationListenerBridge(env, weakThis));
+    return reinterpret_cast<jlong>( animator );
+}
+
+static jlong createCanvasPropertyPaintAnimator(JNIEnv* env, jobject clazz,
+        jobject weakThis, jlong canvasPropertyPtr, jint paintFieldRaw,
+        jint deltaTypeRaw, jfloat deltaValue) {
+    RenderPropertyAnimator::DeltaValueType deltaType = toDeltaType(deltaTypeRaw);
+    CanvasPropertyPaint* canvasProperty = reinterpret_cast<CanvasPropertyPaint*>(canvasPropertyPtr);
+    CanvasPropertyPaintAnimator::PaintField paintField = toPaintField(paintFieldRaw);
+    BaseAnimator* animator = new CanvasPropertyPaintAnimator(
+            canvasProperty, paintField, deltaType, deltaValue);
+    animator->setListener(new AnimationListenerBridge(env, weakThis));
     return reinterpret_cast<jlong>( animator );
 }
 
 static void setDuration(JNIEnv* env, jobject clazz, jlong animatorPtr, jint duration) {
     LOG_ALWAYS_FATAL_IF(duration < 0, "Duration cannot be negative");
-    RenderNodeAnimator* animator = reinterpret_cast<RenderNodeAnimator*>(animatorPtr);
+    BaseAnimator* animator = reinterpret_cast<BaseAnimator*>(animatorPtr);
     animator->setDuration(duration);
 }
 
-static void unref(JNIEnv* env, jobject clazz, jlong objPtr) {
-    VirtualLightRefBase* obj = reinterpret_cast<VirtualLightRefBase*>(objPtr);
-    obj->decStrong(0);
+static jint getDuration(JNIEnv* env, jobject clazz, jlong animatorPtr) {
+    BaseAnimator* animator = reinterpret_cast<BaseAnimator*>(animatorPtr);
+    return static_cast<jint>(animator->duration());
 }
 
+static void setInterpolator(JNIEnv* env, jobject clazz, jlong animatorPtr, jlong interpolatorPtr) {
+    BaseAnimator* animator = reinterpret_cast<BaseAnimator*>(animatorPtr);
+    Interpolator* interpolator = reinterpret_cast<Interpolator*>(interpolatorPtr);
+    animator->setInterpolator(interpolator);
+}
+
+#endif
+
 // ----------------------------------------------------------------------------
 // JNI Glue
 // ----------------------------------------------------------------------------
@@ -100,9 +152,14 @@
 const char* const kClassPathName = "android/view/RenderNodeAnimator";
 
 static JNINativeMethod gMethods[] = {
+#ifdef USE_OPENGL_RENDERER
     { "nCreateAnimator", "(Ljava/lang/ref/WeakReference;IIF)J", (void*) createAnimator },
+    { "nCreateCanvasPropertyFloatAnimator", "(Ljava/lang/ref/WeakReference;JIF)J", (void*) createCanvasPropertyFloatAnimator },
+    { "nCreateCanvasPropertyPaintAnimator", "(Ljava/lang/ref/WeakReference;JIIF)J", (void*) createCanvasPropertyPaintAnimator },
     { "nSetDuration", "(JI)V", (void*) setDuration },
-    { "nUnref", "(J)V", (void*) unref },
+    { "nGetDuration", "(J)I", (void*) getDuration },
+    { "nSetInterpolator", "(JJ)V", (void*) setInterpolator },
+#endif
 };
 
 #define FIND_CLASS(var, className) \
diff --git a/core/jni/android_view_RenderNodeAnimator.h b/core/jni/android_view_RenderNodeAnimator.h
deleted file mode 100644
index d84003f..0000000
--- a/core/jni/android_view_RenderNodeAnimator.h
+++ /dev/null
@@ -1,36 +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 "jni.h"
-
-#include <Animator.h>
-
-namespace android {
-
-class RenderNodeAnimator : public uirenderer::RenderPropertyAnimator {
-public:
-    RenderNodeAnimator(JNIEnv* env, jobject callbackObject,
-            RenderProperty property, DeltaValueType deltaType, float delta);
-    virtual ~RenderNodeAnimator();
-
-    void callOnFinished();
-
-private:
-    JavaVM* mJvm;
-    jobject mWeakThis;
-};
-
-}
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index ab6c1e0..6c9d060 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -69,15 +69,10 @@
 } gRectClassInfo;
 
 static struct {
-    jfieldID mFinalizer;
-    jfieldID mNativeCanvas;
     jfieldID mSurfaceFormat;
+    jmethodID safeCanvasSwap;
 } gCanvasClassInfo;
 
-static struct {
-    jfieldID mNativeCanvas;
-} gCanvasFinalizerClassInfo;
-
 // ----------------------------------------------------------------------------
 
 // this is just a pointer we use to pass to inc/decStrong
@@ -191,15 +186,6 @@
     }
 }
 
-static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
-  jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
-  SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
-          env->GetLongField(canvasObj, gCanvasClassInfo.mNativeCanvas));
-  env->SetLongField(canvasObj, gCanvasClassInfo.mNativeCanvas, (jlong)newCanvas);
-  env->SetLongField(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (jlong)newCanvas);
-  SkSafeUnref(previousCanvas);
-}
-
 static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,
         jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {
     sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
@@ -247,7 +233,7 @@
     }
 
     SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
-    swapCanvasPtr(env, canvasObj, nativeCanvas);
+    env->CallVoidMethod(canvasObj, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
 
     if (dirtyRectPtr) {
         nativeCanvas->clipRect( SkRect::Make(reinterpret_cast<const SkIRect&>(dirtyRect)) );
@@ -277,7 +263,7 @@
 
     // detach the canvas from the surface
     SkCanvas* nativeCanvas = SkNEW(SkCanvas);
-    swapCanvasPtr(env, canvasObj, nativeCanvas);
+    env->CallVoidMethod(canvasObj, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
 
     // unlock surface
     status_t err = surface->unlockAndPost();
@@ -388,12 +374,8 @@
     gSurfaceClassInfo.ctor = env->GetMethodID(gSurfaceClassInfo.clazz, "<init>", "(J)V");
 
     clazz = env->FindClass("android/graphics/Canvas");
-    gCanvasClassInfo.mFinalizer = env->GetFieldID(clazz, "mFinalizer", "Landroid/graphics/Canvas$CanvasFinalizer;");
-    gCanvasClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "J");
     gCanvasClassInfo.mSurfaceFormat = env->GetFieldID(clazz, "mSurfaceFormat", "I");
-
-    clazz = env->FindClass("android/graphics/Canvas$CanvasFinalizer");
-    gCanvasFinalizerClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "J");
+    gCanvasClassInfo.safeCanvasSwap = env->GetMethodID(clazz, "safeCanvasSwap", "(JZ)V");
 
     clazz = env->FindClass("android/graphics/Rect");
     gRectClassInfo.left = env->GetFieldID(clazz, "left", "I");
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index c293c7a..5a935a9 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -50,6 +50,8 @@
     "android/view/Surface$OutOfResourcesException";
 
 static struct {
+    jclass clazz;
+    jmethodID ctor;
     jfieldID width;
     jfieldID height;
     jfieldID refreshRate;
@@ -346,24 +348,49 @@
     SurfaceComposerClient::setDisplayProjection(token, orientation, layerStackRect, displayRect);
 }
 
-static jboolean nativeGetDisplayInfo(JNIEnv* env, jclass clazz,
-        jobject tokenObj, jobject infoObj) {
+static jobjectArray nativeGetDisplayConfigs(JNIEnv* env, jclass clazz,
+        jobject tokenObj) {
     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
-    if (token == NULL) return JNI_FALSE;
+    if (token == NULL) return NULL;
 
-    DisplayInfo info;
-    if (SurfaceComposerClient::getDisplayInfo(token, &info)) {
-        return JNI_FALSE;
+    Vector<DisplayInfo> configs;
+    if (SurfaceComposerClient::getDisplayConfigs(token, &configs) != NO_ERROR ||
+            configs.size() == 0) {
+        return NULL;
     }
 
-    env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w);
-    env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h);
-    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps);
-    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density);
-    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
-    env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
-    env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure);
-    return JNI_TRUE;
+    jobjectArray configArray = env->NewObjectArray(configs.size(),
+            gPhysicalDisplayInfoClassInfo.clazz, NULL);
+
+    for (size_t c = 0; c < configs.size(); ++c) {
+        const DisplayInfo& info = configs[c];
+        jobject infoObj = env->NewObject(gPhysicalDisplayInfoClassInfo.clazz,
+                gPhysicalDisplayInfoClassInfo.ctor);
+        env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w);
+        env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h);
+        env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps);
+        env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density);
+        env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
+        env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
+        env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure);
+        env->SetObjectArrayElement(configArray, static_cast<jsize>(c), infoObj);
+        env->DeleteLocalRef(infoObj);
+    }
+
+    return configArray;
+}
+
+static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
+    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+    if (token == NULL) return -1;
+    return static_cast<jint>(SurfaceComposerClient::getActiveConfig(token));
+}
+
+static jboolean nativeSetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj, jint id) {
+    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+    if (token == NULL) return JNI_FALSE;
+    status_t err = SurfaceComposerClient::setActiveConfig(token, static_cast<int>(id));
+    return err == NO_ERROR ? JNI_TRUE : JNI_FALSE;
 }
 
 static void nativeBlankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
@@ -576,8 +603,12 @@
             (void*)nativeSetDisplayLayerStack },
     {"nativeSetDisplayProjection", "(Landroid/os/IBinder;IIIIIIIII)V",
             (void*)nativeSetDisplayProjection },
-    {"nativeGetDisplayInfo", "(Landroid/os/IBinder;Landroid/view/SurfaceControl$PhysicalDisplayInfo;)Z",
-            (void*)nativeGetDisplayInfo },
+    {"nativeGetDisplayConfigs", "(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$PhysicalDisplayInfo;",
+            (void*)nativeGetDisplayConfigs },
+    {"nativeGetActiveConfig", "(Landroid/os/IBinder;)I",
+            (void*)nativeGetActiveConfig },
+    {"nativeSetActiveConfig", "(Landroid/os/IBinder;I)Z",
+            (void*)nativeSetActiveConfig },
     {"nativeBlankDisplay", "(Landroid/os/IBinder;)V",
             (void*)nativeBlankDisplay },
     {"nativeUnblankDisplay", "(Landroid/os/IBinder;)V",
@@ -598,6 +629,9 @@
             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");
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index 77ede33..9258543 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -44,16 +44,11 @@
 } gRectClassInfo;
 
 static struct {
-    jfieldID mFinalizer;
-    jfieldID mNativeCanvas;
     jfieldID mSurfaceFormat;
+    jmethodID safeCanvasSwap;
 } gCanvasClassInfo;
 
 static struct {
-    jfieldID mNativeCanvas;
-} gCanvasFinalizerClassInfo;
-
-static struct {
     jfieldID nativeWindow;
 } gTextureViewClassInfo;
 
@@ -125,15 +120,6 @@
     }
 }
 
-static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
-    jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
-    SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
-          env->GetLongField(canvasObj, gCanvasClassInfo.mNativeCanvas));
-    env->SetLongField(canvasObj, gCanvasClassInfo.mNativeCanvas, (jlong)newCanvas);
-    env->SetLongField(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (jlong)newCanvas);
-    SkSafeUnref(previousCanvas);
-}
-
 static jboolean android_view_TextureView_lockCanvas(JNIEnv* env, jobject,
         jlong nativeWindow, jobject canvas, jobject dirtyRect) {
 
@@ -175,7 +161,7 @@
     SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer.format);
 
     SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
-    swapCanvasPtr(env, canvas, nativeCanvas);
+    INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
 
     SkRect clipRect;
     clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
@@ -193,7 +179,7 @@
         jlong nativeWindow, jobject canvas) {
 
     SkCanvas* nativeCanvas = SkNEW(SkCanvas);
-    swapCanvasPtr(env, canvas, nativeCanvas);
+    INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
 
     if (nativeWindow) {
         sp<ANativeWindow> window((ANativeWindow*) nativeWindow);
@@ -241,13 +227,8 @@
     GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I");
 
     FIND_CLASS(clazz, "android/graphics/Canvas");
-    GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer",
-            "Landroid/graphics/Canvas$CanvasFinalizer;");
-    GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
     GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I");
-
-    FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer");
-    GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
+    GET_METHOD_ID(gCanvasClassInfo.safeCanvasSwap, clazz, "safeCanvasSwap", "(JZ)V");
 
     FIND_CLASS(clazz, "android/view/TextureView");
     GET_FIELD_ID(gTextureViewClassInfo.nativeWindow, clazz, "mNativeWindow", "J");
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 58fc1e1..d130a6d 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -26,8 +26,11 @@
 #include <android_runtime/android_view_Surface.h>
 #include <system/window.h>
 
-#include "android_view_RenderNodeAnimator.h"
+#include "android_view_GraphicBuffer.h"
+
+#include <Animator.h>
 #include <RenderNode.h>
+#include <renderthread/CanvasContext.h>
 #include <renderthread/RenderProxy.h>
 #include <renderthread/RenderTask.h>
 #include <renderthread/RenderThread.h>
@@ -67,26 +70,54 @@
     jobject mRunnable;
 };
 
-class InvokeAnimationListeners : public MessageHandler {
+class SetAtlasTask : public RenderTask {
 public:
-    InvokeAnimationListeners(std::vector< sp<RenderNodeAnimator> >& animators) {
-        mAnimators.swap(animators);
+    SetAtlasTask(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size)
+            : mBuffer(buffer)
+            , mMap(map)
+            , mMapSize(size) {
     }
 
-    static void callOnFinished(const sp<RenderNodeAnimator>& animator) {
-        animator->callOnFinished();
-    }
-
-    virtual void handleMessage(const Message& message) {
-        std::for_each(mAnimators.begin(), mAnimators.end(), callOnFinished);
-        mAnimators.clear();
+    virtual void run() {
+        CanvasContext::setTextureAtlas(mBuffer, mMap, mMapSize);
+        mMap = 0;
+        delete this;
     }
 
 private:
-    std::vector< sp<RenderNodeAnimator> > mAnimators;
+    sp<GraphicBuffer> mBuffer;
+    int64_t* mMap;
+    size_t mMapSize;
 };
 
-class RootRenderNode : public RenderNode, public AnimationListener {
+class OnFinishedEvent {
+public:
+    OnFinishedEvent(BaseAnimator* animator, AnimationListener* listener)
+            : animator(animator), listener(listener) {}
+    sp<BaseAnimator> animator;
+    sp<AnimationListener> listener;
+};
+
+class InvokeAnimationListeners : public MessageHandler {
+public:
+    InvokeAnimationListeners(std::vector<OnFinishedEvent>& events) {
+        mOnFinishedEvents.swap(events);
+    }
+
+    static void callOnFinished(OnFinishedEvent& event) {
+        event.listener->onAnimationFinished(event.animator.get());
+    }
+
+    virtual void handleMessage(const Message& message) {
+        std::for_each(mOnFinishedEvents.begin(), mOnFinishedEvents.end(), callOnFinished);
+        mOnFinishedEvents.clear();
+    }
+
+private:
+    std::vector<OnFinishedEvent> mOnFinishedEvents;
+};
+
+class RootRenderNode : public RenderNode, public AnimationHook {
 public:
     RootRenderNode() : RenderNode() {
         mLooper = Looper::getForThread();
@@ -96,32 +127,41 @@
 
     virtual ~RootRenderNode() {}
 
-    void onAnimationFinished(const sp<RenderPropertyAnimator>& animator) {
-        mFinishedAnimators.push_back(
-                reinterpret_cast<RenderNodeAnimator*>(animator.get()));
+    virtual void callOnFinished(BaseAnimator* animator, AnimationListener* listener) {
+        OnFinishedEvent event(animator, listener);
+        mOnFinishedEvents.push_back(event);
     }
 
     virtual void prepareTree(TreeInfo& info) {
-        info.animationListener = this;
+        info.animationHook = this;
         RenderNode::prepareTree(info);
-        info.animationListener = NULL;
+        info.animationHook = NULL;
 
         // post all the finished stuff
-        if (mFinishedAnimators.size()) {
+        if (mOnFinishedEvents.size()) {
             sp<InvokeAnimationListeners> message
-                    = new InvokeAnimationListeners(mFinishedAnimators);
+                    = new InvokeAnimationListeners(mOnFinishedEvents);
             mLooper->sendMessage(message, 0);
         }
     }
 
 private:
     sp<Looper> mLooper;
-    std::vector< sp<RenderNodeAnimator> > mFinishedAnimators;
+    std::vector<OnFinishedEvent> mOnFinishedEvents;
 };
 
-static void android_view_ThreadedRenderer_postToRenderThread(JNIEnv* env, jobject clazz,
-        jobject jrunnable) {
-    RenderTask* task = new JavaTask(env, jrunnable);
+static void android_view_ThreadedRenderer_setAtlas(JNIEnv* env, jobject clazz,
+        jobject graphicBuffer, jlongArray atlasMapArray) {
+    sp<GraphicBuffer> buffer = graphicBufferForJavaObject(env, graphicBuffer);
+    jsize len = env->GetArrayLength(atlasMapArray);
+    if (len <= 0) {
+        ALOGW("Failed to initialize atlas, invalid map length: %d", len);
+        return;
+    }
+    int64_t* map = new int64_t[len];
+    env->GetLongArrayRegion(atlasMapArray, 0, len, map);
+
+    SetAtlasTask* task = new SetAtlasTask(buffer, map, len);
     RenderThread::getInstance().queue(task);
 }
 
@@ -144,6 +184,18 @@
     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 jboolean android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jobject jsurface) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
@@ -177,11 +229,17 @@
     proxy->setup(width, height);
 }
 
-static void android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jint dirtyLeft, jint dirtyTop,
+static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jboolean opaque) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    proxy->setOpaque(opaque);
+}
+
+static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jlong frameTimeNanos, jint dirtyLeft, jint dirtyTop,
         jint dirtyRight, jint dirtyBottom) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    proxy->syncAndDrawFrame(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
+    return proxy->syncAndDrawFrame(frameTimeNanos, dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
 }
 
 static void android_view_ThreadedRenderer_destroyCanvasAndSurface(JNIEnv* env, jobject clazz,
@@ -249,15 +307,18 @@
 
 static JNINativeMethod gMethods[] = {
 #ifdef USE_OPENGL_RENDERER
-    { "postToRenderThread", "(Ljava/lang/Runnable;)V",   (void*) android_view_ThreadedRenderer_postToRenderThread },
+    { "nSetAtlas", "(Landroid/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 },
     { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize },
     { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
     { "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface },
     { "nSetup", "(JII)V", (void*) android_view_ThreadedRenderer_setup },
-    { "nSyncAndDrawFrame", "(JIIII)V", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
+    { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
+    { "nSyncAndDrawFrame", "(JJIIII)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
     { "nDestroyCanvasAndSurface", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvasAndSurface },
     { "nInvokeFunctor", "(JJZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
     { "nRunWithGlContext", "(JLjava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_runWithGlContext },
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index a61fa87..c58bf04 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -92,14 +92,10 @@
     if (WIFEXITED(status)) {
       if (WEXITSTATUS(status)) {
         ALOGI("Process %d exited cleanly (%d)", pid, WEXITSTATUS(status));
-      } else if (false) {
-        ALOGI("Process %d exited cleanly (%d)", pid, WEXITSTATUS(status));
       }
     } else if (WIFSIGNALED(status)) {
       if (WTERMSIG(status) != SIGKILL) {
-        ALOGI("Process %d exited cleanly (%d)", pid, WTERMSIG(status));
-      } else if (false) {
-        ALOGI("Process %d exited cleanly (%d)", pid, WTERMSIG(status));
+        ALOGI("Process %d exited due to signal (%d)", pid, WTERMSIG(status));
       }
 #ifdef WCOREDUMP
       if (WCOREDUMP(status)) {
@@ -117,8 +113,10 @@
     }
   }
 
-  if (pid < 0) {
-    ALOGW("Zygote SIGCHLD error in waitpid: %d", errno);
+  // Note that we shouldn't consider ECHILD an error because
+  // the secondary zygote might have no children left to wait for.
+  if (pid < 0 && errno != ECHILD) {
+    ALOGW("Zygote SIGCHLD error in waitpid: %s", strerror(errno));
   }
 }
 
diff --git a/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
new file mode 100644
index 0000000..ce6f207
--- /dev/null
+++ b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+
+namespace android {
+
+static void incStrong(JNIEnv* env, jobject clazz, jlong objPtr) {
+    VirtualLightRefBase* obj = reinterpret_cast<VirtualLightRefBase*>(objPtr);
+    obj->incStrong(0);
+}
+
+static void decStrong(JNIEnv* env, jobject clazz, jlong objPtr) {
+    VirtualLightRefBase* obj = reinterpret_cast<VirtualLightRefBase*>(objPtr);
+    obj->decStrong(0);
+}
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+const char* const kClassPathName = "com/android/internal/util/VirtualRefBasePtr";
+
+static JNINativeMethod gMethods[] = {
+    { "nIncStrong", "(J)V", (void*) incStrong },
+    { "nDecStrong", "(J)V", (void*) decStrong },
+};
+
+int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv* env) {
+    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+
+} // namespace android
diff --git a/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp b/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
new file mode 100644
index 0000000..704e1be
--- /dev/null
+++ b/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+
+#include <Interpolator.h>
+
+namespace android {
+
+using namespace uirenderer;
+
+#ifdef USE_OPENGL_RENDERER
+
+static jlong createAccelerateDecelerateInterpolator(JNIEnv* env, jobject clazz) {
+    return reinterpret_cast<jlong>(new AccelerateDecelerateInterpolator());
+}
+
+static jlong createAccelerateInterpolator(JNIEnv* env, jobject clazz, jfloat factor) {
+    return reinterpret_cast<jlong>(new AccelerateInterpolator(factor));
+}
+
+static jlong createAnticipateInterpolator(JNIEnv* env, jobject clazz, jfloat tension) {
+    return reinterpret_cast<jlong>(new AnticipateInterpolator(tension));
+}
+
+static jlong createAnticipateOvershootInterpolator(JNIEnv* env, jobject clazz, jfloat tension) {
+    return reinterpret_cast<jlong>(new AnticipateOvershootInterpolator(tension));
+}
+
+static jlong createBounceInterpolator(JNIEnv* env, jobject clazz) {
+    return reinterpret_cast<jlong>(new BounceInterpolator());
+}
+
+static jlong createCycleInterpolator(JNIEnv* env, jobject clazz, jfloat cycles) {
+    return reinterpret_cast<jlong>(new CycleInterpolator(cycles));
+}
+
+static jlong createDecelerateInterpolator(JNIEnv* env, jobject clazz, jfloat factor) {
+    return reinterpret_cast<jlong>(new DecelerateInterpolator(factor));
+}
+
+static jlong createLinearInterpolator(JNIEnv* env, jobject clazz) {
+    return reinterpret_cast<jlong>(new LinearInterpolator());
+}
+
+static jlong createOvershootInterpolator(JNIEnv* env, jobject clazz, jfloat tension) {
+    return reinterpret_cast<jlong>(new OvershootInterpolator(tension));
+}
+
+static jlong createLutInterpolator(JNIEnv* env, jobject clazz, jfloatArray jlut) {
+    jsize len = env->GetArrayLength(jlut);
+    if (len <= 0) {
+        return 0;
+    }
+    float* lut = new float[len];
+    env->GetFloatArrayRegion(jlut, 0, len, lut);
+    return reinterpret_cast<jlong>(new LUTInterpolator(lut, len));
+}
+
+#endif
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+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 },
+    { "createAnticipateOvershootInterpolator", "(F)J", (void*) createAnticipateOvershootInterpolator },
+    { "createBounceInterpolator", "()J", (void*) createBounceInterpolator },
+    { "createCycleInterpolator", "(F)J", (void*) createCycleInterpolator },
+    { "createDecelerateInterpolator", "(F)J", (void*) createDecelerateInterpolator },
+    { "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));
+}
+
+
+} // namespace android
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4f093a8..cdb77f1 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1279,7 +1279,7 @@
          or recently running tasks. -->
     <permission android:name="android.permission.GET_TASKS"
         android:permissionGroup="android.permission-group.APP_INFO"
-        android:protectionLevel="dangerous"
+        android:protectionLevel="signature|system"
         android:label="@string/permlab_getTasks"
         android:description="@string/permdesc_getTasks" />
     <!-- @hide Allows an application to call APIs that allow it to do interactions
@@ -1295,10 +1295,9 @@
     <!-- @hide Fuller form of {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
          that removes restrictions on where broadcasts can be sent and allows other
          types of interactions. -->
-    <!-- TODO: Remove the system protection level.-->
     <permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature|system"
+        android:protectionLevel="signature"
         android:label="@string/permlab_interactAcrossUsersFull"
         android:description="@string/permdesc_interactAcrossUsersFull" />
 
@@ -2681,6 +2680,26 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
+        <activity android:name="com.android.internal.app.IntentForwarderActivity"
+                android:finishOnCloseSystemDialogs="true"
+                android:theme="@style/Theme.NoDisplay"
+                android:excludeFromRecents="true"
+                android:label="@string/user_owner_label"
+                android:exported="true"
+                >
+        </activity>
+        <activity-alias android:name="com.android.internal.app.ForwardIntentToUserOwner"
+                android:targetActivity="com.android.internal.app.IntentForwarderActivity"
+                android:icon="@drawable/personal_icon"
+                android:exported="true"
+                android:label="@string/user_owner_label">
+        </activity-alias>
+        <activity-alias android:name="com.android.internal.app.ForwardIntentToManagedProfile"
+                android:targetActivity="com.android.internal.app.IntentForwarderActivity"
+                android:icon="@drawable/work_icon"
+                android:exported="true"
+                android:label="@string/managed_profile_label">
+        </activity-alias>
         <activity android:name="com.android.internal.app.HeavyWeightSwitcherActivity"
                 android:theme="@style/Theme.Holo.Dialog"
                 android:label="@string/heavy_weight_switcher_title"
@@ -2773,7 +2792,7 @@
 
         <receiver android:name="com.android.server.BootReceiver"
                 android:primaryUserOnly="true">
-            <intent-filter>
+            <intent-filter android:priority="1000">
                 <action android:name="android.intent.action.BOOT_COMPLETED" />
             </intent-filter>
         </receiver>
diff --git a/core/res/res/anim/button_state_list_anim_quantum.xml b/core/res/res/anim/button_state_list_anim_quantum.xml
new file mode 100644
index 0000000..01989a4
--- /dev/null
+++ b/core/res/res/anim/button_state_list_anim_quantum.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" android:state_enabled="true">
+        <set>
+            <objectAnimator android:propertyName="translationZ"
+                            android:duration="@integer/button_pressed_animation_duration"
+                            android:valueTo="@dimen/button_pressed_z"
+                            android:valueType="floatType"/>
+        </set>
+    </item>
+    <!-- base state -->
+    <item>
+        <set>
+            <objectAnimator android:propertyName="translationZ"
+                            android:duration="@integer/button_pressed_animation_duration"
+                            android:valueTo="0"
+                            android:valueType="floatType"/>
+        </set>
+    </item>
+</selector>
\ No newline at end of file
diff --git a/core/res/res/anim/popup_enter_quantum.xml b/core/res/res/anim/popup_enter_quantum.xml
new file mode 100644
index 0000000..79de26b
--- /dev/null
+++ b/core/res/res/anim/popup_enter_quantum.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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shareInterpolator="false" >
+    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+           android:interpolator="@interpolator/decelerate_cubic"
+           android:duration="@android:integer/config_activityShortDur" />
+</set>
diff --git a/core/res/res/anim/popup_exit_quantum.xml b/core/res/res/anim/popup_exit_quantum.xml
new file mode 100644
index 0000000..7d7d5c5
--- /dev/null
+++ b/core/res/res/anim/popup_exit_quantum.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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shareInterpolator="false" >
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+           android:interpolator="@interpolator/decelerate_cubic"
+           android:duration="@android:integer/config_activityShortDur"/>
+</set>
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00000_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..1880a15
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00001_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..aecb4d2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00002_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..8401f91
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00003_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..5832865
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00004_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..6d14962
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00005_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..aee057c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00006_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..fb5801e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00007_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..fdb5271
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00008_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..b8c7397
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00009_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..d0395a8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00010_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..59bb437
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00011_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..c053b90
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00012_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..eb30a79
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00013_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..1af0bff
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00014_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..3b36e7d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00015_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..c12d20a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00000_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..882365b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00001_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..f6c7094
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00002_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..0e326c9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00003_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..8bf1170
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00004_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..cedb66e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00005_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..257d7ba
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00006_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..e07b36e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00007_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..ef94200
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00008_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..ad67004
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00009_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..50796e2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00010_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..ba7be9e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00011_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..bdbfe78
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00012_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..fe89951
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00013_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..840c88f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00014_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..621d1d2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00015_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..fd8be89
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/personal_icon.png b/core/res/res/drawable-hdpi/personal_icon.png
new file mode 100644
index 0000000..8d96b5e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/personal_icon.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_off_qntm_alpha.png b/core/res/res/drawable-hdpi/scrubber_control_off_qntm_alpha.png
index f1023ea..5a99528 100644
--- a/core/res/res/drawable-hdpi/scrubber_control_off_qntm_alpha.png
+++ b/core/res/res/drawable-hdpi/scrubber_control_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_on_qntm_alpha.png b/core/res/res/drawable-hdpi/scrubber_control_on_qntm_alpha.png
index 15ceeee..79de664 100644
--- a/core/res/res/drawable-hdpi/scrubber_control_on_qntm_alpha.png
+++ b/core/res/res/drawable-hdpi/scrubber_control_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_adb_am.png b/core/res/res/drawable-hdpi/stat_sys_adb_am.png
deleted file mode 100644
index dad614c..0000000
--- a/core/res/res/drawable-hdpi/stat_sys_adb_am.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_off_qntm_alpha.9.png b/core/res/res/drawable-hdpi/switch_off_qntm_alpha.9.png
index 90b1498..73e8f1c 100644
--- a/core/res/res/drawable-hdpi/switch_off_qntm_alpha.9.png
+++ b/core/res/res/drawable-hdpi/switch_off_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_on_qntm_alpha.9.png b/core/res/res/drawable-hdpi/switch_on_qntm_alpha.9.png
index b535758..ff6affe 100644
--- a/core/res/res/drawable-hdpi/switch_on_qntm_alpha.9.png
+++ b/core/res/res/drawable-hdpi/switch_on_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/work_icon.png b/core/res/res/drawable-hdpi/work_icon.png
new file mode 100644
index 0000000..e90866b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/work_icon.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_sys_adb_am.png b/core/res/res/drawable-ldpi/stat_sys_adb_am.png
deleted file mode 100644
index 0171adb..0000000
--- a/core/res/res/drawable-ldpi/stat_sys_adb_am.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00000_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..0f44ff9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00001_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..9d5dda0
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00002_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..e4ce802
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00003_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..d1806ac
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00004_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..ab9315b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00005_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..46e90e6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00006_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..e8c56ff
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00007_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..59dcb7e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00008_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..e9bd4a2
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00009_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..1d05037
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00010_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..91b40de
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00011_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..c531cab
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00012_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..11bb387
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00013_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..8843210
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00014_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..6ff2f3d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00015_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..a03c1e2
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00000_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..0a22e1a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00001_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..2e2469c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00002_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..c1054d9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00003_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..cf8d80a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00004_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..9d9e870
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00005_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..1bad701
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00006_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..a84a54f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00007_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..4d8050b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00008_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..374172c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00009_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..233036e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00010_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..61d9b58
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00011_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..274e983
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00012_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..acf16e5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00013_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..ee48241
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00014_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..dbbb736
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00015_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..bcabd0d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_off_qntm_alpha.png b/core/res/res/drawable-mdpi/scrubber_control_off_qntm_alpha.png
index 1833704..e40cba8 100644
--- a/core/res/res/drawable-mdpi/scrubber_control_off_qntm_alpha.png
+++ b/core/res/res/drawable-mdpi/scrubber_control_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_on_qntm_alpha.png b/core/res/res/drawable-mdpi/scrubber_control_on_qntm_alpha.png
index e64d3f2..437a3e3 100644
--- a/core/res/res/drawable-mdpi/scrubber_control_on_qntm_alpha.png
+++ b/core/res/res/drawable-mdpi/scrubber_control_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_adb_am.png b/core/res/res/drawable-mdpi/stat_sys_adb_am.png
deleted file mode 100644
index 5482f34..0000000
--- a/core/res/res/drawable-mdpi/stat_sys_adb_am.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_off_qntm_alpha.9.png b/core/res/res/drawable-mdpi/switch_off_qntm_alpha.9.png
index ffd6c39..8949b52 100644
--- a/core/res/res/drawable-mdpi/switch_off_qntm_alpha.9.png
+++ b/core/res/res/drawable-mdpi/switch_off_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_on_qntm_alpha.9.png b/core/res/res/drawable-mdpi/switch_on_qntm_alpha.9.png
index 15faff0..d727683 100644
--- a/core/res/res/drawable-mdpi/switch_on_qntm_alpha.9.png
+++ b/core/res/res/drawable-mdpi/switch_on_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.png b/core/res/res/drawable-nodpi/platlogo.png
deleted file mode 100644
index 6351c2d..0000000
--- a/core/res/res/drawable-nodpi/platlogo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml
new file mode 100644
index 0000000..668cff7
--- /dev/null
+++ b/core/res/res/drawable-nodpi/platlogo.xml
@@ -0,0 +1,38 @@
+<!--
+    Copyright (C) 2014 The Android Open Source Project
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at"+
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size android:width="400dp" android:height="400dp"/>
+
+    <viewport android:viewportHeight="25" android:viewportWidth="25" />
+
+    <path
+        android:name="shadow"
+        android:pathData="m12,2.5 a11,11 0 1,0 1,0
+        M6.5,7.5
+        l5,0 l0,7 l7,0 l0,5 l-12,0 z"
+        android:fill="#40000000"
+        />
+    <path
+        android:name="circle-L-ranch"
+        android:pathData="m12,1.5 a11,11 0 1,0 1,0
+        M6.5,6.5
+        l5,0 l0,7 l7,0 l0,5 l-12,0 z"
+        android:fill="#FFFFFF40"
+        />
+
+</vector>
+
+
diff --git a/core/res/res/drawable-nodpi/stat_sys_adb.xml b/core/res/res/drawable-nodpi/stat_sys_adb.xml
new file mode 100644
index 0000000..b8ddb77
--- /dev/null
+++ b/core/res/res/drawable-nodpi/stat_sys_adb.xml
@@ -0,0 +1,30 @@
+<!--
+    Copyright (C) 2014 The Android Open Source Project
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at"+
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size android:width="25dp" android:height="25dp"/>
+
+    <viewport android:viewportHeight="25" android:viewportWidth="25" />
+
+
+    <path
+        android:name="adb"
+        android:pathData="m3,3l8,0l0,11l11,0l0,8l-19,0z"
+        android:fill="#FFFFFFFF"
+        />
+
+</vector>
+
+
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00000_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..25500e8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00001_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..b136e25
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00002_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..6a94e30
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00003_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..d386421
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00004_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..c811385
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00005_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..58b3267
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00006_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..0659e72
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00007_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..b4227d1
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00008_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..714ef00
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00009_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..139595b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00010_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..4491107
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00011_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..20eb752
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00012_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..532c9f2
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00013_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..0d78a32
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00014_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..af29678
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00015_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..23eb9e3
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00000_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..cd11e14
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00001_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..b10db83
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00002_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..efeb6fb
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00003_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..83080af
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00004_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..b9cc322
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00005_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..3b5f9c4
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00006_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..58c93db
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00007_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..0f1d010
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00008_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..05a7a0f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00009_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..9345035
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00010_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..5f149b7
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00011_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..191f369
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00012_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..44e08e6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00013_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..5a9dfa0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00014_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..ee921c6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00015_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..567bb0c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_off_qntm_alpha.png b/core/res/res/drawable-xhdpi/scrubber_control_off_qntm_alpha.png
index ad72f06..729e0bf 100644
--- a/core/res/res/drawable-xhdpi/scrubber_control_off_qntm_alpha.png
+++ b/core/res/res/drawable-xhdpi/scrubber_control_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_on_qntm_alpha.png b/core/res/res/drawable-xhdpi/scrubber_control_on_qntm_alpha.png
index 7aceed1..d018a7c 100644
--- a/core/res/res/drawable-xhdpi/scrubber_control_on_qntm_alpha.png
+++ b/core/res/res/drawable-xhdpi/scrubber_control_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_adb_am.png b/core/res/res/drawable-xhdpi/stat_sys_adb_am.png
deleted file mode 100644
index e53f498..0000000
--- a/core/res/res/drawable-xhdpi/stat_sys_adb_am.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_off_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/switch_off_qntm_alpha.9.png
index 309b528..a7a972c 100644
--- a/core/res/res/drawable-xhdpi/switch_off_qntm_alpha.9.png
+++ b/core/res/res/drawable-xhdpi/switch_off_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_on_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/switch_on_qntm_alpha.9.png
index 139795e..dd8910b 100644
--- a/core/res/res/drawable-xhdpi/switch_on_qntm_alpha.9.png
+++ b/core/res/res/drawable-xhdpi/switch_on_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00000_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..1881f54
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00001_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..6f8ec2d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00002_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..c954ed9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00003_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..9d1a47e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00004_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..ce63631
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00005_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..430c134
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00006_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..cdebf83
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00007_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..40ceadb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00008_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..fb13eb2
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00009_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..d716fba
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00010_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..b8be041
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00011_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..bad0c3c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00012_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..a6368fb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00013_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..234e5d1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00014_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..3e7796d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00015_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..0673999
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00000_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..4779944
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00001_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..866f7b7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00002_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..76aae57
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00003_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..0cd470a1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00004_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..0015b39
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00005_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..2f69f5b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00006_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..77142fd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00007_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..2f81277
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00008_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..d37fe60
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00009_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..cb62079
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00010_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..82dc428
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00011_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..2cba2fb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00012_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..5de1952
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00013_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..1c22a17
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00014_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..7f652fc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00015_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..076acbd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_off_qntm_alpha.png b/core/res/res/drawable-xxhdpi/scrubber_control_off_qntm_alpha.png
index c11b0ae..a2b5716 100644
--- a/core/res/res/drawable-xxhdpi/scrubber_control_off_qntm_alpha.png
+++ b/core/res/res/drawable-xxhdpi/scrubber_control_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_on_qntm_alpha.png b/core/res/res/drawable-xxhdpi/scrubber_control_on_qntm_alpha.png
index cde797e..caabc2c 100644
--- a/core/res/res/drawable-xxhdpi/scrubber_control_on_qntm_alpha.png
+++ b/core/res/res/drawable-xxhdpi/scrubber_control_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png b/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
deleted file mode 100644
index d6018dd..0000000
--- a/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_off_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/switch_off_qntm_alpha.9.png
index 9e234af..8d79a13 100644
--- a/core/res/res/drawable-xxhdpi/switch_off_qntm_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/switch_off_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_on_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/switch_on_qntm_alpha.9.png
index b371eab..e0e4ef9 100644
--- a/core/res/res/drawable-xxhdpi/switch_on_qntm_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/switch_on_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_quantum_anim.xml b/core/res/res/drawable/btn_check_quantum_anim.xml
index 0600522..96715a4 100644
--- a/core/res/res/drawable/btn_check_quantum_anim.xml
+++ b/core/res/res/drawable/btn_check_quantum_anim.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!-- Copyright (C) 2014 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,67 +14,92 @@
      limitations under the License.
 -->
 
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:trigger="state_checked"
-    android:versionCode="1" >
+<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false" android:state_checked="true">
+        <bitmap android:src="@drawable/btn_check_anim_00015_qntm_alpha"
+            android:tint="?attr/colorControlActivated"
+            android:alpha="?attr/disabledAlpha" />
+    </item>
+    <item android:state_enabled="false">
+        <bitmap android:src="@drawable/btn_check_anim_00000_qntm_alpha"
+            android:tint="?attr/colorControlNormal"
+            android:alpha="?attr/disabledAlpha" />
+    </item>
+    <item android:state_checked="true" android:id="@+id/on">
+        <bitmap android:src="@drawable/btn_check_anim_00015_qntm_alpha"
+            android:tint="?attr/colorControlActivated" />
+    </item>
+    <item android:id="@+id/off">
+        <bitmap android:src="@drawable/btn_check_anim_00000_qntm_alpha"
+            android:tint="?attr/colorControlNormal" />
+    </item>
+    <transition android:fromId="@+id/off" android:toId="@+id/on" android:reversible="true">
+        <animation-list>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00000_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00001_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00002_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00003_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00004_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00005_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00006_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00007_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00008_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00009_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00010_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00011_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00012_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00013_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00014_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00015_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+        </animation-list>
+    </transition>
+</animated-selector>
 
-    <size
-        android:height="32dp"
-        android:width="32dp" />
-
-    <viewport
-        android:viewportHeight="320"
-        android:viewportWidth="320" />
-
-    <group>
-        <path
-            android:name="box1"
-            android:pathData="M 240,80 L 240,240 L 80,240 L 80,80 L 240,80 L 240,80 z"
-            android:stroke="?attr/colorControlNormal"
-            android:strokeWidth="20"
-            android:strokeLineCap="round"
-            android:strokeLineJoin="round" />
-    </group>
-    <group>
-        <path
-            android:name="box2"
-            android:pathData="M 160,200 L 160,240 L 120,240 L 120,200 L 160,200 L 160,200 z"
-            android:stroke="?attr/colorControlNormal"
-            android:strokeWidth="10"
-            android:strokeLineCap="round"
-            android:strokeLineJoin="round" />
-    </group>
-    <group>
-        <path
-            android:name="box3"
-            android:pathData="M 160,216.5 L 143.5,240 L 120,223.5 L 136.5,200 L 160,216.5 L 160,216.5 z"
-            android:rotation="35"
-            android:pivotX="140"
-            android:pivotY="220"
-            android:fill="?attr/colorControlNormal"
-            android:stroke="?attr/colorControlNormal"
-            android:strokeWidth="5"
-            android:strokeLineCap="round"
-            android:strokeLineJoin="round" />
-    </group>
-    <group>
-        <path
-            android:name="box4"
-            android:pathData="M 160,216.5 L 143.5,240 L 120,223.5 L 136.5,200 L 160,216.5 L 160,216.5 z"
-            android:fill="?attr/colorControlActivated"
-            android:stroke="?attr/colorControlActivated"
-            android:strokeLineCap="round"
-            android:strokeLineJoin="round" />
-    </group>
-    <group>
-        <path
-            android:name="check"
-            android:pathData="M 232.1,80.6 L 248.5,92.1 L 145.2,239.5 L 71.5,187.8 L 83,171.5 L 140.3,211.7 z"
-            android:fill="?attr/colorControlActivated" />
-    </group>
-
-    <animation
-        android:durations="300,100,0,300"
-        android:sequence="box1,box2,box3,box4,check" />
-
-</vector>
diff --git a/core/res/res/drawable/btn_color_quantum.xml b/core/res/res/drawable/btn_color_quantum.xml
deleted file mode 100644
index 2da9226..0000000
--- a/core/res/res/drawable/btn_color_quantum.xml
+++ /dev/null
@@ -1,30 +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.
--->
-
-<touch-feedback xmlns:android="http://schemas.android.com/apk/res/android"
-    android:tint="?attr/colorButtonPressedColored">
-    <selector>
-        <item android:state_enabled="false">
-            <nine-patch android:src="@drawable/btn_qntm_alpha"
-                android:tint="?attr/colorButtonNormal"
-                android:alpha="?attr/disabledAlpha" />
-        </item>
-        <item>
-            <nine-patch android:src="@drawable/btn_qntm_alpha"
-                android:tint="?attr/colorButtonNormalColored" />
-        </item>
-    </selector>
-</touch-feedback>
diff --git a/core/res/res/drawable/btn_radio_quantum_anim.xml b/core/res/res/drawable/btn_radio_quantum_anim.xml
new file mode 100644
index 0000000..5068b7a
--- /dev/null
+++ b/core/res/res/drawable/btn_radio_quantum_anim.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false" android:state_checked="true">
+        <bitmap android:src="@drawable/btn_radio_anim_00015_qntm_alpha"
+            android:tint="?attr/colorControlActivated"
+            android:alpha="?attr/disabledAlpha" />
+    </item>
+    <item android:state_enabled="false">
+        <bitmap android:src="@drawable/btn_radio_anim_00000_qntm_alpha"
+            android:tint="?attr/colorControlNormal"
+            android:alpha="?attr/disabledAlpha" />
+    </item>
+    <item android:state_checked="true" android:id="@+id/on">
+        <bitmap android:src="@drawable/btn_radio_anim_00015_qntm_alpha"
+            android:tint="?attr/colorControlActivated" />
+    </item>
+    <item android:id="@+id/off">
+        <bitmap android:src="@drawable/btn_radio_anim_00000_qntm_alpha"
+            android:tint="?attr/colorControlNormal" />
+    </item>
+    <transition android:fromId="@+id/off" android:toId="@+id/on" android:reversible="true">
+        <animation-list>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00000_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00001_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00002_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00003_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00004_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00005_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00006_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00007_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00008_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00009_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00010_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00011_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00012_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00013_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00014_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00015_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+        </animation-list>
+    </transition>
+</animated-selector>
diff --git a/core/res/res/drawable/notification_icon_legacy_bg.xml b/core/res/res/drawable/notification_icon_legacy_bg.xml
index 4ac67c3..cc5755d 100644
--- a/core/res/res/drawable/notification_icon_legacy_bg.xml
+++ b/core/res/res/drawable/notification_icon_legacy_bg.xml
@@ -18,5 +18,5 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="oval">
     <solid
-            android:color="@color/notification_icon_legacy_bg_color"/>
+            android:color="@color/notification_icon_bg_color"/>
 </shape>
diff --git a/core/res/res/drawable/popup_background_quantum.xml b/core/res/res/drawable/popup_background_quantum.xml
new file mode 100644
index 0000000..7e5b003
--- /dev/null
+++ b/core/res/res/drawable/popup_background_quantum.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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+
+    <corners
+        android:radius="2dp" />
+    <solid
+        android:color="?attr/colorBackground" />
+
+</shape>
diff --git a/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml b/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml
index d172b05..f82fe7a 100644
--- a/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml
+++ b/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml
@@ -16,22 +16,26 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false">
-        <bitmap android:src="@drawable/scrubber_track_qntm_alpha"
+        <nine-patch android:src="@drawable/scrubber_track_qntm_alpha"
             android:tint="?attr/colorControlNormal" />
     </item>
     <item>
         <layer-list>
             <item android:id="@id/background">
-                <bitmap android:src="@drawable/scrubber_track_qntm_alpha"
+                <nine-patch android:src="@drawable/scrubber_track_qntm_alpha"
                     android:tint="?attr/colorControlNormal" />
             </item>
             <item android:id="@id/secondaryProgress">
-                <bitmap android:src="@drawable/scrubber_primary_qntm_alpha"
-                    android:tint="?attr/colorControlNormal" />
+                <scale android:scaleWidth="100%">
+                    <nine-patch android:src="@drawable/scrubber_primary_qntm_alpha"
+                        android:tint="?attr/colorControlNormal" />
+                </scale>
             </item>
             <item android:id="@id/progress">
-                <bitmap android:src="@drawable/scrubber_primary_qntm_alpha"
-                    android:tint="?attr/colorControlActivated" />
+                <scale android:scaleWidth="100%">
+                    <nine-patch android:src="@drawable/scrubber_primary_qntm_alpha"
+                        android:tint="?attr/colorControlActivated" />
+                </scale>
             </item>
         </layer-list>
     </item>
diff --git a/core/res/res/drawable/stat_sys_adb.xml b/core/res/res/drawable/stat_sys_adb.xml
deleted file mode 100644
index dfc8563..0000000
--- a/core/res/res/drawable/stat_sys_adb.xml
+++ /dev/null
@@ -1,23 +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.
- */
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-        android:src="@drawable/stat_sys_adb_am"
-        android:autoMirrored="true">
-</bitmap>
diff --git a/core/res/res/layout-xlarge/screen_action_bar.xml b/core/res/res/layout-xlarge/screen_action_bar.xml
index d2fe9fa..02c99fe 100644
--- a/core/res/res/layout-xlarge/screen_action_bar.xml
+++ b/core/res/res/layout-xlarge/screen_action_bar.xml
@@ -34,7 +34,7 @@
         android:layout_height="wrap_content"
         android:layout_alignParentTop="true"
         style="?android:attr/actionBarStyle"
-        android:sharedElementName="android:action_bar"
+        android:viewName="android:action_bar"
         android:gravity="top">
         <com.android.internal.widget.ActionBarView
             android:id="@+id/action_bar"
diff --git a/core/res/res/layout/alert_dialog_leanback.xml b/core/res/res/layout/alert_dialog_leanback.xml
new file mode 100644
index 0000000..8655aea
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_leanback.xml
@@ -0,0 +1,131 @@
+<?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
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/parentPanel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginLeft="@dimen/leanback_alert_dialog_horizontal_margin"
+    android:layout_marginRight="@dimen/leanback_alert_dialog_horizontal_margin"
+    android:layout_marginTop="@dimen/leanback_alert_dialog_vertical_margin"
+    android:layout_marginBottom="@dimen/leanback_alert_dialog_vertical_margin"
+    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:minHeight="@dimen/alert_dialog_title_height"
+            android:layout_marginStart="16dip"
+            android:layout_marginEnd="16dip">
+            <ImageView android:id="@+id/icon"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingEnd="8dip"
+                android:src="@null" />
+            <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
+                style="?android: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>
+
+    <LinearLayout android:id="@+id/contentPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:minHeight="64dp">
+        <ScrollView android:id="@+id/scrollView"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:clipToPadding="false">
+            <TextView android:id="@+id/message"
+                style="?android:attr/textAppearanceMedium"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:paddingStart="16dip"
+                android:paddingEnd="16dip"
+                android:paddingTop="8dip"
+                android:paddingBottom="8dip"/>
+        </ScrollView>
+    </LinearLayout>
+
+    <FrameLayout android:id="@+id/customPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:minHeight="64dp">
+        <FrameLayout android:id="@+android:id/custom"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+    </FrameLayout>
+
+    <LinearLayout android:id="@+id/buttonPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="@dimen/alert_dialog_button_bar_height"
+        android:orientation="vertical">
+        <LinearLayout
+            style="?android:attr/buttonBarStyle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:layoutDirection="locale"
+            android:measureWithLargestChild="true">
+            <Button android:id="@+id/button2"
+                android:layout_width="wrap_content"
+                android:layout_gravity="start"
+                android:layout_weight="1"
+                android:maxLines="2"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                android:layout_height="wrap_content" />
+            <Button android:id="@+id/button3"
+                android:layout_width="wrap_content"
+                android:layout_gravity="center_horizontal"
+                android:layout_weight="1"
+                android:maxLines="2"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                android:layout_height="wrap_content" />
+            <Button android:id="@+id/button1"
+                android:layout_width="wrap_content"
+                android:layout_gravity="end"
+                android:layout_weight="1"
+                android:maxLines="2"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:layout_height="wrap_content" />
+        </LinearLayout>
+     </LinearLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/alert_dialog_leanback_button_panel_right.xml b/core/res/res/layout/alert_dialog_leanback_button_panel_right.xml
new file mode 100644
index 0000000..096b015
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_leanback_button_panel_right.xml
@@ -0,0 +1,142 @@
+<?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
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/parentPanel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginLeft="@dimen/leanback_alert_dialog_horizontal_margin"
+    android:layout_marginRight="@dimen/leanback_alert_dialog_horizontal_margin"
+    android:layout_marginTop="@dimen/leanback_alert_dialog_vertical_margin"
+    android:layout_marginBottom="@dimen/leanback_alert_dialog_vertical_margin"
+    android:orientation="horizontal">
+
+  <LinearLayout
+      android:id="@+id/leftPanel"
+      android:layout_width="0dp"
+      android:layout_weight="0.66"
+      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:minHeight="@dimen/alert_dialog_title_height"
+            android:layout_marginStart="16dip"
+            android:layout_marginEnd="16dip">
+            <ImageView android:id="@+id/icon"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingEnd="8dip"
+                android:src="@null" />
+            <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
+                style="?android: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>
+
+    <LinearLayout android:id="@+id/contentPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:minHeight="64dp">
+        <ScrollView android:id="@+id/scrollView"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:clipToPadding="false">
+            <TextView android:id="@+id/message"
+                style="?android:attr/textAppearanceMedium"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:paddingStart="16dip"
+                android:paddingEnd="16dip"
+                android:paddingTop="8dip"
+                android:paddingBottom="8dip"/>
+        </ScrollView>
+    </LinearLayout>
+
+    <FrameLayout android:id="@+id/customPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:minHeight="64dp">
+        <FrameLayout android:id="@+android:id/custom"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+    </FrameLayout>
+  </LinearLayout>
+
+    <LinearLayout android:id="@+id/buttonPanel"
+        android:layout_width="0dp"
+	android:layout_weight="0.33"
+        android:layout_height="match_parent"
+        android:minHeight="@dimen/alert_dialog_button_bar_height"
+	android:paddingLeft="32dp"
+	android:paddingRight="32dp"
+        android:orientation="horizontal">
+        <LinearLayout
+            style="?android:attr/buttonBarStyle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+	    android:layout_gravity="center_vertical"
+            android:orientation="vertical"
+            android:layoutDirection="locale"
+            android:measureWithLargestChild="true">
+            <Button android:id="@+id/button1"
+                android:layout_width="match_parent"
+                android:gravity="center_vertical"
+                android:layout_weight="1"
+                android:maxLines="2"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                android:layout_height="wrap_content" />
+            <Button android:id="@+id/button3"
+                android:layout_width="match_parent"
+                android:gravity="center_vertical"
+                android:layout_weight="1"
+                android:maxLines="2"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                android:layout_height="wrap_content" />
+            <Button android:id="@+id/button2"
+                android:layout_width="match_parent"
+                android:gravity="center_vertical"
+                android:layout_weight="1"
+                android:maxLines="2"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:layout_height="wrap_content" />
+        </LinearLayout>
+     </LinearLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/alert_dialog_micro.xml b/core/res/res/layout/alert_dialog_micro.xml
new file mode 100644
index 0000000..abdbd16
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_micro.xml
@@ -0,0 +1,140 @@
+<?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:id="@+id/parentPanel"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@android:color/white"
+    android:layout_gravity="center"
+    android:orientation="vertical">
+
+    <LinearLayout android:id="@+id/topPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+        <View android:id="@+id/titleDividerTop"
+            android:layout_width="match_parent"
+            android:layout_height="2dip"
+            android:visibility="gone"
+            android:background="@android:color/holo_blue_light" />
+        <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:minHeight="@dimen/alert_dialog_title_height"
+            android:layout_marginStart="16dip"
+            android:layout_marginEnd="16dip">
+            <ImageView android:id="@+id/icon"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingEnd="8dip"
+                android:src="@null" />
+            <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
+                style="?android:attr/windowTitleStyle"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textAlignment="viewStart" />
+        </LinearLayout>
+        <View android:id="@+id/titleDivider"
+            android:layout_width="match_parent"
+            android:layout_height="2dip"
+            android:visibility="gone"
+            android:background="@android:color/holo_blue_light" />
+        <!-- If the client uses a customTitle, it will be added here. -->
+    </LinearLayout>
+
+    <LinearLayout android:id="@+id/contentPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:minHeight="64dp">
+        <ScrollView android:id="@+id/scrollView"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:clipToPadding="false">
+            <TextView android:id="@+id/message"
+                style="?android:attr/textAppearanceMedium"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:paddingStart="16dip"
+                android:paddingEnd="16dip"
+                android:paddingTop="8dip"
+                android:paddingBottom="8dip"/>
+        </ScrollView>
+    </LinearLayout>
+
+    <FrameLayout android:id="@+id/customPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:minHeight="64dp">
+        <FrameLayout android:id="@+android:id/custom"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+    </FrameLayout>
+
+    <LinearLayout android:id="@+id/buttonPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="@dimen/alert_dialog_button_bar_height"
+        android:orientation="vertical"
+        android:divider="?android:attr/dividerHorizontal"
+        android:showDividers="beginning"
+        android:dividerPadding="0dip">
+        <LinearLayout
+            style="?android:attr/buttonBarStyle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:layoutDirection="locale"
+            android:measureWithLargestChild="true">
+            <Button android:id="@+id/button2"
+                android:layout_width="wrap_content"
+                android:layout_gravity="start"
+                android:layout_weight="1"
+                android:maxLines="2"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                android:layout_height="wrap_content" />
+            <Button android:id="@+id/button3"
+                android:layout_width="wrap_content"
+                android:layout_gravity="center_horizontal"
+                android:layout_weight="1"
+                android:maxLines="2"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                android:layout_height="wrap_content" />
+            <Button android:id="@+id/button1"
+                android:layout_width="wrap_content"
+                android:layout_gravity="end"
+                android:layout_weight="1"
+                android:maxLines="2"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:layout_height="wrap_content" />
+        </LinearLayout>
+     </LinearLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/progress_dialog_leanback.xml b/core/res/res/layout/progress_dialog_leanback.xml
new file mode 100644
index 0000000..6bcad7a
--- /dev/null
+++ b/core/res/res/layout/progress_dialog_leanback.xml
@@ -0,0 +1,48 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="2dip"
+        android:background="@android:color/leanback_dark_gray" />
+    <LinearLayout android:id="@+id/body"
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:baselineAligned="false"
+        android:padding="16dip">
+
+        <ProgressBar android:id="@android:id/progress"
+            style="?android:attr/progressBarStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:max="10000"
+            android:layout_marginEnd="16dip" />
+
+        <TextView android:id="@+id/message"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/screen_action_bar.xml b/core/res/res/layout/screen_action_bar.xml
index 77f537b..eb237b3 100644
--- a/core/res/res/layout/screen_action_bar.xml
+++ b/core/res/res/layout/screen_action_bar.xml
@@ -34,7 +34,7 @@
         android:layout_height="wrap_content"
         android:layout_alignParentTop="true"
         style="?attr/actionBarStyle"
-        android:sharedElementName="android:action_bar"
+        android:viewName="android:action_bar"
         android:gravity="top">
         <com.android.internal.widget.ActionBarView
             android:id="@+id/action_bar"
diff --git a/core/res/res/layout/screen_custom_title.xml b/core/res/res/layout/screen_custom_title.xml
index d02cc8b..c8952bf 100644
--- a/core/res/res/layout/screen_custom_title.xml
+++ b/core/res/res/layout/screen_custom_title.xml
@@ -31,7 +31,7 @@
     <FrameLayout android:id="@android:id/title_container" 
         android:layout_width="match_parent" 
         android:layout_height="?android:attr/windowTitleSize"
-        android:sharedElementName="android:title"
+        android:viewName="android:title"
         style="?android:attr/windowTitleBackgroundStyle">
     </FrameLayout>
     <FrameLayout android:id="@android:id/content"
diff --git a/core/res/res/layout/voice_interaction_session.xml b/core/res/res/layout/voice_interaction_session.xml
new file mode 100644
index 0000000..48b6579
--- /dev/null
+++ b/core/res/res/layout/voice_interaction_session.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/layout/alert_dialog.xml
+**
+** 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.
+*/
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+</FrameLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index eb68c39..6809000 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinkroniseer"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Te veel <xliff:g id="CONTENT_TYPE">%s</xliff:g> uitgevee."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Tablet se berging is vol. Vee \'n aantal lêers uit om spasie vry te maak."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Horlosieberging is vol! Vee \'n paar lêers uit om plek te maak."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Foon se berging is vol. Vee \'n aantal lêers uit om spasie vry te maak."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netwerk kan dalk gemonitor word"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Deur \'n onbekende derde party"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Luitoestel aan"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Sit tans af…"</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Jou tablet gaan nou afskakel."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Jou horlosie gaan nou afskakel."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Jou foon gaan nou afsit."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Wil jy afskakel?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Herlaai na veilige modus"</string>
@@ -173,7 +171,6 @@
     <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 AF"</string>
-    <string name="global_action_settings" msgid="1756531602592545966">"Instellings"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Veiligmodus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-stelsel"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"deïnstalleer kortpaaie"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Laat die program toe om Tuisskerm-kortpaaie te verwyder sonder gebruikerinmenging."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"herlei uitgaande oproepe"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Laat die program toe om te sien watter nommer tydens \'n uitgaande oproep geskakel word, met die opsie om die oproep na \'n ander nommer te herlei of die oproep heeltemal te beëindig."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Laat die program toe om uitgaande oproepe te verwerk en die nommer wat geskakel moet word te verander. Hierdie toestemming laat die program toe om uitgaande oproepe te monitor, herlei, of te voorkom."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"ontvang teksboodskappe (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Laat die program toe om SMS-boodskappe te ontvang en te verwerk. Dit beteken dat die program boodskappe wat na jou toestel gestuur is, kan monitor of uitvee, sonder dat jy dit gesien het."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"ontvang teksboodskappe (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Laat die program toe om die inhoud van die aktiewe venster op te haal. Kwaadwillige programme kan die hele venster se inhoud ophaal, en al die teks ondersoek, behalwe wagwoorde."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"aktiveer toeganklikheid tydelik"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Laat \'n program toe om toeganklikheid tydelik op die toestel te aktiveer. Kwaadwillige programme kan sonder die toestemming van die gebruiker toeganklikheid verkry."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"haal vensterteken"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Laat \'n program toe om die vensterteken te gaan haal. Kwaadwillige programme kan dalk ongemagtigde interaksie met die programvenster uitvoer deur die stelsel te verpersoonlik."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"haal raamstatistiek"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Laat \'n program toe om raamstatistiek in te samel. Kwaadwillige programme kan dalk die raamstatistiek van vensters van ander programme af naboots."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"haal vensterinligting op"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Laat \'n program toe om inligting oor vensters vanaf die vensterbestuurder op te haal. Kwaadwillige programme kan moontlik inligting ophaal wat vir interne stelselgebruik bedoel is."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filter gebeure"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Laat \'n program toe om \'n invoerfilter te registreer wat die stroom van alle gebruikergebeure filter voordat dit versend word. Kwaadwillige programme kan moontlik die stelsel-UI beheer sonder gebruikers se tussentrede."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"vergroot skerm"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Laat \'n program toe om die inhoud van \'n skerm te vergroot. Kwaadwillige programme kan die skerminhoud so omskep dat die toestel onbruikbaar word."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"gedeeltelike afskakeling"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Plaas die aktiwiteitbestuurder in \'n afsluitingstatus. Doen nie \'n volledige afsluiting nie."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"verhoed program-oorskakelings"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Laat die program toe om \'n kennisgewing uit te saai dat \'n SMS-boodskap ontvang is. Kwaadwillige programme kan dit dalk gebruik om inkomende SMS-boodskappe na te maak."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"stuur WAP-PUSH-ontvange uitsending"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Laat die program toe om \'n kennisgewing uit te saai dat \'n WAP PUSH-boodskap ontvang is. Kwaadwillige programme kan dit dalk gebruik om MMS-boodskap-ontvangsbewyse na te maak of die inhoud van enige webbladsy stilweg te vervang met kwaadwillige variante."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"stuur uitsending vir netwerktelling"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Laat die program toe om \'n kennisgewing uit te saai dat netwerke tellings moet kry. Nooit vir normale programme nodig nie."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"beperk hoeveelheid lopende prosesse"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Laat die program toe om die maksimum getal prosesse te beheer wat sal loop. Nooit nodig vir normale programme nie."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"dwing agtergrondprogramme om te sluit"</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n VPN-diens te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"bind aan \'n muurpapier"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n muurpapier te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"koppel aan \'n afstandskerm"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Dit laat die houer toe om aan die top-koppelvlak van \'n afstandskerm te koppel. Behoort nooit vir gewone programme nodig te wees nie."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind aan \'n legstukdiens"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Laat die program toe om enige geïnstalleer mediadekodeerder te gebruik om te kan dekodeer vir terugspeel."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"bestuur vertroude eiebewyse"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Laat die program CA-sertifikate as vertroude eiebewyse installeer en deïnstalleer."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"laat program gedurende ledige tyd loop"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Met hierdie toestemming kan die Android-stelsel die program in die agtergrond laat loop terwyl die toestel nie gebruik word nie."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"bind aan ledige dienste"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Hierdie toestemming laat die Android-stelsel toe om aan \'n program se ledige dienste te bind."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lees/skryf na bronne wat diag besit"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Laat die program toe om na enige hulpbron wat deur die diag-groep besit word, te skryf, byvoorbeeld lêers in /dev. Dit kan potensieel stelselstabiliteit en sekuriteit affekteer. Dit moet NET gebruik word vir hardewarespesifieke diagnose deur die vervaardiger of operateur."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"aktiveer of deaktiveer programkomponente"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Laat die program toe om persoonlike profielinligting  wat op jou toestel gestoor is, soos jou naam en kontakbesonderhede, te lees. Dit beteken dat die program jou kan identifiseer en jou profielinligting moontlik aan ander mense kan stuur."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"verander jou eie kontakkaart"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Laat die program toe om persoonlike profielinligting, soos jou naam en kontakinligting, wat op jou toestel gestoor is, te verander of daarby te voeg. Dit beteken dat die program jou kan identifiseer en moontlik jou profielinligting na ander mense kan stuur."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"liggaamsensors (soos hartklopmonitors)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Laat die program toe om toegang tot data te verkry vanaf sensors wat jy gebruik om te meet wat binne jou liggaam aangaan, soos hartklop."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"lees jou sosiale stroom"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Laat die program toe om toegang tot sosiale opdaterings van jou en jou vriende te verkry en dit te sinkroniseer. Wees versigtig wanneer jy inligting deel -- dit laat die program toe om kommunikasie tussen jou en jou vriende op sosiale netwerke te lees, ongeag vertroulikheid. Let wel: hierdie toestemming mag dalk nie op alle sosiale netwerke afgedwing word nie."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"skryf aan jou sosiale stroom"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Laat die program toe om die foonkenmerke van die toestel te beheer. \'n Program met hierdie toestemming kan tussen netwerke wissel, die foonradio aan en af skakel, en dies meer, sonder om jou ooit te laat weet."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"lees foonstatus en identiteit"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Laat die program toe om toegang tot die foonfunksies van die toestel te verkry. Hierdie toestemming laat die program toe om te bepaal wat die foonnommer en toestel-IDs is, of die oproep aan die gang is, en die afgeleë nommer wat deur \'n oproep verbind word."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"lees presiese foonstate"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Gee die program toegang tot presiese foonstate. Hierdie toestemming laat die program toe om die werklike oproepstatus te bepaal, of \'n oproep aktief is en of dit in die agtergrond is. Dit kan ook mislukte oproepe, presiese dataverbindingstatus en mislukte dataverbindings bepaal."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"verhoed dat tablet slaap"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"verhoed foon om te slaap"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Laat die program toe om die tablet te keer om te slaap."</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Verander WiMAX-status"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Laat die program toe om die tablet aan WiMAX-netwerke te koppel en daarvan te ontkoppel."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Laat die program toe om die foon aan WiMAX-netwerke te koppel en daarvan te ontkoppel."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"gee telling vir netwerke"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Laat die program toe om netwerke te gradeer en beïnvloed watter netwerke die tablet moet verkies."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Laat die program toe om netwerke te gradeer en beïnvloed watter netwerke die foon moet verkies."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"bind saam met Bluetooth-toestelle"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Laat die program toe om die opstelling van Bluetooth op die tablet te sien, en om verbindings met saamgebinde toestelle te maak en te aanvaar."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Laat die program toe om die opstelling van die Bluetooth op die foon te sien, en om verbindings met saamgebinde toestelle te maak en te aanvaar."</string>
@@ -703,18 +685,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"roep die opstellingprogram op wat deur die diensverskaffer voorsien is"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Laat die houer toe om die opstellingsprogram wat deur die diensverskaffer voorsien word, op te roep. Behoort nooit vir gewone programme nodig te wees nie."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"luister vir waarnemings oor netwerktoestande"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Laat \'n program luister vir waarnemings oor netwerktoestande. Behoort nooit nodig te wees vir normale programme nie."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"verander invoertoestelkalibrasie"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Laat die program toe om die kalibrasieparameters van die raakskerm te wysig. Dit behoort nooit vir normale programme nodig te wees nie."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"gaan in by DRM-sertifikate"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Laat \'n program toe om DRM-sertifikate op te stel en te gebruik. Behoort nooit vir normale 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="policylab_watchLogin" msgid="914130646942199503">"Monitor pogings om skerm te ontsluit"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Laat \'n program toe om toegang tot keyguard se veilige berging te kry."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Beheer wys en versteek van keyguard"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Laat \'n program toe om keyguard te beheer."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Luister na vertrouenstaatveranderinge."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Laat \'n program toe om vir veranderinge in vertrouenstaat te luister."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Verbind met \'n vertrouensagentdiens"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Laat \'n program toe om met \'n vertrouensagentdiens te verbind."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Tree in wisselwerking met opdatering- en terugstellingstelsel"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Laat \'n program met die terugstellingstelsel en stelselopdaterings in wisselwerking tree."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Raak twee keer vir zoembeheer"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Muurpapier"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Verander muurpapier"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Kennisgewingluisteraar"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN geaktiveer"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN is geaktiveer deur <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Raak om die netwerk te bestuur."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 05594b3..56bdd24 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -46,7 +46,7 @@
     <string name="badPin" msgid="9015277645546710014">"የተየበከው የድሮ ፒን ትክክል አይደለም።"</string>
     <string name="badPuk" msgid="5487257647081132201">"የተየብከው PUK ትክክል  አይደለም።"</string>
     <string name="mismatchPin" msgid="609379054496863419">"ያስገባሃቸው ፒኖች አይዛመዱም"</string>
-    <string name="invalidPin" msgid="3850018445187475377">"ከ4 እስከ 8 ቁጥሮች የያዘ ፒን  ተይብ"</string>
+    <string name="invalidPin" msgid="3850018445187475377">"ከ4 እስከ 8 ቁጥሮች የያዘ PIN ተይብ"</string>
     <string name="invalidPuk" msgid="8761456210898036513">"8 ወይም ከዛ በላይ የሆኑ ቁጥሮችንPUK ተይብ።"</string>
     <string name="needPuk" msgid="919668385956251611">"SIM ካርድዎ PUK-የተቆለፈ ነው።የPUK ኮዱን በመተየብ ይክፈቱት።"</string>
     <string name="needPuk2" msgid="4526033371987193070">" SIM ለመክፈት PUK2 ተይብ።"</string>
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"ሥምሪያ"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"በጣም ብዙ <xliff:g id="CONTENT_TYPE">%s</xliff:g> ስርዞች።"</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"የጡባዊ ተኮ ማከማቻ ሙሉ ነው! ቦታ ነፃ ለማድረግ አንዳንድ ፋይሎች ሰርዝ።"</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"የእጅ ሰዓት ማከማቻ ሙሉ ነው። ቦታ ለማስለቀቅ አንዳንድ ፋይሎችን ይሰርዙ።"</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"የስልክ ማከማቻ ሙሉ ነው! ቦታ ነፃ ለማድረግ አንዳንድ ፋይሎች ሰርዝ።"</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"አውታረ መረብ በክትትል ውስጥ ሊሆን ይችላል"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"ባልታወቀ ሶስተኛ ወገን"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"መጥሪያ በርቷል"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"በመዝጋት ላይ..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"ጡባዊዎ ይዘጋል።"</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"የእርስዎ የእጅ ሰዓት ይዘጋል።"</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"ስልክዎ ይዘጋል።"</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"ዘግተህ መውጣት  ትፈልጋለህ?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"በአስተማማኝ ኹነታ ውስጥ ዳግም አስጀምር"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"የአውሮፕላን ሁነታ"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"የሚያስተማምን ሁነታ"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android ስርዓት"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"አቋራጮችን ያራግፋል"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"መተግበሪያው ያለተጠቃሚ ጣልቃ-ገብነት የመነሻ ማያ ገጽ አቋራጮችን እንዲያስወግድ ያስችለዋል።"</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"የወጪ ጥሪዎች አቅጣጫ ቀይር"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"በወጪ ጥሪ ጊዜ ጥሪውን ወደተለየ ቁጥር ከማዞር ወይም ጥሪውን በአጠቃላይ ከመተው አማራጭ ጋር እየተደወለለት ያለውን ቁጥር እንዲያይ ያስችለዋል።"</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"መተግበሪያው ወጪ ጥሪዎችን እንዲያስኬድና የሚደወለውን ቁጥር እንዲቀይር ይፈቅድለታል። ይህ ፈቃድ መተግበሪያው ወጪ ጥሪዎችን እንዲቆጣጠር፣ አቅጣጫ እንዲየስቀይር ወይም እንዲያግድ ይፈቅድለታል።"</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"የፅሁፍ መልዕክቶችን ተቀበል (ኤስ.ኤም.ኤስ.)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"መተግበሪያው የኤስ.ኤም.ኤስ. መልእክቶችን እንዲያነብ እና እንዲያካሂድ ይፈቅዳል። ይህ ማለት መተግበሪያው ወደ መሳሪያህ የተላኩ መልእክቶችን ላንተ ሳያሳይህ ሊቆጣጠር ወይም ሊሰርዝ ይችላል።"</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"የፅሁፍ መልዕክቶችን ተቀበል (ኤም.ኤም.ኤስ.)"</string>
@@ -273,13 +270,13 @@
     <string name="permlab_sendRespondViaMessageRequest" msgid="8713889105305943200">"የበመልዕክት-በኩል-ምላሽ-ስጥ ክስተቶችን ይላኩ"</string>
     <string name="permdesc_sendRespondViaMessageRequest" msgid="7107648548468778734">"መተግበሪያው ሌሎች የመልዕክት መላኪያ መተግበሪያዎች ለመጪ ጥሪዎች በመልዕክት-በኩል-ምላሽ-መስጠት ስራን እንዲይዙ ጥያቄዎች እንዲልክላቸው ያስችለዋል።"</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"የጽሑፍ መልዕክቶችዎን ያንብቡ (ኤስ.ኤም.ኤስ. ወይም ኤም.ኤም.ኤስ.)"</string>
-    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"መገለጫው በጡባዊ ተኮዎ ወይም በSIM ካርድዎ የተከማቹ የኤስኤምኤስ. መልዕክቶችን እንዲያነብ ይፈቅድለታል። ይህ መተግበሪያው ይዘት ወይም ሚስጥራዊነትን ከግምት ሳያስገባ ሁሉንም የኤስኤምኤስ መልዕክቶች እንዲያነብ ይፈቅድለታል።"</string>
+    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"መገለጫው በጡባዊ ቱኮህ ወይም በSIM ካርድህ የተከማቹ የኤስ.ኤም.ኤስ. መልእክቶችን እንዲያነብ ይፈቅድለታል። ይህ መተግበሪያው ይዘት ወይም ሚስጥራዊነትን ከግምት ሳያስገባ ሁሉንም የኤስ.ኤም.ኤስ. መልእክቶች እንዲያነብ ይፈቅድለታል።"</string>
     <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"መገለጫው በስልክዎ ወይም በSIM ካርድዎ የተከማቹ የኤስ.ኤም.ኤስ. መልዕክቶችን እንዲያነብ ይፈቅድለታል። ይህ መተግበሪያው ይዘት ወይም ሚስጥራዊነትን ከግምት ሳያስገባ ሁሉንም የኤስ.ኤም.ኤስ. መልዕክቶች እንዲያነብ ይፈቅድለታል።"</string>
     <string name="permlab_writeSms" msgid="3216950472636214774">"የጽሑፍ መልዕክቶችህን አርትዕ (ኤስ.ኤም.ኤስ. ወይም ኤም.ኤም.ኤስ.)"</string>
     <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"በጡባዊ ተኮህ ወይም ሲም ካርድህ ላይ ኤስ ኤም ኤስ መልዕክቶችን ለመፃፍ ለመተግበሪያው ይፈቅዳሉ፡፡መልዕክቶችህን ተንኮል አዘል መተግበሪያዎች ሊሰርዙ ይችላሉ፡፡"</string>
     <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"በስልክዎ ወይም ሲም ካርድዎ ላይ ኤስ ኤም ኤስ መልዕክቶችን ለመፃፍ ለመተግበሪያው ይፈቅዳሉ። መልዕክቶችዎን ተንኮል አዘል መተግበሪያዎች ሊሰርዙ ይችላሉ።"</string>
     <string name="permlab_receiveWapPush" msgid="5991398711936590410">"የፅሁፍ መልዕክቶችን ተቀበል (WAP)"</string>
-    <string name="permdesc_receiveWapPush" msgid="748232190220583385">"መተግበሪያው የWAP መልዕክቶችን እንዲያነብ እና እንዲያካሂድ ይፈቅዳል። ይህ ፈቃድ የተላኩልዎን መልዕክቶች ለእርስዎ ሳያሳይዎ የመቆጣጠር ወይም የመሰረዝ ብቃትን ያጠቃልላል።"</string>
+    <string name="permdesc_receiveWapPush" msgid="748232190220583385">"መተግበሪያው የWAP መልእክቶችን እንዲያነብ እና እንዲያካሂድ ይፈቅዳል። ይህ ፈቃድ የተላኩልህን መልእክቶች ላንተ ሳያሳይህ የመቆጣጠር ወይም የመሰረዝ ብቃትን ያጠቃልላል።"</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"አሂድ መተግበሪያዎችን ሰርስረው ያውጡ"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"መተግበሪያው በአሁኑ ጊዜና በቅርቡ እየተካሄዱ ስላሉ ተግባሮችን መረጃ ሰርስሮ እንዲያወጣ ይፈቅድለታል። ይህ መተግበሪያው በመሳሪያው ላይ የትኛዎቹ መተግበሪያዎች ጥቅም ላይ ስለመዋላቸው መረጃ እንዲያገኝ ሊፈቅድለት ይችላል።"</string>
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"በተለያዩ ተጠቃሚዎች መካከል መስተጋብር መፍጠር"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"የነቃ መስኮት ይዘትን ለመበርበር ለመተግበሪያው ይፈቅዳሉ፡፡ ጠቅላላውን የመስኮት ይዘት ለመበርበር እና ከይለፍ ቃል በስተቀር ሁሉንም ጽሑፉን ለማየት ጎጂ መተግበሪያዎች ይችላሉ፡፡"</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"ተደራሽነት በጊዜያዊነት ያነቃል"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"አንድ መተግበሪያ በጊዜያዊነት በመሣሪያው ላይ ተደራሽነትን እንዲያነቃ ያስችለዋል። ተንኮል-አዘል መተግበሪያዎች ያለተጠቃሚው ፍቃድ ተደራሽነትን ሊያነቁ ይችላሉ።"</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"የመስኮት ማስመሰያ ሰርስሮ ያወጣል"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"አንድ መተግበሪያ የመስኮት ማስመሰያውን ሰርስሮ እንዲያወጣ ያስችላል። ተንኮል-አዘል ዌር ስርዓቱት በማስመሰል ከመተግበሪያው መስኮት ጋር ያልተፈቀደ መስተጋብር ሊፈጥሩ ይችላሉ።"</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"የክፈፍ ስታቲስቲክሶችን ሰርስሮ ያወጣል"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"አንድ መተግበሪያ የክፈፍ ስታቲስቲክስን እንዲሰበስብ ያስችላል። ተንኮል-አዘል ዌር የሌሎች መተግበሪያዎች የክፈፍ ስታቲስቲክሶችን ሊመለከቱ ይችላሉ።"</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"የመስኮት መረጃን አምጣ"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"አንድ መተግበሪያ ከመስኮት አቀናባሪው ሆኖ ስለመስኮቱ መረጃ እንዲያመጣ ያስችለዋል። ተንኮል-አዘል መተግበሪያዎች ለውስጣዊ ስርዓት ጥቅም የታሰበ መረጃን ሊወስዱ ይችላሉ።"</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"ክስተቶችን አጣራ"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"አንድ መተግበሪያ የሁሉንም ተጠቃሚዎች ክስተቶች ከመላካቸው በፊት እነሱን የሚያጣራ የግቤት ማጣሪያ እንዲመዘግብ ያስችለዋል። ተንኮል-አዘል መተግበሪያዎች ተጠቃሚው ጣልቃ ሳይገባ የስርዓቱን በይነገጽ ሊቆጣጠሩት ይችላሉ።"</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"ማሳያን አጉላ"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"አንድ መተግበሪያ የአንድ ማሳያ ይዘት እንዲያጎላ ይፈቅድለታል። ተንኮል-አዘል መተግበሪያዎች መሣሪያውን ከጥቅም ውጪ በሚያደርገው ሁኔታ የማሳያ ይዘቱ ሊለውጡት ይችላሉ።"</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"ከፊል ዝጋ"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"የእንቅስቃሴውን አደራጅ ወደ ዝጋ ሁነታ አስቀምጥ።ሙሉ ለሙሉ ዝጋ አያከናውንም።"</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"የትግበራ መቀያየርን ተከላከል"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"ኤስ ኤም ኤስ መልዕክት መቀበሉን ማሳወቂያ እንዲያሰራጭ ለመተግበሪያው ይፈቅዳሉ፡፡ መጪ ኤስ ኤም ኤስ መልዕክቶችን አመሳስሎ በማቅረብ  ተንኮል አዘል መተግበሪያዎች ይሄንን ሊጠቀሙበት ይችላሉ፡፡"</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"የWAP-PUSH ደርስዋል ስርጭት ላክ"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"የWAP PUSH መልዕክት እንደተቀበለ ማሳወቂያ ለማሰራጨት ለመተግበሪያው ይፈቅዳሉ፡፡ ኤም ኤም ኤስ መልዕክት መቀበልን ለማስመሰል ወይም በተንኮል አዘል መሰሎች ለማንኛውም የድር ገፅ ይዘት በዝምታ ለመተካት ተንኮል አዘል መተግበሪያዎች ሊጠቀሙበት ይችላሉ፡፡"</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ለአውታረ መረቦች የነጥብ ስጥ ስርጭት ይልካል"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"መተግበሪያው አውታረ መረቦች ነጥብ እንዲያዝለት የሚፈልጉት አንድ ማሳወቂያ እንዲያሰራጭ ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"የአሂድ ሂደቶችን ቁጥር ወስን"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"የሚሄዱ ሂደቶችን የመጨረሻ ቁጥር ለመቆጣጠር ለመተግበሪያው ይፈቅዳሉ፡፡ ለመደበኛ መተግበሪያዎች መቼም አያስፈልግም፡፡"</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"የጀርባ መተግበሪያዎች እንዲዘጉ አስገድዳቸው"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"የVPN ግልጋሎትን ወደ ከፍተኛ-ደረጃ በየነ ገጽ ለማሳር ለመያዣው ይፈቅዳሉ፡፡ለተለመዱ መተግበሪያዎች አያስፈልግም፡፡"</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"በልጣፍ ጠርዝ"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ ልጣፍ ለመጠረዝ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ከአንድ የርቀት ማሳያ ጋር ይጠርዛል"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"ባለቤቱ ከአንድ የቴሌቪዥን ግብዓት ከፍተኛ-ደረጃ በይነገጽ ጋር እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"የመሣሪያ አስተዳዳሪ ያክሉ ወይም ያስወግዱ"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"ያዢው ንቁ የመሣሪያ አስተዳዳሪዎች እንዲያክል ወይም እንዲያስወግድ ያስችለዋል። ለመደበኛ መተግበሪያዎች ጭራሽ ሊያስፈልግ አይገባም።"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"የማያ ገፀ አቀማመጥን ለውጥ"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ለመልሰህ አጫውት ፍታን በማንኛውም የተጫኑ በማህደረ መረጃ ዲኮደር ለመጠቀም  ለመተግበሪያ ይፈቅዳል።"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"የታመኑ ምስክርነቶችን ያስተዳድሩ"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"መተግበሪያው CA የምስክር ወረቀቶችን እንደሚታመኑ ምስክርነቶች አንዲጭን እና እንዲያራግፍ ይፍቀዱ።"</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"ስራ በተፈታበት ጊዜ ላይ መተግበሪያውን አሂድ"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"ይህ ፍቃድ መሣሪያው ስራ ላይ ባልሆነ ጊዜ የAndroid ስርዓቱ መተግበሪያውን በጀርባ ውስጥ እንዲያሂደው ያስችለዋል።"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"ከስራ ፈት አገልግሎቶች ጋር ይሰሩ"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"ይህ ፍቃድ የAndroid ስርዓቱ የአንድ መተግበሪያ ስራ-ፈት አገልግሎቶችን እንዲያስር ያስችለዋል።"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"በdiag ባለቤትነት ያሉ ንብረቶችን አንብብ/ፃፍ"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"በዲያግ ቡድን ባለቤትነት ወደ አለ ማንኛውም ንብረት ለምሳሌ በ/dev ያሉ ፋይሎች ለማንበብ እና ለመፃፍ ለመተግበሪያው ይፈቅዳሉ። ይህ በመሰረቱ የስርዓት መረጋጋትን እና ደህንነትን ሊጎዳ ይችላል። ይህ ውስን የሀርድዌር-ተኮር ዲያግኖስቲክስ በአምራቹ ወይም ከዋኙ ብቻ መሆን አለበት።"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"የመተግበሪያ ምንዝሮችን አንቃ ወይም አቦዝን"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"መተግበሪያው ልክ እንደ ስምዎ እና የእውቂያ መረጃዎ ያሉ በመሳሪያዎ ላይ የተከማቹ የግል መገለጫ መረጃዎችን እንዲያነብ ይፈቅድለታል። ይህም ማለት መተግበሪያው ለይቶ ሊያውቁዎ እና የመገለጫ መረጃዎን ለሌሎች ሊልክ ይችላል።"</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"የራስህን የዕውቂያ ካርድ አስተካክል"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"መተግበሪያው ልክ እንደ ስምዎ እና የእውቂያ መረጃዎ ያሉ በመሳሪያዎ ላይ የተከማቹ የግል መገለጫ መረጃዎችን እንዲቀይር ወይም እንዲያክልባቸው ይፈቅድለታል። ይህም ማለት መተግበሪያው ለይቶ ሊያውቅዎ እና የመገለጫ መረጃዎን ለሌሎች ሊልክ ይችላል።"</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"የሰውነት መመርመሪያዎች (እንደ የልብ ምት መቆጣጠሪያዎች)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"መተግበሪያው እርስዎ በሰውነትዎ ውስጥ እየተካሄዱ ያሉ እንደ የልብ ምት የመሳሰሉ ነገሮችን ለመለካት የሚጠቀሙበትን ውሂብ ከመመርመሪያዎቹ ላይ እንዲደርስ ይፈቅድለታል።"</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"የአንተን ማህበራዊ የውይይት ክፍሎች አንብብ"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"መተግበሪያው የአንተንና የጓኞችህን ማህበራዊ ዝማኔዎችን እንዲደርስባቸው እና እንዲያመሳስላቸው ይፈቅድለታል። መረጃ ስታጋራ ተጠንቀቅ -- ይህ መተግበሪያው ሚስጥራዊነትን ከግምት ሳያስገባ በማህበራዊ አውታረ መረቦች በአንተ እና በጓደኞችህ መካከል የሚደረጉ ግንኙነቶችን እንዲያነብ ይፈቅድለታል። ማስታወሻ፦ ይህ ፈቃድ ለሁሉም ማህበራዊ አውታር መረቦች ላይ ላይፈጸም ይችላል።"</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"ወደ የአንተ  ማህበራዊ የውይይት ክፍሎች ጻፍ"</string>
@@ -488,11 +473,11 @@
     <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"መተግበሪያው የጓደኞችህን እና የስራ ባልደረቦችህን ጨምሮ በጡባዊ ተኮህ ላይ ልታስተካክላቸው የምትችላቸውን ክስተቶች እንዲያክል፣ እንዲያስወግድ፣ እንዲለውጥ ይፈቅድለታል። ይህ መተግበሪያው ከቀን መቁጠሪያ ባለቤቶች የመጡ የሚመስሉ መልእክቶችን እንዲልክ ወይም ያለባለቤቱ እውቀት ክስተቶችን እንዲያስተካክል ሊፈቅድለት ይችላል።"</string>
     <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"መተግበሪያው የጓደኞችዎን እና የስራ ባልደረቦችዎን ጨምሮ በስልክዎ ላይ ሊያስተካክሏቸው የሚችሏቸውን ክስተቶች እንዲያክል፣ እንዲያስወግድ፣ እንዲለውጥ ይፈቅድለታል። ይህ መተግበሪያው ከቀን መቁጠሪያ ባለቤቶች የመጡ የሚመስሉ መልዕክቶችን እንዲልክ ወይም ያለባለቤቱ እውቀት ክስተቶችን እንዲያስተካክል ሊፈቅድለት ይችላል።"</string>
     <string name="permlab_accessMockLocation" msgid="8688334974036823330">"ለሙከራ ጊዜያዊ ሥፍራ ፍጠር።"</string>
-    <string name="permdesc_accessMockLocation" msgid="5808711039482051824">"ለሙከራ የጊዜያዊ የመነሻ ምንጮችን ይፍጠሩ ወይም አዲስ የአካባቢ አቅራቢ ይጫኑ። ይህ መተግበሪያው አካባቢውን እና/ወይም እንደ GPS ወይም የአካባቢ አቅራቢዎች ባሉ ሌላ የመነሻ ምንጮች የተመለሱ ሁኔታዎችን ችላ እንዲል ይፈቅድለታል።"</string>
+    <string name="permdesc_accessMockLocation" msgid="5808711039482051824">"ለሙከራ የማስመሰል የመነሻ ምንጮችን ፍጠር ወይም አዲስ የአካባቢ አቅራቢ ጫን። ይህ መተግበሪያው አካባቢውን እና/ወይም እንደ GPS ወይም የአካባቢ አቅራቢዎች ባሉ ሌላ የመነሻ ምንጮች የተመለሱ ሁኔታዎችን ችላ እንዲል ይፈቅድለታል።"</string>
     <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"ተጨማሪ ሥፍራ አቅራቢ ትዕዛዞችን ድረስ።"</string>
     <string name="permdesc_accessLocationExtraCommands" msgid="5945166642335800763">"መተግበሪያው ተጨማሪ የአካባቢ አቅራቢ ትእዛዞችን እንዲደርስ ይፈቅድለታል። ይህ መተግበሪያው በGPS ወይም ሌላ የመነሻ ምንጮች ክወና ላይ ጣልቃ እንዲገባ ሊፈቅድለት ይችላል።"</string>
     <string name="permlab_installLocationProvider" msgid="6578101199825193873">"የሥፍራ አቅራቢ ለመጫን ፍቀድ"</string>
-    <string name="permdesc_installLocationProvider" msgid="9066146120470591509">"ለሙከራ የጊዜያዊ የመነሻ ምንጮችን ይፍጠሩ ወይም አዲስ የአካባቢ አቅራቢ ይጫኑ። ይህ መተግበሪያው አካባቢውን እና/ወይም እንደ ጂፒኤስ ወይም የአካባቢ አቅራቢዎች ባሉ ሌላ የመነሻ ምንጮች የተመለሱ ሁኔታዎችን ችላ እንዲል ይፈቅድለታል።"</string>
+    <string name="permdesc_installLocationProvider" msgid="9066146120470591509">"ለሙከራ የማስመሰል የመነሻ ምንጮችን ፍጠር ወይም አዲስ የአካባቢ አቅራቢ ጫን። ይህ መተግበሪያው አካባቢውን እና/ወይም እንደ GPS ወይም የአካባቢ አቅራቢዎች ባሉ ሌላ የመነሻ ምንጮች የተመለሱ ሁኔታዎችን ችላ እንዲል ይፈቅድለታል።"</string>
     <string name="permlab_accessFineLocation" msgid="1191898061965273372">"ትክክለኛ አካባቢ (በጂ ፒ ኤስ እና አውታረ መረብ ላይ የተመሠረተ)"</string>
     <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"መተግበሪያው የእርስዎን አለምአቀፍ የመሬት አቀማመጥ ስርዓትን (ጂ ፒ ኤስ) ወይም እንደ የተንቀሳቃሽ ስልክ ማማዎች እና Wi-Fi ያሉ የአውታረ መረብ አካባቢ ምንጮችን ተጠቅሞ ትክክለኛ አካባቢዎትን እንዲያውቅ ያስችለዋል። መተግበሪያው እነዚህ የአካባቢ አገልግሎቶችን እንዲጠቀምባቸው እነሱ ሊበሩ እና ለመሣሪያዎ የሚገኙ መሆን አለባቸው። መተግበሪያዎች እርስዎ የት እንዳሉ ለማወቅ ይህንን ሊጠቀሙበት ይችላሉ፣ እና ተጨማሪ ባትሪ ሊፈጁ ይችላሉ።"</string>
     <string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"ግምታዊ አካባቢ (በአውታረ መረብ ላይ የተመሰረተ)"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"የመገልገያ መሳሪያውን የስልክ ባህሪያት ለመቆጣጠር ለመተግበሪያው ይፈቅዳል፡፡ ከዚህ ፍቃድ ጋር መተግበሪያ አውታረ መረቦችን ሊለውጥ ይችላል፤አንተን ምንም ሳያሳውቅ የስልኩን ሬድዮ አብራ እና አጥፋ እና የመሳሰሉትን ሊያበራ ይችላል፡፡"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"የስልክ ሁኔታና ማንነት አንብብ"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"መተግበሪያው የመሳሪያውን የስልክ ባህሪያት ላይ እንዲደርስ ይፈቅድለታል። ይህ ፈቃድ መተግበሪያው የስልክ ቁጥሩን እና የመሳሪያውን መታወቂያዎች፣ ጥሪ የነቃ እንደሆነ፣ እና በጥሪ የተገናኘውን የሩቅ ቁጥር እንዲወስን ይፈቅድለታል።"</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"ትክክለኛዎቹን የስልክ ሁኔታዎች ያነብባል"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"መተግበሪያው ትክክለኛዎቹ የስልክ ሁኔታዎችን እንዲደርስባቸው ያስችለዋል። ይህ ፍቃድ መተግበሪያው የእውነተኛ ጥሪው ሁኔታ፣ አንድ ጥሪ ገባሪ ወይም ጀርባ ላይ ይሁን፣ ያልተሳኩ ጥሪዎች፣ ትክክለኛው የውሂብ ግንኙነት ሁኔታ እና የውሂብ ግንኙነት አለመሳካቶችን እንዲያውቅ ያስችለዋል።"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ጡባዊ ከማንቀላፋት ተከላከል"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ስልክ ከማንቀላፋት ተከላከል"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"ጡባዊውን ከመተኛት መከልከል ለመተግበሪያው ይፈቅዳሉ።"</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"የWiMAX ሁኔታ ለውጥ"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"መተግበሪያው ጡባዊ ተኮውን ከWiMAX አውታረ መረብ ጋር እንዲያገናኝና እንዲያለያይ ይፈቅድለታል።"</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"መተግበሪያው ስልኩን ከWiMAX አውታረ መረብ ጋር እንዲያገናኝና እንዲያለያይ ይፈቅድለታል።"</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ለአውታረ መረቦች ነጥብ ይሰጣል"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"መተግበሪያው ለአውታረ መረቦች ደረጃ እንዲሰጥ እና ጡባዊው የትኛዎቹን አውታረ መረቦች እንደሚመርጥ ላይ ተጽዕኖ እንዲያሳርፍ ያስችለዋል።"</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"መተግበሪያው ለአውታረ መረቦች ደረጃ እንዲሰጥ እና ስልኩ የትኛዎቹን አውታረ መረቦች እንደሚመርጥ እና ላይ ተጽዕኖ እንዲያሳርፍ ያስችለዋል።"</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"ከብሉቱዝ መሣሪያዎች ጋር ተጣመር"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"መተግበሪያው በጡባዊ ተኮው ላይ ያለውን የብሉቱዝ ውቅር እንዲያይ እና ከተጣመሩ መሳሪያዎች ጋር ግንኙነቶችን እንዲያደርግና እንዲቀበል ይፈቅድለታል።"</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"መተግበሪያው በስልኩ ላይ ያለውን የብሉቱዝ ውቅር እንዲያይ እና ከተጣመሩ መሳሪያዎች ጋር ግንኙነቶችን እንዲያደርግና እንዲቀበል ይፈቅድለታል።"</string>
@@ -703,18 +683,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"መተግበሪያው ማሳወቂያዎችን እንዲያስመጣ፣ እንዲመረምር እና እንዲያጸዳ ያስችለዋል፣ በሌሎች መተግበሪያዎች የተለጠፉትንም ጨምሮ።"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ከአንድ የማሳወቂያ አዳማጭ አገልግሎት ጋር ይሰሩ"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ያዢው የማሳወቂያ አዳማጭ አገልግሎቱን ከከፍተኛ-ደረጃ በይነገጹ ጋር እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"በድምጸ-ተያያዥ ሞደም የቀረበው የውቅር መተግበሪያውን መጥራት"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ያዢው በድምጸ-ተያያዥ ሞደም የቀረበው የውቅር መተግበሪያውን እንዲጠራው ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"በአውታረ መረብ ሁኔታዎች ላይ የተስተዋሉ ነገሮችን ያዳምጣል"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"አንድ መተግበሪያ በአውታረ መረብ ሁኔታዎች ላይ የተስተዋሉ ነገሮችን እንዲያዳምጥ ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አስፈላጊ ሊሆን አይገባም።"</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"የግቤት መሣሪያ ማስተካከያ ቀይር"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"መተግበሪያው የማያ ንካ የማስተካከያ ልኬቶቹን እንዲቀይር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ ሊያስፈልግ አይገባም።"</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"የDRM የምስክር ወረቀቶች ላይ ይድረሱ"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"አንድ መተግበሪያ የDRM የምስክር ወረቀቶችን እንዲሰጥና እንዲጠቀም ያስችላል። ለመደበኛ መተግበሪያዎች በፍጹም አስፈላጊ አይሆንም።"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"የይለፍ ቃል ደንቦች አዘጋጅ"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"በማያ-መክፈት የተፈቀዱ የይለፍ ቃል ርዝመት እና ቁምፊዎች ተቆጣጠር።"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"የማሳያ-ክፈት ሙከራዎችን አሳይ"</string>
@@ -858,7 +830,7 @@
     <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">"ለመክፈት ፒን ተይብ"</string>
-    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ትክክል ያልሆነ ፒን  ኮድ።"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ትክክል ያልሆነ PIN ኮድ።"</string>
     <string name="keyguard_label_text" msgid="861796461028298424">"ለመክፈት፣ምናሌ ተጫን ከዛ 0"</string>
     <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"የአደጋ ጊዜቁጥር"</string>
     <string name="lockscreen_carrier_default" msgid="8963839242565653192">"ከአገልግሎት መስጫ ክልል ውጪ"</string>
@@ -1016,12 +988,12 @@
     <string name="search_go" msgid="8298016669822141719">"ፍለጋ"</string>
     <string name="searchview_description_search" msgid="6749826639098512120">"ፍለጋ"</string>
     <string name="searchview_description_query" msgid="5911778593125355124">"ጥያቄ ፍለጋ"</string>
-    <string name="searchview_description_clear" msgid="1330281990951833033">"ጥያቄ አጽዳ"</string>
+    <string name="searchview_description_clear" msgid="1330281990951833033">"ጥያቄ አጥራ"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"ጥያቄ አስረክብ"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"የድምፅ ፍለጋ"</string>
     <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"በመንካት አስስ ይንቃ?"</string>
-    <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>  ማሰስን በንኪ ማንቃት ይፈልጋል። አስስ በንኪ በሚበራበት ጊዜ፣ ከጡባዊ ተኮው ጋር ለመግባባት ምን በጣትዎ ስር ወይም ምልክቶችን ማከናወን እንዳለብዎ ማብራሪያ ሊመለከቱ ወይም ሊሰሙ ይችላሉ።"</string>
-    <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="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>  ማሰስን በንኪ ማንቃት ይፈልጋል። አስስ በንኪ በሚበራበት ጊዜ፣ ከጡባዊ ተኮው ጋር ለመግባባት ምን በጣትህ ስር ወይም ምልክቶችን ማከናወን እንዳለብህ ማብራሪያ ልታይ ወይም ልትሰማ ትችላለህ።"</string>
+    <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">
@@ -1149,9 +1121,9 @@
     <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> እያሄደ ነው"</string>
     <string name="app_running_notification_text" msgid="4653586947747330058">"ተጨማሪ መረጃ ለማግኘት ወይም መተግበሪያውን ለማቆም ይንኩ።"</string>
     <string name="ok" msgid="5970060430562524910">"እሺ"</string>
-    <string name="cancel" msgid="6442560571259935130">"ይቅር"</string>
+    <string name="cancel" msgid="6442560571259935130">"ሰርዝ"</string>
     <string name="yes" msgid="5362982303337969312">"እሺ"</string>
-    <string name="no" msgid="5141531044935541497">"ይቅር"</string>
+    <string name="no" msgid="5141531044935541497">"ሰርዝ"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"ትኩረት"</string>
     <string name="loading" msgid="7933681260296021180">"በመጫን ላይ…"</string>
     <string name="capital_on" msgid="1544682755514494298">"በ"</string>
@@ -1253,7 +1225,7 @@
     <string name="sms_short_code_details" msgid="3492025719868078457">"ይሄ በተንቀሳቃሽ ስልክ መለያዎ ላይ "<font fgcolor="#ffffb060">"ክፍያዎችን ሊያስከትል ይችላል"</font>"።"</string>
     <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"ይሄ በተንቀሳቃሽ ስልክ መለያዎ ላይ ክፍያዎችን ያስከትላል።"</font></string>
     <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"ላክ"</string>
-    <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"ይቅር"</string>
+    <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"ሰርዝ"</string>
     <string name="sms_short_code_remember_choice" msgid="5289538592272218136">"ምርጫዬን አስታውስ"</string>
     <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"ይሄንን በኋላ ላይ በቅንብሮች &gt; መተግበሪያዎች ውስጥ ሊቀይሩት ይችላሉ"</string>
     <string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"ሁልጊዜ ፍቀድ"</string>
@@ -1267,7 +1239,7 @@
     <string name="time_picker_dialog_title" msgid="8349362623068819295">"ጊዜ አዘጋጅ"</string>
     <string name="date_picker_dialog_title" msgid="5879450659453782278">"ውሂብ አዘጋጅ"</string>
     <string name="date_time_set" msgid="5777075614321087758">"አዘጋጅ"</string>
-    <string name="date_time_done" msgid="2507683751759308828">"ተከናውኗል"</string>
+    <string name="date_time_done" msgid="2507683751759308828">"ተጠናቋል"</string>
     <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"አዲስ፦ "</font></string>
     <string name="perms_description_app" msgid="5139836143293299417">"በ<xliff:g id="APP_NAME">%1$s</xliff:g> የቀረበ።"</string>
     <string name="no_permissions" msgid="7283357728219338112">"ምንም ፍቃዶች አይጠየቁም"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"አንድ መተግበሪያ ደህንነቱ በቁልፍ የተጠበቀ ማከማቻ እንዲደርስ ያስችለዋል።"</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>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ለተአማኒነት ወኪል አገልግሎት ተገዢ አድርግ"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"ለመተግበሪያን የተአማኒነት ወኪል አገልግሎትን እንዲያከብር ይፈቅዳል።"</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"ከዝማኔዎች እና ከመልሶ ማግኛ ስርዓቶች ጋር ይገናኙ"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"መተግበሪያው ከመልሶ ማግኛ ስርዓት እና ከስርዓት ማዘመኛዎች ጋር እንዲገናኝ ይፈቅድለታል።"</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"ለአጉላ መቆጣጠሪያ ሁለት ጊዜ ነካ አድርግ"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"ልጣፍ"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"ልጣፍ ለውጥ"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"ማሳወቂያ አዳማጭ"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN ነቅቷል።"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN በ<xliff:g id="APP">%s</xliff:g>ገብሯል"</string>
     <string name="vpn_text" msgid="3011306607126450322">"አውታረመረብ ለማደራጀት  ንካ።"</string>
@@ -1457,7 +1423,7 @@
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"ዓመት ጨምር"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"ዓመት ቀንስ"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ይቅር"</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>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index fa662fd..f90b65d 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"مزامنة"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"عمليات حذف <xliff:g id="CONTENT_TYPE">%s</xliff:g> كثيرة للغاية."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"سعة تخزين الجهاز اللوحي ممتلئة! احذف بعض الملفات لإخلاء مساحة."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"سعة تخزين المشاهدة ممتلئة! احذف بعض الملفات لتحرير مساحة."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"سعة تخزين الهاتف ممتلئة. احذف بعض الملفات لإخلاء مساحة."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"قد تكون الشبكة مراقبة"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"بواسطة جهة خارجية غير معلومة"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"تشغيل الرنين"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"جارٍ إيقاف التشغيل..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"سيتم إيقاف تشغيل الجهاز اللوحي."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"سيتم إيقاف المشاهدة."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"سيتم إيقاف تشغيل هاتفك."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"هل تريد إيقاف التشغيل؟"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"إعادة تشغيل في الوضع الآمن"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"وضع الطائرة"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"الوضع الآمن"</string>
     <string name="android_system_label" msgid="6577375335728551336">"‏نظام Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"إزالة الاختصارات"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"للسماح للتطبيق بإزالة اختصارات من الشاشة الرئيسية بدون تدخل المستخدم."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"إعادة توجيه المكالمات الصادرة"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"للسماح للتطبيق بالاطلاع على الرقم الذي يتم الاتصال به عند إجراء مكالمة صادرة مع وجود الخيار لإعادة توجيه المكالمة إلى رقم آخر أو إنهاء المكالمة تمامًا."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"للسماح للتطبيق بمعالجة المكالمات الصادرة وتغيير الرقم المطلوب. يتيح هذا الإذن للتطبيق مراقبة المكالمات الصادرة أو إعادة توجيهها أو منعها."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"‏تلقي رسائل نصية (رسائل قصيرة SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"‏للسماح للتطبيق بتلقي ومعالجة الرسائل القصيرة SMS. وهذا يعني أنه يمكن للتطبيق مراقبة الرسائل التي يتم إرسالها إلى جهازك أو حذفها بدون عرضها لك."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"تلقي رسائل نصية (رسائل وسائط متعددة)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"للسماح للتطبيق باسترداد محتوى النافذة النشطة. يمكن للبرامج الضارة استرداد محتوى النافذة بالكامل وفحص جميع النصوص الموجودة بها باستثناء كلمات المرور."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"تمكين إمكانية الدخول مؤقتًا"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"يتيح لتطبيق تمكين إمكانية الدخول مؤقتًا بالجهاز. قد تتيح التطبيقات الضارة تمكين إمكانية الدخول بدون موافقة المستخدم."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"استرداد النافذة التي تم التقاطها"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"يتيح للتطبيق استعادة النافذة التي تم التقاطها. وقد تتمكن التطبيقات الضارة من تنفيذ تفاعل غير مصرح به مع نافذة التطبيق التي تنتحل صفة النظام."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"استرداد الإحصاءات الإطارية"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"يتيح للتطبيق جمع إحصاءات إطارية. وقد تتمكن التطبيقات الضارة من رصد الإحصاءات الإطارية للنوافذ من تطبيقات أخرى."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"استرداد معلومات النوافذ"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"للسماح لأحد التطبيقات باستعادة معلومات حول النوافذ من مدير النوافذ. يمكن أن تستعيد التطبيقات الضارة معلومات الغرض منها استخدام النظام الداخلي."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"تصفية الأحداث"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"للسماح لأحد التطبيقات بتسجيل فلتر إدخال يعمل على تصفية مجموعة البث من جميع أحداث المستخدمين قبل إرسالها. يمكن أن يتحكم برنامج ضار في واجهة المستخدم النظام دون تدخل المستخدم."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"تكبير الشاشة"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"للسماح للتطبيق بتكبير محتوى شاشة. قد تؤدي التطبيقات الضارة إلى نقل محتوى الشاشة بطريقة تعرض الجهاز في وضع غير قابل للاستخدام."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"إيقاف تشغيل جزئي"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"لوضع مدير الأنشطة في حالة إيقاف التشغيل. لا يتم تنفيذ إيقاف تشغيل كامل."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"منع التبديل بين التطبيقات"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"‏للسماح للتطبيق ببث إشعار باستلام رسالة قصيرة SMS. قد تستخدم التطبيقات الضارة هذا لتزييف الرسائل القصيرة SMS الواردة."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"‏إرسال بث WAP-PUSH المستلم"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"‏للسماح للتطبيق ببث إشعار باستلام رسالة WAP PUSH. يمكن أن تستخدم التطبيقات الضارة هذا لتزيف استلام رسالة وسائط متعددة أو لاستبدال محتوى أي صفحة ويب بمتغيرات ضارة بشكل غير ملحوظ."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"إرسال بث الشبكات التي تم تقييمها"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"السماح للتطبيق لكي يبث إشعارًا يفيد بأنه يلزم تقييم الشبكات. لا يلزم ذلك مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"تحديد عدد العمليات قيد التشغيل"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"للسماح للتطبيق بالتحكم في الحد الأقصى لعدد العمليات التي سيتم تشغيلها. غير مطلوب على الإطلاق للتطبيقات العادية."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"فرض إغلاق تطبيقات الخلفية"</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"‏للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة الشبكة الظاهرية الخاصة (VPN). لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"الالتزام بخلفية ما"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"للسماح للمالك بالالتزام بواجهة المستوى العلوي للخلفية. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"الربط بالشاشة عن بُعد"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"السماح للتطبيق باستخدام أي برنامج فك تشفير وسائط مثبت لفك التشفير من أجل التشغيل."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"إدارة بيانات الاعتماد الموثوقة"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"‏السماح للتطبيق بتثبيت شهادات CA وإلغاء تثبيتها باعتبارها بيانات اعتماد محل ثقة."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"تشغيل التطبيق أثناء وقت الخمول"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"‏يتيح هذا الإذن لنظام Android تشغيل التطبيق في الخلفية في حين أن الجهاز ليس قيد الاستخدام."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"الالتزام بالخدمات الخاملة"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"‏يتيح هذا الإذن لنظام Android الارتباط بخدمات وضع الخمول لأحد التطبيقات."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"قراءة/كتابة إلى الموارد المملوكة بواسطة التشخيص"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"‏للسماح للتطبيق بالقراءة والكتابة إلى أي مورد مملوك بواسطة مجموعة التشخيصات؛ على سبيل المثال، الملفات في /dev. من المحتمل أن يؤثر ذلك في استقرار النظام وأمانه. يجب ألا يستخدم ذلك سوى للتشخيصات الخاصة بالنظام من قِبل المصنِّع أو المشغِّل."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"تمكين مكونات التطبيق أو تعطيلها"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"للسماح للتطبيق بقراءة المعلومات الشخصية في الملف الشخصي المخزنة على الجهاز، مثل اسمك ومعلومات جهات الاتصال. ويعني ذلك أنه يمكن للتطبيق التعرف عليك كما يمكنه إرسال معلومات ملفك الشخصي إلى الآخرين."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"تعديل بطاقة جهة الاتصال الخاصة"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"للسماح للتطبيق بتغيير المعلومات الشخصية في الملف الشخصي المخزنة على الجهاز أو الإضافة إليها، مثل اسمك ومعلومات جهات الاتصال. ويعني ذلك أنه يمكن للتطبيق التعرف عليك كما يمكنه إرسال معلومات ملفك الشخصي إلى الآخرين."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"أجهزة استشعار الجسم (مثل شاشات معدل ضربات القلب)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"للسماح للتطبيق بالدخول إلى البيانات من أجهزة الاستشعار التي تستخدمها لقياس ما يجري داخل جسمك، مثل معدل ضربات القلب."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"قراءة المشاركات الاجتماعية"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"للسماح للتطبيق بالدخول إلى التحديثات الاجتماعية منك ومن أصدقائك ومزامنتها. توخ الحذر عند مشاركة المعلومات، حيث يتيح هذا للتطبيق قراءة عمليات التواصل بينك وبين أصدقائك على الشبكات الاجتماعية، بغض النظر عن مدى السرية. ملاحظة: لا يجوز فرض هذا الإذن على جميع الشبكات الاجتماعية."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"كتابة إلى المشاركات الاجتماعية"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"للسماح للتطبيق بالتحكم في ميزات الهاتف بالجهاز. يمكن لأحد التطبيقات بهذا الإذن تبديل الشبكات وتشغيل لاسلكي الهاتف وإيقاف تشغيله وما إلى ذلك بدون إعلامك على الإطلاق."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"قراءة حالة الهاتف والهوية"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"للسماح للتطبيق بالدخول إلى ميزات الهاتف في الجهاز. ويتيح هذا الإذن للتطبيق تحديد رقم الهاتف ومعرّفات الجهاز، وما إذا كانت هناك مكالمة نشطة والرقم البعيد الذي تم الاتصال به في المكالمة."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"قراءة حالات الهاتف الدقيقة"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"للسماح للتطبيق بالوصول إلى حالات الهاتف الدقيقة. يتيح هذا الإذن للتطبيق تحديد حالة المكالمة الفعلية، سواء أكانت مكالمة نشطة أم في الخلفية، وإخفاق الاتصال، وحالة اتصال البيانات الدقيقة، وإخفاق اتصال البيانات."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"منع الجهاز اللوحي من الدخول في وضع السكون"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"منع الهاتف من الدخول في وضع السكون"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"للسماح للتطبيق بمنع الجهاز اللوحي من الانتقال إلى وضع السكون."</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"‏تغيير حالة WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"‏للسماح للتطبيق بتوصيل الجهاز اللوحي بشبكات WiMAX وقطع اتصاله بها."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"‏للسماح للتطبيق بتوصيل الهاتف بشبكات WiMAX وقطع اتصاله بها."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"تقييم الشبكات"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"للسماح للتطبيق بترتيب الشبكات وتحديد تلك الشبكات التي من المفضل أن يستخدمها الجهاز اللوحي."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"للسماح للتطبيق بترتيب الشبكات وتحديد تلك الشبكات التي من المفضل أن يستخدمها الهاتف."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"الاتصال بأجهزة بلوتوث"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"للسماح للتطبيق بعرض تهيئة البلوتوث على الجهاز اللوحي وإجراء اتصالات وقبولها مع الأجهزة المقترنة."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"للسماح للتطبيق بعرض تهيئة البلوتوث على الهاتف وإجراء اتصالات وقبولها مع الأجهزة المقترنة."</string>
@@ -703,18 +685,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"يتيح للتطبيق استرجاع الإشعارات وفحصها ومسحها، بما في ذلك تلك التي نشرتها تطبيقات أخرى."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"الربط بخدمة تلقّي الإشعارات الصوتية"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"يتيح للمالك الربط بواجهة المستوى العلوي لخدمة تلقّي الإشعارات الصوتية. ولن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"استدعاء تطبيق التهيئة الذي يوفره مشغل شبكة الجوال"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"للسماح للمالك باستدعاء تطبيق التهيئة الذي يوفره مشغل شبكة الجوال. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"الاستماع إلى ملاحظات حول أحوال الشبكة"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"للسماح للتطبيق بالاستماع إلى ملاحظات حول أحوال الشبكة. لا حاجة إلى هذا مع التطبيقات العادية."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"تغيير معايرة أجهزة الإدخال"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"يتيح للتطبيق إمكانية تعديل معلمات المعايرة في شاشة اللمس. يجب عدم اللجوء إليه مع التطبيقات العادية."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"‏الدخول إلى شهادات DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"‏للسماح لأحد التطبيقات بتقديم شهادات DRM واستخدامها. لا يجب أن يكون ذلك لازمًا مطلقًا مع التطبيقات العادية."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"تعيين قواعد كلمة المرور"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"يمكنك التحكم في الطول والأحرف المسموح بها في كلمات مرور إلغاء تأمين الشاشة."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"مراقبة محاولات إلغاء قفل الشاشة"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"السماح لأحد التطبيقات بالدخول إلى التخزين المحمي بقفل المفاتيح."</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>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"الالتزام بخدمة الوكيل المعتمد"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"للسماح لأحد التطبيقات بالالتزام بخدمة الوكيل المعتمد."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"التفاعل مع نظام التحديث والاسترداد"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"للسماح للتطبيق بالتفاعل مع نظام الاسترداد وتحديثات النظام."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"المس مرتين للتحكم في التكبير/التصغير"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"الخلفية"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"تغيير الخلفية"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"برنامج تلقّي الإشعارات الصوتية"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"‏تم تنشيط الشبكة الظاهرية الخاصة (VPN)"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"‏تم تنشيط VPN بواسطة <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"المس لإدارة الشبكة."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index d347db6..218d54a 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Синхронизиране"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Изтриванията за <xliff:g id="CONTENT_TYPE">%s</xliff:g> са твърде много."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Хранилището на таблета е пълно. Изтрийте файлове, за да освободите място."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Хранилището на часовника е пълно. Изтрийте файлове, за да освободите място."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Хранилището на телефона е пълно. Изтрийте файлове, за да освободите място."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мрежата може да се наблюдава"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"От неизвестна трета страна"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Звъненето е включено"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Изключва се..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Таблетът ви ще се изключи."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Часовникът ви ще се изключи."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Телефонът ви ще се изключи."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Искате ли да изключите?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Рестартиране в безопасен режим"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Самолетен режим"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безопасен режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Системно от Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"деинсталиране на преки пътища"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Разрешава на приложението да премахва преки пътища от началния екран без намеса на потребителя."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"пренасочване на изходящите обаждания"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Разрешава на приложението да вижда набирания номер по време на изходящо обаждане и му дава възможност да пренасочи обаждането към друг номер или да го прекрати изцяло."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Разрешава на приложението да обработва изходящите обаждания и да променя номера, който да се набере. Това разрешение му позволява да наблюдава, пренасочва или не допуска изходящи обаждания."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"получаване на текстови съобщения (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Разрешава на приложението да получава и обработва SMS съобщения. Това означава, че то може да наблюдава или изтрива изпратените до устройството ви, без да ви ги покаже."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"получаване на текстови съобщения (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Разрешава на приложението да извлича съдържанието от активния прозорец. Злонамерените приложения могат да извлекат цялото му съдържание и да проследят целия текст в него освен паролите."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"временно активиране на достъпността"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Разрешава на приложението временно да активира достъпността на устройството. Злонамерените приложения може да я активират без съгласието на потребителя."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"извличане на означението за прозорци"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Разрешава на приложението да извлича означението за прозорци. Представяйки се за системата, злонамерените приложения може да извършат неупълномощено взаимодействие с прозореца на приложението."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"извличане на статистически данни за кадрите"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Разрешава на приложението да събира статистически данни за кадрите. Злонамерените приложения може да наблюдават тези данни за прозорците на други приложения."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"извличане на информация за прозорците"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Разрешава на приложението да извлича информация за прозорците от съответния мениджър. Злонамерените приложения може да извличат данни, които са предназначени за вътрешно използване от системата."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"филтриране на събитията"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Разрешава на приложението да регистрира входящ филтър, който филтрира потока на всички потребителски събития преди изпращането им. Злонамерено приложение може да контролира системния потребителски интерфейс без намесата на потребителя."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"промяна на мащаба на дисплея"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Разрешава на приложението да променя мащаба на съдържанието на дисплей. Злонамерените приложения може да преобразят съдържанието на дисплея по начин, който изобразява устройството като неизползваемо."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"частично изключване"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Изключва диспечера на дейностите. Не извършва пълно изключване."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"предотвратяване на превключването между приложения"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Разрешава на приложението да излъчва известие, че е получен SMS. Злонамерените приложения могат да използват това, за да фалшифицират входящите SMS съобщения."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"изпращане на излъчване при получено WAP PUSH"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Разрешава на приложението да излъчва известие, че е получено WAP PUSH съобщение. Злонамерените приложения могат да използват това, за да фалшифицират получаването на MMS или скрито да заменят съдържанието на произволна уеб страница със злонамерен вариант."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"изпращане на излъчване за оценяване на мрежите"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Разрешава на приложението да излъчи известие, че мрежите трябва да бъдат оценени. Не е необходимо за нормалните приложения."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"ограничаване на броя изпълнявани процеси"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Разрешава на приложението да контролира максималния брой изпълнявани процеси. Нормалните приложения никога не се нуждаят от това."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"принудително затваряне на приложенията на заден план"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за VPN. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"обвързване с тапет"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на тапет. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"свързване с отдалечен екран"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Разрешава на притежателя да се свърже към интерфейса от най-високото ниво за вход на телевизор. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"добавяне или премахване на администратор на устройства"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Разрешава на притежателя да добавя или премахва администратори на активни устройства. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"промяна на ориентацията на екрана"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Разрешава на приложението да използва всеки инсталиран медиен декодер с цел декодиране за възпроизвеждане."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"управление на надеждните идентификационни данни"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Разрешава на приложението да инсталира и деинсталира сертификати от сертифициращи органи като надеждни идентификационни данни."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"изпълняване на приложението по време на неактивност"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Това разрешение позволява на системата Android да изпълнява приложението на заден план, докато устройството не се използва."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"обвързване с услуги при неактивност"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Това разрешение позволява на системата Android да се свързва с неактивните услуги на приложението."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"четене/запис в ресурси, притежавани от diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Разрешава на приложението да чете и записва във всеки ресурс, притежаван от групата diag, например файловете в /dev. Това потенциално може да засегне стабилността и сигурността на системата. То трябва да се използва САМО за диагностика, конкретно за хардуера, от страна на производителя или оператора."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"активиране или деактивиране на компоненти на приложенията"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Разрешава на приложението да чете информацията от личния потребителски профил, съхранена на устройството ви, например вашето име и данни за връзка. Това означава, че приложението може да ви идентифицира и да изпраща информацията за потребителския ви профил на други хора."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"промяна на собств. ви карт. с данни за контакт"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Разрешава на приложението да променя или добавя към личния потребителски профил информация, съхранена на устройството ви, като например вашето име и данни за връзка. Това означава, че приложението може да ви идентифицира и да изпраща данните за потребителския ви профил на други хора."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"телесни сензори (като монитори за сърдечния ритъм)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Разрешава на приложението да осъществява достъп до данни от използваните от вас сензори, за да измери какво се случва в тялото ви, като например сърдечен ритъм."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"четене на социалния ви поток"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Разрешава на приложението да осъществява достъп и да синхронизира социални актуализации от вас и приятелите ви. Бъдете внимателни при споделянето на информация – това позволява на приложението да чете съобщения помежду ви в социалните мрежи независимо от поверителността. Забележка: Възможно е ограниченията на това разрешение да не могат да бъдат наложени във всички социални мрежи."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"писане в социалния ви поток"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Разрешава на приложението да контролира телефонните функции на устройството. Приложение с такова разрешение може да превключва между мрежи, да включва и изключва радиомодула на телефона и други подобни, без изобщо да ви известява."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"четене на състоянието и идентификационните данни на телефона"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Разрешава на приложението достъп до телефонните функции на устройството. Това разрешение позволява на приложението да определя телефонния номер и идентификационния номер на устройството, дали се води разговор и отдалечения номер, до който е установена връзка с обаждането."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"четене на точните състояния на телефона"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Позволява на приложението да осъществява достъп до точните състояния на телефона. С това разрешение то може да определи действителното състояние на обаждането – дали е активно, или е на заден план, дали е неуспешно, точното състояние на връзката за пренос на данни и неуспешната връзка за пренос."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"предотвратяване на спящия режим на таблета"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"предотвратява спящ режим на телефона"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Разрешава на приложението да предотвратява преминаването на таблета в спящ режим."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Промяна на състоянието на WiMAX мрежата"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Разрешава на приложението да свързва таблета към WiMAX мрежа и да прекратява връзката му с нея."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Разрешава на приложението да свързва телефона към WiMAX мрежа и да прекратява връзката му с нея."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"оценяване на мрежите"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Разрешава на приложението да класира мрежите и да повлияе върху това, кои да са предпочитаните за таблета."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Разрешава на приложението да класира мрежите и да повлияе върху това, кои да са предпочитаните за телефона."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"сдвояване с устройства с Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Разрешава на приложението да вижда конфигурацията на Bluetooth на таблета и да изгражда и приема връзки със сдвоени устройства."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Разрешава на приложението да вижда конфигурацията на Bluetooth на телефона и да изгражда и приема връзки със сдвоени устройства."</string>
@@ -703,18 +683,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Разрешава на приложението да извлича, преглежда и изчиства известия, включително публикуваните от други приложения."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"обвързване с услуга за слушател на известия"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Разрешава на притежателя да се обвърже с интерфейса от първо ниво на услуга за слушател на известия. Нормалните приложения не би трябвало никога да се нуждаят от това."</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"извикване на предоставеното от оператора приложение за конфигуриране"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Разрешава на притежателя да извиква предоставеното от оператора приложение за конфигуриране. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"слушане за наблюдения на мрежовите условия"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Разрешава на приложението да слуша за наблюдения на мрежовите условия. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"промяна на калибрирането на устройството за въвеждане"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Разрешава на приложението да променя параметрите на калибриране на сензорния екран. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"достъп до сертификатите за управление на цифровите права (DRM)"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Разрешава на приложението да обезпечава и използва сертификатите за управление на цифровите права (DRM). Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Задаване на правила за паролата"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролирайте дължината и разрешените знаци за паролите за отключване на екрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Наблюдаване на опитите за отключване на екрана"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Позволява на приложението да осъществява достъп до надеждното хранилище, свързано с функцията за защита на клавишите."</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>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Обвързване с услуга за trust agents"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Разрешава на приложението да се обвърже с услуга за trust agents."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Взаимодействие със системата за актуализации и възстановяване"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Разрешава на приложението да взаимодейства със системата за възстановяване и системните актуализации."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Докоснете двукратно за управление на промяната на мащаба"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Тапет"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Промяна на тапета"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Слушател на известия"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN е активирана"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN е активирана от <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Докоснете за управление на мрежата."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index fce2c4e..44757fd 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -135,9 +135,8 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronització"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Massa supressions de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"L\'emmagatzematge de la tauleta és ple. Suprimeix uns quants fitxers per alliberar espai."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"L\'emmagatzematge del rellotge està ple. Suprimeix uns quants fitxers per alliberar espai."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"L\'emmagatzematge del telèfon és ple. Suprimeix uns quants fitxers per alliberar espai."</string>
-    <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"És possible que la xarxa estigui supervisada"</string>
+    <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Pot ser que la xarxa se supervisi."</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Per un tercer desconegut"</string>
     <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Per <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
     <string name="me" msgid="6545696007631404292">"Mi"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Timbre activat"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"S\'està apagant..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"La tauleta s\'apagarà."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"El rellotge s\'apagarà."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"El telèfon s\'apagarà."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Vols apagar-lo?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Reinicia en mode segur"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mode d\'avió"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"+999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode segur"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"desinstal·la dreceres"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Permet que l\'aplicació suprimeixi les dreceres de la pantalla d\'inici sense la intervenció de l\'usuari."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"desviació de les trucades sortints"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Permet que l\'aplicació vegi el número que s\'està marcant durant una trucada sortint, amb l\'opció de redirigir la trucada a un altre número o bé de cancel·lar-la completament."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Permet que l\'aplicació processi les trucades sortints i que canviï el número que es marcarà. Aquest permís permet que l\'aplicació supervisi, redirigeixi o bloquegi les trucades sortints."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"recepció de missatges de text (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Permet que l\'aplicació rebi i processi missatges SMS. Això vol dir que l\'aplicació pot controlar o suprimir missatges que s\'han enviat al teu dispositiu sense mostrar-te\'ls."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"recepció de missatges de text (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Permet que l\'aplicació recuperi el contingut de la finestra activa. Les aplicacions malicioses poden recuperar el contingut de tota la finestra i examinar-ne tot el text, excepte les contrasenyes."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"activació temporal de l\'accessibilitat"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Permet que una aplicació activi temporalment l\'accessibilitat al dispositiu. És possible que les aplicacions malicioses activin l\'accessibilitat sense el consentiment de l\'usuari."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"recuperació del testimoni de la finestra"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Permet que una aplicació recuperi el testimoni de la finestra. Les aplicacions malicioses poden suplantar la identitat del sistema per dur a terme una interacció no autoritzada amb la finestra de l\'aplicació."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"recuperació d\'estadístiques de fotogrames"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Permet que una aplicació recopili estadístiques de fotogrames. Les aplicacions malicioses poden veure les estadístiques de fotogrames de finestres d\'altres aplicacions."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"recupera informació de les finestres"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Permet que una aplicació recuperi informació sobre les finestres del gestor de finestres. Aplicacions malicioses podrien recuperar informació dirigida a la utilització per part del sistema intern."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filtra els esdeveniments"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Permet que una aplicació registri un filtre d\'entrada per a l\'emissió de tots els esdeveniments d\'usuari abans no s\'enviïn. Aplicacions malicioses podrien controlar la IU del sistema sense la intervenció de l\'usuari."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"augment de la pantalla"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Permet a una aplicació augmentar el contingut d\'una pantalla. Les aplicacions malicioses poden transformar el contingut de la pantalla de manera que el dispositiu no es pugui fer servir."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"apagar parcialment"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Posa el gestor d\'activitats en estat d\'apagada. No fa una apagada completa."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"impedir els canvis d\'aplicació"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permet que l\'aplicació difongui una notificació en què s\'indiqui que s\'ha rebut un missatge SMS. Les aplicacions malicioses poden fer servir aquesta funció per falsificar els missatges SMS entrants."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar una difusió de tipus WAP-PUSH-received"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permet que l\'aplicació difongui una notificació que indica que s\'ha rebut un missatge d\'inserció WAP. Les aplicacions malicioses poden utilitzar-ho per falsificar la recepció dels missatges MMS o per substituir silenciosament el contingut d\'una pàgina web per variants malicioses."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"enviar l\'emissió de la puntuació de les xarxes"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Permet que l\'aplicació emeti una notificació necessària perquè les xarxes rebin una puntuació. No es necessita mai per a les aplicacions normals."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar el nombre de processos en execució"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permet que l\'aplicació controli el nombre màxim de processos que s\'executaran. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"com fer que es tanquin les aplicacions en segon pla"</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei de VPN. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"enllaça amb un fons de pantalla"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permet que el titular vinculi a la interfície de nivell superior d\'un fons de pantalla. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"vincula a una pantalla remota"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permet que el titular es vinculi a la interfície de nivell superior d\'una pantalla remota. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincula a un servei de widget"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet que l\'aplicació utilitzi qualsevol descodificador de mitjans instal·lat per descodificar per a la reproducció."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestiona les credencials de confiança"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet que l\'aplicació instal·li i desinstal·li certificats de CA com a credencials de confiança."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"executar l\'aplicació durant el temps d\'inactivitat"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Aquest permís permet que el sistema Android executi l\'aplicació en segon pla mentre el dispositiu no està en ús."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"vincula als serveis inactius"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Amb aquest permís, el sistema Android podrà vincular-se amb els serveis inactius d\'una aplicació."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"llegir/escriure recursos propietat de diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet que l\'aplicació llegeixi i escrigui a qualsevol recurs propietat del grup diag; per exemple, els fitxers de /dev. Això podria afectar l\'estabilitat i la seguretat del sistema. NOMÉS l\'hauria d\'utilitzar el fabricant o l\'operador per a diagnòstics específics de maquinari."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activa o desactiva els components de l\'aplicació"</string>
@@ -447,19 +436,19 @@
     <string name="permdesc_grantRevokePermissions" msgid="4088642654085850662">"Permet que una aplicació concedeixi o denegui permisos específics per a aquesta o per a altres aplicacions. És possible que les aplicacions malicioses ho facin servir per accedir a funcions a les quals no has concedit accés."</string>
     <string name="permlab_setPreferredApplications" msgid="8463181628695396391">"defineix les aplicacions preferides"</string>
     <string name="permdesc_setPreferredApplications" msgid="4973986762241783712">"Permet que l\'aplicació modifiqui les aplicacions preferides. Les aplicacions malicioses poden canviar silenciosament les aplicacions que s\'executen, falsejar les aplicacions existents o recollir dades privades de l\'usuari."</string>
-    <string name="permlab_writeSettings" msgid="2226195290955224730">"modificar la configuració del sistema"</string>
+    <string name="permlab_writeSettings" msgid="2226195290955224730">"modificació de la configuració del sistema"</string>
     <string name="permdesc_writeSettings" msgid="7775723441558907181">"Permet que l\'aplicació modifiqui les dades de configuració del sistema. Les aplicacions malicioses poden malmetre la configuració del sistema."</string>
     <string name="permlab_writeSecureSettings" msgid="204676251876718288">"modificar la configuració de seguretat del sistema"</string>
     <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"Permet que l\'aplicació modifiqui les dades de la configuració de seguretat del sistema. No indicat per a les aplicacions normals."</string>
     <string name="permlab_writeGservices" msgid="2149426664226152185">"modificar el mapa de serveis de Google"</string>
     <string name="permdesc_writeGservices" msgid="1287309437638380229">"Permet que l\'aplicació modifiqui el mapa dels serveis de Google. No la poden fer servir les aplicacions normals."</string>
-    <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"executar-se a l\'inici"</string>
+    <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"execució en iniciar"</string>
     <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Permet que l\'aplicació s\'iniciï tan bon punt el sistema hagi acabat d\'arrencar. Això pot fer que es trigui més a iniciar el telèfon i permetre a l\'aplicació alentir-ne el funcionament general en executar-se sempre."</string>
     <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Permet que l\'aplicació s\'iniciï tan bon punt el sistema hagi acabat d\'arrencar. Això pot fer que es trigui més a iniciar el telèfon i permetre a l\'aplicació alentir-ne el funcionament general si s\'executa sempre."</string>
     <string name="permlab_broadcastSticky" msgid="7919126372606881614">"enviar difusió permanent"</string>
     <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"Permet que l\'aplicació enviï emissions permanents, que es conserven després de finalitzar l\'emissió. L\'ús excessiu pot alentir o desestabilitzar la tauleta si li fan utilitzar massa memòria."</string>
     <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Permet que l\'aplicació enviï emissions permanents, que es conserven després de finalitzar l\'emissió. L\'ús excessiu pot alentir o desestabilitzar el telèfon si li fan utilitzar massa memòria."</string>
-    <string name="permlab_readContacts" msgid="8348481131899886131">"consultar els contactes"</string>
+    <string name="permlab_readContacts" msgid="8348481131899886131">"lectura dels contactes"</string>
     <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Permet que l\'aplicació llegeixi dades sobre els contactes que tinguis emmagatzemats a la tauleta, inclosa la freqüència amb què has trucat, has enviat correus electrònics o t\'has comunicat d\'altres maneres amb persones concretes. Aquest permís permet que les aplicacions desin les dades dels teus contactes, i és possible que les aplicacions malicioses comparteixin dades dels contactes sense el teu coneixement."</string>
     <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Permet que l\'aplicació llegeixi dades sobre els contactes que tinguis emmagatzemats al telèfon, inclosa la freqüència amb què has trucat, has enviat correus electrònics o t\'has comunicat d\'altres maneres amb persones concretes. Aquest permís permet que les aplicacions desin les dades dels teus contactes, i és possible que les aplicacions malicioses comparteixin dades dels contactes sense el teu coneixement."</string>
     <string name="permlab_writeContacts" msgid="5107492086416793544">"modificar els teus contactes"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Permet que l\'aplicació pugui llegir informació del perfil personal emmagatzemada al dispositiu, com ara el teu nom i la teva informació de contacte. Això significa que l\'aplicació et pot identificar i enviar la informació del teu perfil a altres persones."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"modificació targeta contacte"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Permet que l\'aplicació pugui canviar o afegir informació del perfil personal emmagatzemada al dispositiu, com ara el teu nom i la teva informació de contacte. Això significa que l\'aplicació et pot identificar i enviar la informació del teu perfil a altres persones."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"sensors corp. (monitors freq. cardíaca)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Permet que l\'aplicació accedeixi a les dades dels sensors que utilitzes per mesurar els signes vitals del teu cos, com ara la freqüència cardíaca."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"llegeix el teu tauler d\'activitat social"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Permet que l\'aplicació accedeixi i sincronitzi actualitzacions socials teves i dels teus amics. Vés amb compte en compartir informació: això permet que l\'aplicació llegeixi comunicacions entre tu i els teus amics a les xarxes socials, independentment de la confidencialitat. Nota: És possible que aquest permís no s\'apliqui a totes les xarxes socials."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"escriu al tauler d\'activitat social"</string>
@@ -523,7 +510,7 @@
     <string name="permdesc_recordAudio" msgid="4906839301087980680">"Permet que l\'aplicació enregistri àudio amb el micròfon. Aquest permís permet que l\'aplicació enregistri àudio en qualsevol moment sense la teva confirmació."</string>
     <string name="permlab_sim_communication" msgid="1180265879464893029">"comunicació SIM"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"Permet que l\'aplicació enviï ordres a la SIM. Això és molt perillós."</string>
-    <string name="permlab_camera" msgid="3616391919559751192">"fer fotos i vídeos"</string>
+    <string name="permlab_camera" msgid="3616391919559751192">"fes fotos i vídeos"</string>
     <string name="permdesc_camera" msgid="8497216524735535009">"Permet que l\'aplicació faci fotos i vídeos amb la càmera. Aquest permís permet que l\'aplicació utilitzi la càmera en qualsevol moment sense la teva confirmació."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"desactiva la transmissió del LED indicador en fer servir la càmera"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permet que una aplicació dels sistema preinstal·lada desactivi el LED indicador d\'ús de la càmera."</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permet que l\'aplicació controli les funcions de telèfon del dispositiu. Una aplicació amb aquest permís pot canviar de xarxa, activar i desactivar el senyal mòbil i dur a terme accions semblants sense notificar-t\'ho."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"veure l\'estat i la identitat del telèfon"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permet que l\'aplicació accedeixi a les funcions de telèfon del dispositiu. Aquest permís permet que l\'aplicació determini el número de telèfon i els identificadors del dispositiu, si hi ha una trucada activa i el número remot connectat amb una trucada."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"llegeix els estats exactes del telèfon"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permet que l\'aplicació accedeixi als estats exactes del telèfon. Amb aquest permís, l\'aplicació pot determinar l\'estat real de la trucada, si la trucada està activa o en segon pla, si s\'ha produït algun error, l\'estat exacte de la connexió de dades i els errors de la connexió de dades."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"evita que la tauleta entri en mode d\'inactivitat"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir que el telèfon entri en mode de repòs"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permet que l\'aplicació impedeixi que la tauleta entri en repòs."</string>
@@ -613,7 +598,7 @@
     <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Permet que l\'aplicació obtingui la llista de comptes coneguts pel telèfon. Això pot incloure tots els comptes que hagin creat les aplicacions que tens instal·lades."</string>
     <string name="permlab_authenticateAccounts" msgid="5265908481172736933">"creació de comptes i definició de contrasenyes"</string>
     <string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"Permet que l\'aplicació utilitzi les funcions d\'autenticador de comptes del gestor de comptes, incloses la creació de comptes i l\'obtenció i la definició de les seves contrasenyes."</string>
-    <string name="permlab_manageAccounts" msgid="4983126304757177305">"afegir o eliminar comptes"</string>
+    <string name="permlab_manageAccounts" msgid="4983126304757177305">"addició o eliminació de comptes"</string>
     <string name="permdesc_manageAccounts" msgid="8698295625488292506">"Permet que l\'aplicació dugui a terme operacions com ara afegir i eliminar comptes i suprimir-ne la contrasenya."</string>
     <string name="permlab_useCredentials" msgid="235481396163877642">"fer servir comptes del dispositiu"</string>
     <string name="permdesc_useCredentials" msgid="7984227147403346422">"Permet que l\'aplicació sol·liciti testimonis d\'autenticació."</string>
@@ -647,19 +632,16 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Canvia l\'estat de WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permet que l\'aplicació connecti i desconnecti la tauleta de les xarxes WiMAX."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permet que l\'aplicació connecti i desconnecti el telèfon de les xarxes WiMAX."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"puntuar les xarxes"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Permet que l\'aplicació classifiqui les xarxes i indiqui quines han de ser les xarxes preferides de la tauleta."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Permet que l\'aplicació classifiqui les xarxes i indiqui quines han de ser les xarxes preferides del telèfon."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"emparella amb dispositius Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permet que l\'aplicació visualitzi la configuració de Bluetooth de la tauleta i que estableixi i accepti connexions amb dispositius sincronitzats."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permet que una aplicació visualitzi la configuració de Bluetooth del telèfon i que estableixi i accepti connexions amb els dispositius sincronitzats."</string>
-    <string name="permlab_nfc" msgid="4423351274757876953">"controlar Comunicació de camp proper (NFC)"</string>
+    <string name="permlab_nfc" msgid="4423351274757876953">"controla Near Field Communication (NFC)"</string>
     <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_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>
+    <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activació o desactivació de la sincronització"</string>
     <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Permet que una aplicació modifiqui la configuració de sincronització d\'un compte. Per exemple, aquesta acció es pot fer servir per activar la sincronització de l\'aplicació Persones amb un compte."</string>
     <string name="permlab_readSyncStats" msgid="7396577451360202448">"llegir les estadístiques de sincronització"</string>
     <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Permet que una aplicació llegeixi les estadístiques de sincronització d\'un compte, inclòs l\'historial d\'esdeveniments sincronitzats i quantes dades se sincronitzen."</string>
@@ -671,7 +653,7 @@
     <string name="permdesc_readDictionary" msgid="659614600338904243">"Permet que l\'aplicació llegeixi les paraules, els noms i les frases que l\'usuari pot haver emmagatzemat al seu diccionari."</string>
     <string name="permlab_writeDictionary" msgid="2183110402314441106">"afegeix paraules al diccionari definit per l\'usuari"</string>
     <string name="permdesc_writeDictionary" msgid="8185385716255065291">"Permet que l\'aplicació escrigui paraules noves al diccionari de l\'usuari."</string>
-    <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"consultar contingut emmagatzematge USB"</string>
+    <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"lectura contingut emmagat. USB"</string>
     <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"lectura del contingut de la targeta SD"</string>
     <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Permet que l\'aplicació llegeixi el contingut de l\'emmagatzematge USB."</string>
     <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Permet que l\'aplicació llegeixi el contingut de la targeta SD."</string>
@@ -701,20 +683,12 @@
     <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Permet que l\'aplicació modifiqui les marques de sòcols per a l\'encaminament"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"accedeix a les notificacions"</string>
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
+    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincula a un servei de processament de notificacions"</string>
+    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet que el titular vinculi la interfície de nivell superior d\'un servei de processament de notificacions. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invoca l\'aplicació de configuració proporcionada per l\'operador"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permet que el titular invoqui l\'aplicació de configuració proporcionada per l\'operador. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"conèixer les observacions sobre les condicions de la xarxa"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permet que una aplicació conegui les observacions sobre les condicions de la xarxa. No s\'ha de necessitar mai per a aplicacions normals."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"canviar el calibratge del dispositiu d\'entrada"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permet que l\'aplicació modifiqui els paràmetres de calibratge de la pantalla tàctil. No ha de ser mai necessari per a aplicacions normals."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"accedir als certificats de DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Permet que una aplicació proporcioni i utilitzi certificats de gestió de drets digitals (DRM, Digital Rights Management). No ha de ser mai necessari per a 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="policylab_watchLogin" msgid="914130646942199503">"Controlar intents de desbloqueig de pantalla"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permet que una aplicació accedeixi a l\'emmagatzematge protegit per contrasenya."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Controla si es mostra o s\'amaga el bloqueig de les tecles."</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permet que una aplicació controli el bloqueig de les tecles."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Escoltar els canvis de l\'estat de confiança"</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permet que una aplicació escolti els canvis en l\'estat de confiança."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Enllaçar amb el servei d\'un agent de confiança"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permet que una aplicació es vinculi amb el servei d\'un agent de confiança."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interacciona amb el sistema de recuperació i amb les actualitzacions"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Permet que una aplicació interaccioni amb el sistema de recuperació i amb les actualitzacions del sistema."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Toca dos cops per controlar el zoom"</string>
@@ -1376,9 +1346,7 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibilitat"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Fons de pantalla"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Canvia el fons de pantalla"</string>
-    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Oient de notificacions"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
+    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Processador de notificacions"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ha activat VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Toca per gestionar la xarxa."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 2f73544..c338661 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronizace"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Příliš mnoho smazaných položek služby <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Úložiště tabletu je plné. Uvolněte místo smazáním některých souborů."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Úložiště hodinek je plné. Uvolněte místo smazáním některých souborů."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Paměť telefonu je plná. Uvolněte místo smazáním některých souborů."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Síť může být monitorována"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Původce: neznámá třetí strana"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Vyzvánění zapnuto"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Vypínání..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tablet se vypne."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Hodinky se vypnou."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Váš telefon bude vypnut."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Chcete zařízení vypnout?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Restart v nouzovém režimu"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Režim V letadle"</string>
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Režim V letadle je ZAPNUTÝ"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Režim V letadle je VYPNUTÝ"</string>
-    <string name="global_action_settings" msgid="1756531602592545966">"Nastavení"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Nouzový režim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"odinstalace zástupců"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Umožňuje aplikaci odebrat zástupce z plochy bez zásahu uživatele."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"přesměrování odchozích hovorů"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Umožňuje aplikaci sledovat při odchozích hovorech volaná čísla a přesměrovat hovor na jiné číslo nebo jej zcela zrušit."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Umožňuje aplikaci zpracovávat odchozí hovory a měnit vytáčené číslo. Toto oprávnění umožňuje sledovat či přesměrovat odchozí hovory nebo jim zabránit."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"příjem textových zpráv (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Umožňuje aplikaci přijmout a zpracovat zprávy SMS. Znamená to, že aplikace může sledovat zprávy odeslané do vašeho zařízení nebo je smazat, aniž by se vám zobrazily."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"příjem textových zpráv (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Umožňuje aplikaci načíst obsah aktivního okna. Škodlivé aplikace mohou načíst obsah celého okna a prozkoumat všechen text kromě hesel."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"dočasná aktivace usnadnění přístupu"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Umožňuje aplikaci dočasně aktivovat usnadnění přístupu v zařízení. Škodlivé aplikace mohou usnadnění přístupu aktivovat bez souhlasu uživatele."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"načíst token okna"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Umožňuje aplikaci načíst token okna. Škodlivé aplikace se mohou vydávat za systém a provádět s oknem aplikace neoprávněné interakce."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"načíst statistiky rámců"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Umožňuje aplikaci shromažďovat statistiky rámců. Škodlivé aplikace mohou sledovat statistiky rámců oken ostatních aplikací."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"načítání informací o oknech"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Umožňuje aplikaci načíst informace o oknech ze správce oken. Škodlivé aplikace mnohou načíst informace, které slouží k internímu systémovému využití."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filtrování událostí"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Umožní aplikaci registrovat vstupní filtr, který filtruje stream všech uživatelských přenosů před jejich odvysíláním. Škodlivé aplikace mohou používat uživatelské rozhraní systému bez zásahu uživatele."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"zvětšit zobrazení"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Povoluje aplikaci zvětšit obsah displeje. Škodlivé aplikace mohou změnit zobrazení obsahu způsobem, který učiní zařízení nepoužitelným."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"částečné vypnutí"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Uvede správce činností do vypnutého stavu. Nedojde však k úplnému vypnutí."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"zabránění přepínání aplikací"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Umožňuje aplikaci vysílat oznámení o přijetí zprávy SMS. Škodlivé aplikace mohou toto oprávnění použít k vytváření falešných příchozích zpráv SMS."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"odeslání vysílání typu WAP-PUSH-received"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Umožňuje aplikaci vysílat oznámení o přijetí zprávy WAP PUSH. Škodlivé aplikace mohou toto oprávnění použít k vytváření falešných přijatých zpráv MMS nebo utajenému nahrazení obsahu libovolné webové stránky jejich škodlivými variantami."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"odeslání skóre vysílaných sítěmi"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Umožňuje aplikaci vysílat oznámení, že je třeba zadat skóre sítí. Běžné aplikace toto oprávnění nepotřebují."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"omezení počtu spuštěných procesů"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Umožňuje aplikaci řídit maximální počet spuštěných procesů. Běžné aplikace toto oprávnění nikdy nepotřebují."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"vynucení zavření aplikací na pozadí"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Umožňuje držiteli navázat se na nejvyšší úroveň služby VPN. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"vazba na tapetu"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní tapety. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"připojit se ke vzdálenému displeji"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Umožňuje držiteli připojit se k vysokoúrovňovému rozhraní vzdáleného displeje. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"navázat se na službu widgetu"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní televizního vstupu. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"přidat nebo odebrat správce zařízení"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Opravňuje držitele přidávat nebo odebírat aktivní správce zařízení. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"změna orientace obrazovky"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Umožňuje aplikaci používat libovolný nainstalovaný dekodér médií k dekódování při přehrávání."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"správa důvěryhodných identifikačních údajů"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Umožňuje aplikaci instalovat a odinstalovat certifikáty CA jako důvěryhodné identifikační údaje."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"spustit aplikaci během nečinnosti"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Toto oprávnění umožňuje systému Android spustit aplikaci na pozadí, když zařízení není používáno."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"napojit se na nečinné služby"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Toto oprávnění umožní systému Android vázat se na nečinné služby aplikace."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"čtení nebo zápis do prostředků funkce diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Umožňuje aplikaci číst libovolné prostředky ve skupině diag, např. soubory ve složce /dev, a zapisovat do nich. Může dojít k ovlivnění stability a bezpečnosti systému. Toto nastavení by měl používat POUZE výrobce či operátor pro diagnostiku hardwaru."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivace či deaktivace komponent aplikací"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Umožňuje aplikaci číst údaje v osobním profilu uložené v zařízení, například jméno nebo kontaktní údaje. Znamená to, že vás aplikace může identifikovat a odeslat údaje z profilu dalším aplikacím."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"úprava vaší vlastní vizitky"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Umožňuje aplikaci změnit nebo přidat údaje osobního profilu uložené v zařízení, například jméno nebo kontaktní údaje. Znamená to, že vás aplikace může identifikovat a odeslat údaje z profilu dalším aplikacím."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"tělesné senzory (například snímače tepu)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Umožňuje aplikaci přistupovat k datům ze senzorů, pomocí kterých měříte činnost svého těla, například tep."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"čtení vašeho sociálního streamu"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Umožňuje aplikaci získat přístup k sociálním aktualizacím od vašich přátel a synchronizaci těchto aktualizací. Při sdílení informací buďte opatrní – toto oprávnění umožňuje aplikaci číst komunikaci mezi vámi a vašimi přáteli v sociálních sítích bez ohledu na její důvěrnost. Poznámka: Toto oprávnění nemusí platit pro všechny sociální sítě."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"zápis do sociálního streamu"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Umožňuje aplikaci ovládat telefonní funkce zařízení. Aplikace s tímto oprávněním smí bez upozornění přepínat sítě, zapínat a vypínat bezdrátový modul telefonu a podobně."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"čtení stavu a identity telefonu"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Umožňuje aplikaci získat přístup k telefonním funkcím zařízení. Toto oprávnění umožňuje aplikaci zjistit telefonní číslo telefonu, identifikační čísla zařízení, zda zrovna probíhá hovor, a vzdálené číslo, ke kterému je hovor připojen."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"čtení přesného stavu telefonování"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Umožňuje aplikaci zjišťovat přesný stav telefonování a mobilních dat. Toto oprávnění aplikaci umožňuje zjistit skutečný stav volání, zda je volání aktivní nebo na pozadí, zda volání selhalo, přesný stav datového připojení a zda datové připojení selhalo."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"bránění přechodu tabletu do režimu spánku"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"bránění přechodu telefonu do režimu spánku"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Umožňuje aplikaci zabránit přechodu tabletu do režimu spánku."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Změnit stav připojení WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Umožňuje aplikaci připojovat tablet k sítím WiMAX a odpojovat jej od nich."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Umožňuje aplikaci připojovat telefon k sítím WiMAX a odpojovat jej od nich."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"zadání skóre sítí"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Umožňuje aplikaci hodnotit sítě a ovlivňovat, které sítě by měl tablet preferovat."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Umožňuje aplikaci hodnotit sítě a ovlivňovat, které sítě by měl telefon preferovat."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"párování se zařízeními Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Umožňuje aplikaci zobrazit konfiguraci tabletu s rozhraním Bluetooth, vytvářet připojení ke spárovaným zařízením a přijímat tato připojení."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Umožňuje aplikaci zobrazit konfiguraci telefonu s rozhraním Bluetooth, vytvářet připojení ke spárovaným zařízením a přijímat tato připojení."</string>
@@ -703,18 +683,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"vyvolat konfigurační aplikaci poskytnutou operátorem"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Umožňuje vyvolání konfigurační aplikace poskytnuté operátorem. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"naslouchat informacím o stavu sítě"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Umožňuje aplikaci naslouchat informacím o stavu sítě. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"měnit kalibraci vstupního zařízení"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Umožňuje aplikaci měnit parametry kalibrace dotykové obrazovky. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"přístup k certifikátům DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Umožňuje aplikaci vydávat a používat certifikáty DRM. 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="policylab_watchLogin" msgid="914130646942199503">"Sledovat pokusy o odemčení obrazovky"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Umožňuje aplikaci přístup k bezpečnému úložišti keyguard."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Ovládání zobrazování a skrývání zámku obrazovky"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Umožňuje aplikaci ovládat zámek obrazovky."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Naslouchat změnám stavu důvěryhodnosti"</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Umožňuje aplikaci naslouchat změnám ve stavu důvěryhodnosti."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Vázat se na službu zástupce důvěryhodnosti"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Umožňuje aplikaci vázat se na službu zástupce důvěryhodnosti."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interakce se systémem aktualizací a obnovení"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Umožňuje aplikaci interakci se systémem obnovení a s aktualizacemi systému."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Dvojitým dotykem můžete ovládat přiblížení"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Změnit tapetu"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Aplikace poslouchající oznámení"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"Síť VPN je aktivována"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Aplikace <xliff:g id="APP">%s</xliff:g> aktivovala síť VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Dotykem zobrazíte správu sítě."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index d1ab769..d8babe9 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -46,7 +46,7 @@
     <string name="badPin" msgid="9015277645546710014">"Den gamle pinkode, som du har indtastet, er ikke korrekt."</string>
     <string name="badPuk" msgid="5487257647081132201">"Den indtastede PUK-kode er forkert."</string>
     <string name="mismatchPin" msgid="609379054496863419">"De indtastede pinkoder er ikke ens"</string>
-    <string name="invalidPin" msgid="3850018445187475377">"Indtast en pinkode på mellem 4 og 8 tal."</string>
+    <string name="invalidPin" msgid="3850018445187475377">"Indtast en PIN-kode på mellem 4 og 8 tal."</string>
     <string name="invalidPuk" msgid="8761456210898036513">"Angiv en PUK-kode på 8 eller flere cifre."</string>
     <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>
@@ -63,12 +63,12 @@
     <string name="CwMmi" msgid="9129678056795016867">"Ventende opkald"</string>
     <string name="BaMmi" msgid="455193067926770581">"Opkaldsspærring"</string>
     <string name="PwdMmi" msgid="7043715687905254199">"Ændring af adgangskode"</string>
-    <string name="PinMmi" msgid="3113117780361190304">"ændring af pinkode"</string>
+    <string name="PinMmi" msgid="3113117780361190304">"ændring af PIN-kode"</string>
     <string name="CnipMmi" msgid="3110534680557857162">"Opkaldsnummeret er til stede"</string>
     <string name="CnirMmi" msgid="3062102121430548731">"Opkaldsnummeret er begrænset"</string>
     <string name="ThreeWCMmi" msgid="9051047170321190368">"Trevejsopkald"</string>
     <string name="RuacMmi" msgid="7827887459138308886">"Afvisning af uønskede, irriterende opkald"</string>
-    <string name="CndMmi" msgid="3116446237081575808">"Levering af nummervisning"</string>
+    <string name="CndMmi" msgid="3116446237081575808">"Levering af opkaldsnummer"</string>
     <string name="DndMmi" msgid="1265478932418334331">"Forstyr ikke"</string>
     <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Standarder for opkalds-id til begrænset. Næste opkald: Begrænset"</string>
     <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Standarder for opkalds-id til begrænset. Næste opkald: Ikke begrænset"</string>
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synkroniser"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"For mange <xliff:g id="CONTENT_TYPE">%s</xliff:g> sletninger"</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Din tablets lager er fuldt. Slet nogle filer for at frigøre plads."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Urets lager er fuldt. Slet nogle filer for at frigøre plads."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Telefonens lager er fuldt. Slet nogle filer for at frigøre plads."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netværket kan være overvåget"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Af en ukendt tredjepart"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Ringeren er aktiveret"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Lukker ned..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Din tablet slukkes nu."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Dit ur lukkes ned."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Din telefon slukkes nu."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Vil du slukke?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Genstart i sikker tilstand"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flytilstand"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
@@ -244,7 +241,7 @@
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"undersøge indholdet i et vindue, du interagerer med."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"aktivere Udforsk ved berøring"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="5800552516779249356">"De emner, der trykkes på, læses højt, og skærmen kan udforskes ved hjælp af bevægelser."</string>
-    <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"aktivere forbedrede webhjælpefunktioner"</string>
+    <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"aktivere forbedret webhjælpefunktioner"</string>
     <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Der installeres muligvis scripts for at gøre appindhold mere tilgængeligt."</string>
     <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"observere tekst, du skriver"</string>
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Dette omfatter personlige data såsom kreditkortnumre og adgangskoder."</string>
@@ -259,15 +256,15 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"afinstaller genveje"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Tillader, at applikationen fjerner genveje på startskærmen uden brugerindgriben."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"omdirigere udgående opkald"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Tillader, at appen kan se det nummer, der ringes op til under et udgående opkald, og giver mulighed for at omdirigere opkaldet til et andet nummer eller afbryde opkaldet helt."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Tillader, at appen kan behandle udgående opkald og ændre det nummer, der skal ringes til. Med denne tilladelse kan appen overvåge, omdirigere eller forhindre udgående opkald."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"modtage tekstbeskeder (sms)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Tillader, at appen kan modtage og behandle sms-beskeder. Det betyder, at appen kan overvåge eller slette de beskeder, der sendes til din enhed, uden at vise dem til dig."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"modtage tekstbeskeder (mms)"</string>
     <string name="permdesc_receiveMms" msgid="533019437263212260">"Tillader, at appen kan modtage og behandle mms-beskeder. Det betyder, at appen kan overvåge eller slette de beskeder, der sendes til din enhed, uden at vise dem til dig."</string>
     <string name="permlab_receiveEmergencyBroadcast" msgid="1803477660846288089">"modtage nødudsendelser"</string>
     <string name="permdesc_receiveEmergencyBroadcast" msgid="848524070262431974">"Tillader, at appen kan modtage og behandle nødtransmissioner. Denne tilladelse er kun tilgængelig for systemapps."</string>
-    <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"læse Cell Broadcast-beskeder"</string>
-    <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Tillader, at appen læser Cell Broadcast-beskeder, der modtages af din enhed. I nogle områder sendes der Cell Broadcast-beskeder for at advare om nødsituationer. Ondsindede apps kan forstyrre ydelsen eller driften af ​din ​enhed, når der modtages en Cell Broadcast-besked om en nødsituation."</string>
+    <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"læse mobiltransmissionsbeskeder"</string>
+    <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Tillader, at appen læser mobiltransmissionsbeskeder, der modtages af din enhed. I nogle områder sendes mobiltransmissionsbeskeder for at advare om nødsituationer. Ondsindede apps kan forstyrre ydelsen eller driften af ​din ​enhed, når en mobiltransmission om en nødsituation modtages."</string>
     <string name="permlab_sendSms" msgid="5600830612147671529">"send sms-beskeder"</string>
     <string name="permdesc_sendSms" msgid="7094729298204937667">"Tillader, at appen kan sende sms-beskeder. Dette kan resultere i uventede opkrævninger. Skadelige apps kan koste dig penge ved at sende beskeder uden din bekræftelse."</string>
     <string name="permlab_sendRespondViaMessageRequest" msgid="8713889105305943200">"send hændelser, hvor der skal svares pr. besked"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Tillader, at appen kan hente indholdet i det aktive vindue. Ondsindede apps kan hente al indholdet i vinduet og undersøge al dens tekst med undtagelse af adgangskoder."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"aktivere hjælpefunktioner midlertidigt"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Tillader, at en app midlertidigt kan aktivere hjælpefunktioner på enheden. Skadelige apps kan muligvis aktivere hjælpefunktioner uden brugerens samtykke."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"hente vinduestoken"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Tillader, at en applikation kan hente vinduestokenet. Skadelige apps udfører muligvis uautoriseret interaktion med applikationsvinduet ved at efterligne systemet."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"hente rammestatistik"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Tillader, at en applikation kan indsamle rammestatistik. Skadelige apps kan muligvis observere rammestatistikker for vinduer fra andre apps."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"hent oplysninger om vinduer"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Tillader, at en applikation henter oplysninger om vinduerne i vinduesadministratoren. Skadelige apps kan muligvis hente oplysninger, der er beregnet til intern systembrug."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filtrer begivenheder"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Tillader, at en applikation registrerer et inputfilter, som filtrerer alle brugeres strøm, før disse afsendes. Skadelige apps kan muligvis kontrollere systemets grænseflade uden brugerens deltagelse."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"forstør skærmen"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Tillader, at applikationer kan forstørre indholdet på en skærm. Skadelige apps kan omdanne skærmindholdet, så enheden bliver ubrugelig."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"delvis lukning"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Sætter aktivitetsadministratoren i lukningstilstand. Lukker ikke helt ned."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"undgå programskift"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Tillader, at appen kan udsende en underretning om, at der er modtaget en sms-besked. Ondsindede apps kan bruge dette til at simulere indgående sms-beskeder."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"send WAP-PUSH-modtaget udsendelse"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Tillader, at appen kan udsende en underretning om, at der er modtaget en WAP PUSH-besked. Ondsindede apps kan bruge dette til at simulere modtagelse af mms-beskeder eller i det skjulte erstatte indholdet på en webside med ondsindede varianter."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"sende underretninger om bedømmelse af netværk"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Tillader, at appen kan udsende en underretning om, at netværket skal bedømmes. Dette er aldrig nødvendigt for almindelige apps."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"begræns antallet af kørende processer"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Tillader, at appen kan kontrollere det maksimale antal kørende processer. Dette er aldrig nødvendigt til normale apps."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"tvinge baggrundsapps til at lukke"</string>
@@ -385,18 +380,12 @@
     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Tillader, at ejeren kan binde en teksttjenestes grænseflade (f. eks. SpellCheckerService) på øverste niveau. Dette bør aldrig være nødvendigt til normale apps."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"bind til en VPN-tjeneste"</string>
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Tillader, at brugeren forpligter sig til en VPN-tjenestes grænseflade på øverste niveau. Bør aldrig være nødvendigt i almindelige apps."</string>
-    <string name="permlab_bindWallpaper" msgid="8716400279937856462">"knyt til en baggrund"</string>
+    <string name="permlab_bindWallpaper" msgid="8716400279937856462">"forpligt til et tapet"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Tillader, at indehaveren kan binde en baggrunds grænseflade på øverste niveau. Dette bør aldrig være nødvendigt for almindelige apps."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind til en ekstern skærm"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Tillader, at brugeren kan foretage en binding til grænsefladens øverste niveau på en ekstern skærm. Bør aldrig være nødvendigt til almindelige apps."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"forpligt til en widgettjeneste"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Tillader, at appen bruger enhver installeret medieafkoder til at afkode til afspilning."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrer pålidelige logonoplysninger"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Tillader, at appen installerer og afinstallerer CA-certifikater som pålidelige loginoplysninger."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"kør applikation, mens enheden er i dvale"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Med denne tilladelse kan Android-systemet køre applikationen i baggrunden, mens enheden ikke er i brug."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"knyt til tjenester i dvale"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Med denne tilladelse kan Android-systemet bindes til en applikations dvaletjenester."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"læs/skriv til ressourcer ejet af diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Tillader, at appen kan læse og skrive til alle ressourcer, der ejes af diag-gruppen,  f.eks. filer i /dev. Dette kan muligvis påvirke systemets stabilitet og sikkerhed. Dette bør KUN bruges til hardwarespecifik diagnosticering, som foretages af producenten eller udbyderen."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivere eller deaktivere appkomponenter"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Tillader, at appen kan læse de personlige profiloplysninger, der er gemt på din enhed, f.eks. dit navn og dine kontaktoplysninger. Det betyder, at appen kan identificere dig og sende dine profiloplysninger til andre."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"ændre dit eget kontaktkort"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Tillader, at appen kan ændre eller tilføje oplysninger i din personlige profil, der er gemt på din enhed, f.eks. dit navn eller dine kontaktoplysninger. Dette betyder, at andre apps kan identificere dig og sende profiloplysninger til andre."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"kropssensorer (f.eks. pulsmålere)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Tillader, at appen får adgang til data fra sensorer, du bruger til at måle, hvad der sker inde i din krop, f.eks. din puls."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"læs din sociale strøm"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Tillader, at appen kan få adgang til og synkronisere sociale opdateringer fra dig og dine venner. Vær forsigtig, når du deler oplysninger – med denne tilladelse kan appen læse kommunikation mellem dig og dine venner på sociale netværk, uanset fortrolighed. Bemærk! Denne tilladelse håndhæves muligvis ikke på alle sociale netværk."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"skriv i din sociale strøm"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Tillader, at appen kan styre enhedens telefonfunktioner. En app med denne tilladelse kan skifte netværk, slå telefonsenderen til og fra og lignende uden at underrette dig."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"læse telefonens status og identitet"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Tillader, at appen kan få adgang til telefonfunktionerne på enheden. Med denne tilladelse kan appen fastslå telefonnummeret og enheds-id\'erne, hvorvidt et opkald er aktivt samt det eksterne nummer, der oprettes forbindelse til via et opkald."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"læse nøjagtig status for telefonen"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Tillader, at appen får adgang til den nøjagtige status for telefonen. Denne tilladelse giver appen mulighed for at fastlægge den rigtige opkaldsstatus – om et opkald er aktivt eller kører i baggrunden, om opkaldet mislykkes, hvad den nøjagtige status for dataforbindelsen er, og om dataforbindelsen mislykkes."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"afholde tabletcomputeren fra at gå i dvale"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"afholde telefonen fra at gå i dvale"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Tillader, at appen kan forhindre tabletten i at gå i dvale."</string>
@@ -594,7 +579,7 @@
     <string name="permlab_factoryTest" msgid="3715225492696416187">"kør i fabriksindstillet testtilstand"</string>
     <string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Kør som en producenttest på lavt niveau, der giver fuld adgang til tabletens hardware. Kun tilgængeligt når en tablet kører i producenttesttilstand."</string>
     <string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Kør som en producenttest på lavt niveau. Giver fuld adgang til telefonens hardware. Kun tilgængeligt når en telefon kører i producenttesttilstand."</string>
-    <string name="permlab_setWallpaper" msgid="6627192333373465143">"angive baggrund"</string>
+    <string name="permlab_setWallpaper" msgid="6627192333373465143">"angiv tapet"</string>
     <string name="permdesc_setWallpaper" msgid="7373447920977624745">"Tillader, at appen kan konfigurere systembaggrunden."</string>
     <string name="permlab_setWallpaperHints" msgid="3278608165977736538">"ændre størrelsen på din baggrund"</string>
     <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"Tillader, at appen giver tips til systembaggrundens størrelse."</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Skift WiMAX-tilstand"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Tillader, at appen kan oprette forbindelse fra tabletten og afbryde forbindelsen til tabletten på WiMAX-netværk."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Tillader, at appen kan oprette forbindelse fra telefonen og afbryde forbindelsen til telefonen på WiMAX-netværk."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"bedømme netværk"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Tillader, at appen rangerer netværk og påvirker, hvilke netværk tabletten bør foretrække."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Tillader, at appen rangerer netværk og påvirker, hvilke netværk telefonen bør foretrække."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"parre med Bluetooth-enheder"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Tillader, at appen kan læse konfigurationen af ​​Bluetooth på tabletten samt kan oprette og acceptere forbindelser med parrede enheder."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Tillader, at appen kan læse konfigurationen af ​​Bluetooth på telefonen samt kan oprette og acceptere forbindelser med parrede enheder."</string>
@@ -703,18 +685,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"aktivere konfigurationsappen, der leveres af mobilselskabet"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Tillader, at brugeren aktiverer konfigurationsappen, der er forsynet af mobilselskabet. Dette bør aldrig være nødvendigt for almindelige apps."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"observer netværksforhold"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Tillader, at en applikation observerer netværksforhold. Bør aldrig være nødvendigt for almindelige apps."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"skift kalibrering for inputenheden"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Tillader, at appen ændrer kalibreringsparametrene for berøringsskærmen. Dette bør aldrig være nødvendigt for almindelige apps."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"få adgang til DRM-certifikater"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Tillader, at en applikation leverer og anvender DRM-certfikater. Dette bør aldrig være nødvendigt for almindelige 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="policylab_watchLogin" msgid="914130646942199503">"Overvåg forsøg på oplåsning af skærm"</string>
@@ -1185,7 +1159,7 @@
     <string name="smv_process" msgid="5120397012047462446">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> har overtrådt sin egen StrictMode-politik."</string>
     <string name="android_upgrading_title" msgid="1584192285441405746">"Android opgraderes..."</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_upgrading_starting_apps" msgid="451464516346926713">"Åbner dine apps."</string>
+    <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Sådan åbner du 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>
     <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Tryk for at skifte til appen"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Tillader, at en applikation får adgang til et nøglebeskyttet lager."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Administrer, om nøglebeskyttelse skal vises eller skjules"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Tillader, at en applikation styrer nøglebeskyttelsen."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Registrere ændringer i trust-tilstand."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Tillader, at en applikation registrerer ændringer i trust-tilstand."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Knytte sig til en trust agent-tjeneste"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Tillader, at en applikation knytter sig til en trust agent-tjeneste."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interager med opdaterings- og gendannelsessystemet"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Giver en applikation tilladelse til at interagere med gendannelsessystemet og systemopdateringerne."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Tryk to gange for zoomstyring"</string>
@@ -1374,11 +1344,9 @@
     <string name="input_method_binding_label" msgid="1283557179944992649">"Inputmetode"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Synkroniser"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Hjælpefunktioner"</string>
-    <string name="wallpaper_binding_label" msgid="1240087844304687662">"Baggrund"</string>
-    <string name="chooser_wallpaper" msgid="7873476199295190279">"Skift baggrund"</string>
+    <string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapet"</string>
+    <string name="chooser_wallpaper" msgid="7873476199295190279">"Skift tapet"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Underretningslytter"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN er aktiveret."</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN aktiveres af <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Tryk for at administrere netværket."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 31b9c9d..4da2043 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronisierung"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Zu viele <xliff:g id="CONTENT_TYPE">%s</xliff:g> gelöscht."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Der Tablet-Speicher ist voll. Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Der Speicher Ihrer Uhr ist voll. Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Der Handyspeicher ist voll! Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Das Netzwerk wird möglicherweise überwacht."</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Von einem unbekannten Dritten"</string>
@@ -146,14 +145,13 @@
     <string name="silent_mode" msgid="7167703389802618663">"Lautlos-Modus"</string>
     <string name="turn_on_radio" msgid="3912793092339962371">"Funk einschalten"</string>
     <string name="turn_off_radio" msgid="8198784949987062346">"Funk ausschalten"</string>
-    <string name="screen_lock" msgid="799094655496098153">"Displaysperre"</string>
+    <string name="screen_lock" msgid="799094655496098153">"Display-Sperre"</string>
     <string name="power_off" msgid="4266614107412865048">"Ausschalten"</string>
     <string name="silent_mode_silent" msgid="319298163018473078">"Klingelton aus"</string>
     <string name="silent_mode_vibrate" msgid="7072043388581551395">"Klingeltonmodus \"Vibration\""</string>
     <string name="silent_mode_ring" msgid="8592241816194074353">"Klingelton ein"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Wird heruntergefahren..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Ihr Tablet wird heruntergefahren."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Ihre Uhr wird heruntergefahren."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefon wird heruntergefahren."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Möchten Sie das Gerät herunterfahren?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Im abgesicherten Modus starten"</string>
@@ -162,7 +160,7 @@
     <string name="no_recent_tasks" msgid="8794906658732193473">"Keine kürzlich geöffneten Apps"</string>
     <string name="global_actions" product="tablet" msgid="408477140088053665">"Tablet-Optionen"</string>
     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefonoptionen"</string>
-    <string name="global_action_lock" msgid="2844945191792119712">"Displaysperre"</string>
+    <string name="global_action_lock" msgid="2844945191792119712">"Display-Sperre"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Ausschalten"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Fehlerbericht"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Fehlerbericht abrufen"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flugmodus"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-System"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"Verknüpfungen deinstallieren"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Ermöglicht einer App das Entfernen von Verknüpfungen vom Startbildschirm ohne Eingriff des Nutzers"</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"Ausgehende Anrufe umleiten"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Ermöglicht der App die Erkennung der während eines ausgehenden Anrufs gewählten Nummer und gibt ihr die Möglichkeit, den Anruf an eine andere Nummer umzuleiten oder den Anruf ganz abzubrechen"</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Ermöglicht der App, ausgehende Anrufe zu verarbeiten und die zu wählende Nummer zu ändern. Die Berechtigung erlaubt der App, ausgehende Anrufe zu überwachen, umzuleiten und zu unterbinden."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"SMS empfangen"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Ermöglicht der App, SMS zu empfangen und zu verarbeiten. Das bedeutet, dass die App an Ihr Gerät gesendete Nachrichten überwachen und löschen kann, ohne sie Ihnen anzuzeigen."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"MMS empfangen"</string>
@@ -317,13 +314,13 @@
     <string name="permlab_retrieve_window_content" msgid="8022588608994589938">"Bildschirminhalt abrufen"</string>
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Ermöglicht der App, den Inhalt des aktiven Fensters abzurufen. Schädliche Apps können so den gesamten Fensterinhalt abrufen und mit Ausnahme von Passwörtern den gesamten Text auswerten."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"Bedienungshilfen vorübergehend aktivieren"</string>
-    <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Ermöglicht der App, die Bedienungshilfen auf dem Gerät vorübergehend zu aktivieren. Schädliche Apps können Bedienungshilfen ohne die Zustimmung des Nutzers aktivieren."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"Fenstertoken abrufen"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Berechtigt eine App zum Abruf des Fenstertokens. Bösartige Apps können sich als System ausgeben und unautorisiert mit dem App-Fenster interagieren."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"Framestatistiken abrufen"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Berechtigt eine App zur Erfassung von Framestatistiken. Bösartige Apps können möglicherweise die Framestatistiken für Fenster von anderen Apps beobachten."</string>
+    <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Ermöglicht einer App, die Bedienungshilfen auf dem Gerät vorübergehend zu aktivieren. Schädliche Apps können Bedienungshilfen ohne die Zustimmung des Nutzers aktivieren."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"Fensterinformationen abrufen"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Ermöglicht einer App, Informationen über die Fenster vom Fenster-Manager abzurufen. Schädliche Apps können Informationen abrufen, die für die systeminterne Nutzung gedacht sind."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"Ereignisse filtern"</string>
-    <string name="permdesc_filter_events" msgid="8006236315888347680">"Ermöglicht der App, einen Eingabefilter zu registrieren, der den Stream aller Nutzerereignisse vor ihrem Versand filtert. Eine schädliche App kann die System-UI ohne Eingriff des Nutzers kontrollieren."</string>
+    <string name="permdesc_filter_events" msgid="8006236315888347680">"Ermöglicht einer App, einen Eingabefilter zu registrieren, der den Stream aller Nutzerereignisse vor ihrem Versand filtert. Eine schädliche App kann die System-UI ohne Eingriff des Nutzers kontrollieren."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"Anzeige vergrößern"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Erlaubt der App, den Inhalt einer Anzeige zu vergrößern. Schädliche Apps verändern eventuell die Ansicht, sodass Inhalte nicht richtig angezeigt werden."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"Partielles Herunterfahren"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Versetzt den Aktivitätsmanager in einen heruntergefahrenen Zustand. Führt kein vollständiges Herunterfahren aus."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"App-Wechsel verhindern"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Ermöglicht der App, eine Benachrichtigung zu senden, dass eine SMS empfangen wurde. Schädliche Apps können so eingehende SMS fälschen."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"Von WAP-PUSH empfangenen Broadcast senden"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Ermöglicht der App, eine Benachrichtigung zu senden, dass eine WAP PUSH-Nachricht empfangen wurde. Schädliche Apps können so den Empfang von MMS vortäuschen oder unbemerkt den Inhalt einer beliebigen Webseite durch schädliche Inhalte ersetzen."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"Netzwerkbewertungen senden"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Ermöglicht der App, Benachrichtigungen zu senden, dass Netzwerke bewertet werden müssen. Für normale Apps ist dies nie erforderlich."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"Anzahl der laufenden Prozesse beschränken"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Ermöglicht der App, die maximale Anzahl an aktiven Prozessen zu steuern. Wird nie für normale Apps benötigt."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"Apps im Hintergrund schließen"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Ermöglicht dem Halter, sich an die Oberfläche eines VPN-Dienstes auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"An einen Hintergrund binden"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Ermöglicht dem Halter, sich an die Oberfläche eines Hintergrunds auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"An Remote-Display binden"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ermöglicht dem Halter, sich an die Oberfläche eines Remote-Displays auf oberster Ebene zu binden. Sollte für normale Apps nie benötigt werden."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"An einen Widget-Dienst binden"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Ermöglicht dem Inhaber, sich an die Oberfläche einer TV-Eingabe auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"Geräteadministrator hinzufügen oder entfernen"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Ermöglicht dem Inhaber, aktive Geräteadministratoren hinzuzufügen oder zu entfernen. Sollte für normale Apps nie benötigt werden."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"Bildschirmausrichtung ändern"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ermöglicht der App, alle installierten Mediendecodierer zur Wiedergabe zu verwenden."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Vertrauenswürdige Anmeldedaten verwalten"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ermöglicht der App, CA-Zertifikate als vertrauenswürdige Anmeldedaten zu installieren und zu deinstallieren."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"App bei Inaktivität ausführen"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Diese Berechtigung ermöglicht es dem Android-System, die App im Hintergrund auszuführen, wenn das Gerät nicht verwendet wird."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"An inaktive Dienste binden"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Mit dieser Berechtigung kann sich das Android-System an die inaktiven Dienste einer App binden."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"Lese-/Schreibberechtigung für zu Diagnosegruppe gehörige Elemente"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Ermöglicht der App, alle Elemente in der Diagnosegruppe zu lesen und zu bearbeiten, etwa Dateien in \"/dev\". Dies könnte eine potenzielle Gefährdung für die Stabilität und Sicherheit des Systems darstellen und sollte NUR für hardwarespezifische Diagnosen des Herstellers oder Mobilfunkanbieters verwendet werden."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"App-Komponenten aktivieren oder deaktivieren"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Ermöglicht der App, auf Ihrem Gerät gespeicherte personenbezogene Profildaten zu lesen, einschließlich Ihres Namens und Ihrer Kontaktdaten. Die App kann Sie somit identifizieren und Ihre Profildaten an andere senden."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"Ihre Kontaktkarten ändern"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Ermöglicht der App, auf Ihrem Gerät gespeicherte personenbezogene Profildaten zu ändern, einschließlich Ihres Namens und Ihrer Kontaktdaten, sowie Daten hinzuzufügen. Die App kann Sie so identifizieren und Ihre Profildaten an andere senden."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"Körpersensoren (wie Herzfrequenzmesser)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Ermöglicht der App den Zugriff auf Daten von Sensoren, mit denen Ihre Vitalfunktionen, etwa die Herzfrequenz, gemessen werden."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"In sozialem Stream lesen"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Ermöglicht der App, auf Updates aus sozialen Netzwerken von Ihnen und Ihren Freunden zuzugreifen und diese zu synchronisieren. Seien Sie vorsichtig, wenn Sie Informationen teilen: Der App wird erlaubt, die Kommunikation zwischen Ihnen und Ihren Freunden in sozialen Netzwerken zu lesen, unabhängig von der Vertraulichkeit der kommunizierten Informationen. Hinweis: Diese Berechtigung kann möglicherweise nicht in allen sozialen Netzwerken erzwungen werden."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"In sozialem Stream schreiben"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Ermöglicht der App, die Telefonfunktionen des Geräts zu steuern. Eine App mit dieser Berechtigung kann das Netzwerk wechseln oder das Radio des Telefons ein- und ausschalten, ohne Sie darüber zu informieren."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"Telefonstatus und Identität abrufen"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Ermöglicht der App, auf die Telefonfunktionen des Geräts zuzugreifen. Die Berechtigung erlaubt der App, die Telefonnummer und Geräte-IDs zu erfassen, festzustellen, ob gerade ein Gespräch geführt wird, und die Rufnummer verbundener Anrufer zu lesen."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"Genaue Telefonstatusangaben abrufen"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Ermöglicht der App, auf die genauen Telefonstatusangaben zuzugreifen. Diese Erlaubnis ermöglicht der App, den tatsächlichen Rufstatus zu ermitteln, das bedeutet, ob ein Anruf aktiv ist oder im Hintergrund abläuft, ob bei einem Anruf ein Fehler aufgetreten ist, wie der genaue Datenverbindungsstatus lautet oder ob bei der Datenverbindung ein Fehler aufgetreten ist."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"Ruhezustand des Tablets deaktivieren"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Ruhezustand deaktivieren"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Ermöglicht der App, den Ruhezustand des Tablets zu deaktivieren"</string>
@@ -647,15 +630,12 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX-Status ändern"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Ermöglicht der App, eine Verbindung zwischen dem Tablet und WiMAX-Netzwerken herzustellen und solche zu trennen."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Ermöglicht der App, eine Verbindung zwischen dem Telefon und WiMAX-Netzwerken herzustellen und solche zu trennen."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"Netzwerke bewerten"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Ermöglicht der App, Netzwerke zu bewerten und die Auswahl des jeweiligen Netzwerks für das Tablet zu beeinflussen"</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Ermöglicht der App, Netzwerke zu bewerten und die Auswahl des jeweiligen Netzwerks für das Telefon zu beeinflussen"</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"Pairing mit Bluetooth-Geräten durchführen"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Ermöglicht der App, die Bluetooth-Konfiguration eines Tablets einzusehen und Verbindungen zu gekoppelten Geräten herzustellen und zu akzeptieren."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Ermöglicht der App, die Bluetooth-Konfiguration des Telefons einzusehen und Verbindungen mit gekoppelten Geräten herzustellen und zu akzeptieren."</string>
     <string name="permlab_nfc" msgid="4423351274757876953">"Nahfeldkommunikation steuern"</string>
     <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="permlab_disableKeyguard" msgid="3598496301486439258">"Display-Sperre 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_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>
@@ -703,18 +683,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"Vom Mobilfunkanbieter bereitgestellte Konfigurations-App aufrufen"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ermöglicht dem Inhaber, die vom Mobilfunkanbieter bereitgestellte Konfigurations-App aufzurufen. Sollte für normale Apps nie benötigt werden."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Informationen zu den Netzwerkbedingungen erfassen"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Ermöglicht der App, Informationen zu den Netzwerkbedingungen zu erfassen. Sollte für normale Apps nie benötigt werden."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"Kalibrierung für Eingabegerät ändern"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Ermöglicht der App, die Kalibrierungsparameter des Touchscreens zu ändern. Für normale Apps sollte dies nie erforderlich sein."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"Auf DRM-Zertifikate zugreifen"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Ermöglicht einer App die Bereitstellung und Nutzung von DRM-Zertifikaten. Sollte für normale Apps nie benötigt werden."</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="policylab_watchLogin" msgid="914130646942199503">"Versuche zum Entsperren des Displays überwachen"</string>
@@ -1342,15 +1314,11 @@
     <string name="permlab_copyProtectedData" msgid="4341036311211406692">"Inhalte kopieren"</string>
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Ermöglicht der App das Aufrufen des Standard-Containerdienstes zum Kopieren von Inhalten. Nicht für normale Apps vorgesehen."</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"Medienausgabe umleiten"</string>
-    <string name="permdesc_route_media_output" msgid="4932818749547244346">"Ermöglicht der App, die Medienausgabe auf andere externe Geräte umzuleiten."</string>
+    <string name="permdesc_route_media_output" msgid="4932818749547244346">"Ermöglicht einer App, die Medienausgabe auf andere externe Geräte umzuleiten."</string>
     <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Zugriff auf mit Keyguard geschützten Speicher"</string>
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Ermöglicht einer App den Zugriff auf mit Keyguard geschützten Speicher"</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Anzeige und Ausblenden des Keyguard steuern"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Apps können den Keyguard steuern."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Überwachung von Änderungen des Trust-Status"</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Ermöglicht einer App die Überwachungen von Änderungen des Trust-Status"</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"An Trust Agent-Service anbinden"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ermöglicht einer App die Anbindung an einen Trust Agent-Service"</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Mit Update- und Wiederherstellungssystem interagieren"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Ermöglicht einer App die Interaktion mit dem Wiederherstellungssystem und den Systemupdates"</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Für Zoomeinstellung zweimal berühren"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Hintergrund"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Hintergrund ändern"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Benachrichtigungs-Listener"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN aktiviert"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN wurde von <xliff:g id="APP">%s</xliff:g> aktiviert."</string>
     <string name="vpn_text" msgid="3011306607126450322">"Zum Verwalten des Netzwerks berühren"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index a1d6049..64d330d 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Συγχρονισμός"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Πάρα πολλές <xliff:g id="CONTENT_TYPE">%s</xliff:g> διαγραφές."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Ο αποθηκευτικός χώρος του tablet είναι πλήρης. Διαγράψτε μερικά αρχεία για να δημιουργήσετε ελεύθερο χώρο."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Ο αποθηκευτικός χώρος παρακολούθησης είναι πλήρης! Διαγράψτε μερικά αρχεία για να απελευθερώσετε χώρο."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Ο αποθηκευτικός χώρος του τηλεφώνου είναι πλήρης. Διαγράψτε μερικά αρχεία για να δημιουργήσετε ελεύθερο χώρο."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Το δίκτυο ενδέχεται να παρακολουθείται"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Από ένα άγνωστο τρίτο μέρος"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Ειδοποίηση ήχου ενεργή"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Απενεργοποίηση..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Το tablet σας θα απενεργοποιηθεί."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Η παρακολούθησή σας θα τερματιστεί."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Το τηλέφωνό σας θα απενεργοποιηθεί."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Θέλετε να γίνει τερματισμός λειτουργίας;"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Επανεκκίνηση στην ασφαλή λειτουργία"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Λειτουργία πτήσης"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Ασφαλής λειτουργία"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Σύστημα Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"κατάργηση εγκατάστασης συντομεύσεων"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Επιτρέπει στην εφαρμογή την κατάργηση συντομεύσεων από την Αρχική οθόνη χωρίς την παρέμβαση του χρήστη."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"αναδρομολόγηση εξερχόμενων κλήσεων"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Επιτρέπει στην εφαρμογή να βλέπει τον αριθμό που καλέσατε κατά τη διάρκεια μιας εξερχόμενης κλήσης με επιλογή ανακατεύθυνσης της κλήσης σε έναν διαφορετικό αριθμό ή διακοπής της κλήσης."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Επιτρέπει στην εφαρμογή την επεξεργασία εξερχόμενων κλήσεων και την αλλαγή του αριθμού που πρόκειται να κληθεί. Αυτό δίνει τη δυνατότητα στην εφαρμογή να παρακολουθεί, να ανακατευθύνει ή να παρεμποδίζει εξερχόμενες κλήσεις:"</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"λήψη μηνυμάτων κειμένου (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Επιτρέπει στην εφαρμογή τη λήψη και την επεξεργασία μηνυμάτων SMS. Αυτό σημαίνει ότι η εφαρμογή θα μπορούσε να παρακολουθήσει ή να διαγράψει τα μηνύματα που αποστέλλονται στη συσκευή σας χωρίς αυτά να εμφανιστούν σε εσάς."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"λήψη μηνυμάτων κειμένου (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Επιτρέπει στην εφαρμογή την ανάκτηση του περιεχομένου του ενεργού παραθύρου. Τυχόν κακόβουλες εφαρμογές ενδέχεται να ανακτήσουν ολόκληρο το περιεχόμενο του παραθύρου και να εξετάσουν ολόκληρο το κείμενό του εκτός από τους κωδικούς πρόσβασης."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"προσωρινή ενεργοποίηση προσβασιμότητας"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Επιτρέπει σε μια εφαρμογή να ενεργοποιήσει την προσβασιμότητα στη συσκευή. Οι κακόβουλες εφαρμογές ενδέχεται να ενεργοποιήσουν την προσβασιμότητα χωρίς τη συγκατάθεση των χρηστών."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"ανάκτηση διακριτικού παραθύρου"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Επιτρέπει σε μια εφαρμογή να ανακτήσει το διακριτικό παραθύρου. Οι κακόβουλες εφαρμογές μπορούν να εκτελούν μη εξουσιοδοτημένη αλληλεπίδραση με το παράθυρο της εφαρμογής, σε απομίμηση του συστήματος."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"ανάκτηση στατιστικών πλαισίου"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Επιτρέπει σε μια εφαρμογή να συλλέγει στατιστικά στοιχεία πλαισίου. Οι κακόβουλες εφαρμογές μπορούν να παρατηρούν τα στατιστικά στοιχεία πλαισίου των παραθύρων από άλλες εφαρμογές."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"ανάκτηση πληροφοριών παραθύρων"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Επιτρέπει σε μια εφαρμογή να ανακτήσει πληροφορίες σχετικά με τα παράθυρα από το διαχειριστή παραθύρων. Οι κακόβουλες εφαρμογές ενδέχεται να ανακτήσουν πληροφορίες που προορίζονται για την εσωτερική χρήση του συστήματος."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"φιλτράρισμα συμβάντων"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Επιτρέπει σε μια εφαρμογή να καταγράφει ένα φίλτρο εισαγωγής, το οποίο φιλτράρει τη ροή όλων των συμβάντων χρήστη πριν την αποστολή τους. Μια κακόβουλη εφαρμογή μπορεί να ελέγξει τη διεπαφή του συστήματος χωρίς την παρέμβαση του χρήστη."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"μεγέθυνση οθόνης"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Επιτρέπει στην εφαρμογή να μεγεθύνει το περιεχόμενο της οθόνης. Οι κακόβουλες εφαρμογές ενδέχεται να τροποποιούν το περιεχόμενο της οθόνης με τέτοιο τρόπο ώστε η εφαρμογή να μην μπορεί να χρησιμοποιηθεί."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"μερικός τερματισμός λειτουργίας"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Θέτει το πρόγραμμα διαχείρισης δραστηριοτήτων σε κατάσταση τερματισμού λειτουργιών. Δεν εκτελεί πλήρη τερματισμό λειτουργιών."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"αποτροπή εναλλαγών εφαρμογών"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Επιτρέπει στην εφαρμογή την εκπομπή ειδοποίησης σχετικά με τη λήψη μηνύματος SMS. Τυχόν κακόβουλες εφαρμογές ενδέχεται να χρησιμοποιήσουν αυτήν τη δυνατότητα για τη δημιουργία πλαστών εισερχόμενων μηνυμάτων SMS."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"αποστολή εκπομπής που έχει ληφθεί με WAP-PUSH"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Επιτρέπει στην εφαρμογή τη μετάδοση μιας ειδοποίησης ότι έχει ληφθεί κάποιο μήνυμα WAP PUSH. Τυχόν κακόβουλες εφαρμογές ενδέχεται να χρησιμοποιήσουν αυτήν τη δυνατότητα για τη λήψη πλαστών μηνυμάτων MMS ή την εν αγνοία του χρήστη αντικατάσταση του περιεχομένου οποιασδήποτε ιστοσελίδας με κακόβουλες παραλλαγές."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"αποστολή μετάδοσης κατάταξης δικτύων"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Επιτρέπει στην εφαρμογή να μεταδίδει μια ειδοποίηση ότι απαιτείται κατάταξη των δικτύων. Δεν απαιτείται ποτέ για τις συνήθεις εφαρμογές."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"περιορισμός αριθμού εκτελούμενων διαδικασιών"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Επιτρέπει στην εφαρμογή τον έλεγχο του μέγιστου αριθμού διαδικασιών που θα εκτελούνται. Δεν είναι απαραίτητο για συνήθεις εφαρμογές."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"αναγκαστικός τερματισμός εφαρμογών στο παρασκήνιο"</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας Vpn. Δεν απαιτείται για κανονικές εφαρμογές."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"δέσμευση σε ταπετσαρία"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας ταπετσαρίας. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"μεταφορά σε μια απομακρυσμένη οθόνη"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Επιτρέπει στην εφαρμογή τη χρήση οποιουδήποτε εγκατεστημένου αποκωδικοποιητή μέσων για αναπαραγωγή."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"διαχείριση αξιόπιστων διαπιστευτηρίων"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Επιτρέπει στην εφαρμογή την εγκατάσταση και την απεγκατάσταση πιστοποιητικών CA ως αξιόπιστων διαπιστευτηρίων."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"εκτέλεση εφαρμογής κατά τη λειτουργία αδράνειας"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Αυτή η άδεια επιτρέπει στο σύστημα Android να εκτελεί την εφαρμογή στο παρασκήνιο όταν δεν χρησιμοποιείται η συσκευή."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"σύνδεση σε υπηρεσίες αδράνειας"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Αυτή η άδεια επιτρέπει στο σύστημα Android να συνδέεται στις υπηρεσίες αδράνειας μιας εφαρμογής."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"ανάγνωση/εγγραφή σε πόρους που ανήκουν στο διαγνωστικό"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Επιτρέπει στην εφαρμογή την ανάγνωση και την εγγραφή σε οποιονδήποτε πόρο που ανήκει στην ομάδα διαγνωστικού (π.χ. αρχεία στον κατάλογο /dev). Αυτό ενδέχεται να επηρεάσει την σταθερότητα και την ασφάλεια του συστήματος. Θα πρέπει να χρησιμοποιείται ΜΟΝΟ για διαγνωστικά υλικού από τον κατασκευαστή ή τον χειριστή."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"ενεργοποίηση ή απενεργοποίηση στοιχείων εφαρμογής"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Επιτρέπει στην εφαρμογή την ανάγνωση προσωπικών πληροφοριών προφίλ οι οποίες είναι αποθηκευμένες στη συσκευή σας, όπως το όνομα και τα στοιχεία επικοινωνίας σας. Αυτό σημαίνει ότι η εφαρμογή μπορεί να σας αναγνωρίσει και να στείλει τις πληροφορίες του προφίλ σας σε άλλους."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"τροποποίηση κάρτας επαφής"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Επιτρέπει στην εφαρμογή την αλλαγή ή την προσθήκη προσωπικών πληροφοριών προφίλ οι οποίες είναι αποθηκευμένες στη συσκευή σας, όπως το όνομα και τα στοιχεία επικοινωνίας σας. Αυτό σημαίνει ότι η εφαρμογή μπορεί να σας αναγνωρίσει και να στείλει τις πληροφορίες του προφίλ σας σε άλλα άτομα."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"αισθητήρες λειτουργιών (π.χ. καρδιακό ρυθμό)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Επιτρέπει στην εφαρμογή την πρόσβαση στα δεδομένα από τους αισθητήρες που χρησιμοποιείτε για να παρακολουθείτε τις εσωτερικές λειτουργίες σας, όπως τον καρδιακό ρυθμό."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"διαβάστε τη ροή σας κοινωνικών δικτύων"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Επιτρέπει στην εφαρμογή την πρόσβαση και το συγχρονισμό κοινωνικών ενημερώσεων από εσάς και τους φίλους σας. Θα πρέπει να είστε προσεκτικοί όταν μοιράζεστε πληροφορίες -- αυτό δίνει τη δυνατότητα στην εφαρμογή να διαβάζει τις επικοινωνίες ανάμεσα σε εσάς και τους φίλους σας σε κοινωνικά δίκτυα, ανεξάρτητα από το επίπεδο εμπιστευτικότητας. Σημείωση: αυτή η άδεια ίσως να μην μπορεί να εφαρμοστεί σε όλα τα κοινωνικά δίκτυα."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"γράψτε στη ροή σας κοινωνικών δικτύων"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Επιτρέπει στην εφαρμογή να ελέγχει τις λειτουργίες τηλεφώνου της συσκευής. Μια εφαρμογή η οποία διαθέτει αυτήν την άδεια μπορεί να κάνει εναλλαγή μεταξύ δικτύων, να ενεργοποιεί και να απενεργοποιεί το ραδιόφωνο του τηλεφώνου και άλλα, χωρίς να ειδοποιείστε."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"ανάγνωση κατάστασης και ταυτότητας τηλεφώνου"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Επιτρέπει στην εφαρμογή την πρόσβαση στις λειτουργίες τηλεφώνου της συσκευής. Αυτή η άδεια δίνει τη δυνατότητα στην εφαρμογή να καθορίζει τον αριθμό τηλεφώνου και τα αναγνωριστικά συσκευών, εάν μια κλήση είναι ενεργή, καθώς και τον απομακρυσμένο αριθμό που συνδέεται από μια κλήση."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"ανάγνωση ακριβούς κατάστασης τηλεφώνου"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Επιτρέπει στην εφαρμογή να αποκτήσει πρόσβαση στην ακριβή κατάσταση του τηλεφώνου. Αυτή η άδεια επιτρέπει στην εφαρμογή να καθορίσει την πραγματική κατάσταση της κλήσης, εάν η κλήση είναι ενεργή ή πραγματοποιείται στο παρασκήνιο, αποτυχίες κλήσεων, ακριβή δεδομένα κατάστασης σύνδεσης και αποτυχίες σύνδεσης δεδομένων."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"παρεμπόδιση μετάβασης του tablet σε κατάσταση αδράνειας"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"παρεμπόδιση μετάβασης του τηλεφώνου σε κατάσταση αδράνειας"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Επιτρέπει στην εφαρμογή την παρεμπόδιση της μετάβασης του tablet σε κατάσταση αδράνειας."</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Αλλαγή κατάστασης WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Επιτρέπει στην εφαρμογή τη σύνδεση στο tablet και την αποσύνδεση από αυτό, από δίκτυα WiMAX."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Επιτρέπει στην εφαρμογή τη σύνδεση στο τηλέφωνο και την αποσύνδεση από αυτό, από δίκτυα WiMAX."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"κατάταξη δικτύων"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Επιτρέπει στην εφαρμογή να κατατάσσει τα δίκτυα και να επιλέγει τα προτιμώμενα δίκτυα του tablet."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Επιτρέπει στην εφαρμογή να κατατάσσει τα δίκτυα και να επιλέγει τα προτιμώμενα δίκτυα του τηλεφώνου."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"σύζευξη με συσκευές Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Επιτρέπει στην εφαρμογή να προβάλλει τη διαμόρφωση του Bluetooth στο tablet, καθώς και να πραγματοποιεί και να αποδέχεται συνδέσεις με συζευγμένες συσκευές."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Επιτρέπει στην εφαρμογή να προβάλλει τη διαμόρφωση του Bluetooth στο τηλέφωνο, καθώς και να πραγματοποιεί και να αποδέχεται συνδέσεις με συζευγμένες συσκευές."</string>
@@ -703,18 +685,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Επιτρέπει στην εφαρμογή να ανακτά, να εξετάζει και να απαλείφει ειδοποιήσεις, συμπεριλαμβανομένων εκείνων που δημοσιεύονται από άλλες εφαρμογές."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"δέσμευση σε υπηρεσία ακρόασης ειδοποίησης"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας ακρόασης ειδοποιήσεων. Δεν απαιτείται σε κανονικές εφαρμογές."</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"κλήση της εφαρμογής διαμόρφωσης που παρέχεται από την εταιρεία κινητής τηλεφωνίας"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Επιτρέπει στον κάτοχο την κλήση της εφαρμογής διαμόρφωσης που παρέχεται από την εταιρεία κινητής τηλεφωνίας. Δεν απαιτείται για κανονικές εφαρμογές."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"λήψη παρατηρήσεων σχετικά με την κατάσταση δικτύου"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Επιτρέπει σε μια εφαρμογή να λαμβάνει παρατηρήσεις σχετικά με την κατάσταση δικτύου. Δεν θα πρέπει να απαιτείται ποτέ για κανονικές εφαρμογές."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"αλλαγή βαθμονόμησης της συσκευής εισόδου"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Επιτρέπει στην εφαρμογή να τροποποιεί τις παραμέτρους βαθμονόμησης της οθόνης αφής. Δεν απαιτείται για τις κανονικές εφαρμογές."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"πρόσβαση σε πιστοποιητικά DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Επιτρέπει σε μια εφαρμογή να παρέχει και να χρησιμοποιεί πιστοποιητικά DRM. Δεν θα χρειαστεί ποτέ για κανονικές εφαρμογές."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Ορισμός κανόνων κωδικού πρόσβασης"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Έλεγχος του μεγέθους και των χαρακτήρων που επιτρέπονται στους κωδικούς πρόσβασης ξεκλειδώματος οθόνης."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Παρακολούθηση προσπαθειών ξεκλειδώματος οθόνης"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Επιτρέπει σε μια εφαρμογή να αποκτήσει πρόσβαση στον ασφαλή αποθηκευτικό χώρο με κλείδωμα."</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>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Σύνδεση σε υπηρεσία trust agent"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Επιτρέπει σε μια εφαρμογή να συνδεθεί σε μια υπηρεσία trust agents."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Αλληλεπίδραση με το σύστημα ενημέρωσης και ανάκτησης"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Επιτρέπει σε μια εφαρμογή να αλληλεπιδρά με το σύστημα ανάκτησης και ενημερώσεων συστήματος."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Αγγίξτε δύο φορές για έλεγχο εστίασης"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Ταπετσαρία"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Αλλαγή ταπετσαρίας"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Υπηρεσία ακρόασης ειδοποίησης"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"Το VPN ενεργοποιήθηκε"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Το VPN ενεργοποιήθηκε από την εφαρμογή <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Αγγίξτε για τη διαχείριση του δικτύου."</string>
@@ -1388,7 +1356,7 @@
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Σφάλμα πάντα ενεργοποιημένου VPN"</string>
     <string name="vpn_lockdown_config" msgid="6415899150671537970">"Αγγίξτε για διαμόρφωση"</string>
     <string name="upload_file" msgid="2897957172366730416">"Επιλογή αρχείου"</string>
-    <string name="no_file_chosen" msgid="6363648562170759465">"Δεν επιλέχθηκε κανένα αρχείο."</string>
+    <string name="no_file_chosen" msgid="6363648562170759465">"Δεν έχει επιλεγεί αρχείο"</string>
     <string name="reset" msgid="2448168080964209908">"Επαναφορά"</string>
     <string name="submit" msgid="1602335572089911941">"Υποβολή"</string>
     <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Η λειτουργία αυτοκινήτου είναι ενεργοποιημένη"</string>
@@ -1465,8 +1433,8 @@
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Επιλέξτε κάποια εφαρμογή"</string>
     <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Δεν ήταν δυνατή η εκκίνηση του <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
-    <string name="shareactionprovider_share_with" msgid="806688056141131819">"Κοινοποίηση με"</string>
-    <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Κοινοποίηση με <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+    <string name="shareactionprovider_share_with" msgid="806688056141131819">"Κοινή χρήση με"</string>
+    <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Κοινή χρήση με <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Στοιχείο χειρισμού με δυνατότητα ολίσθησης. Αγγίξτε και πατήστε παρατεταμένα."</string>
     <string name="description_target_unlock_tablet" msgid="3833195335629795055">"Σύρετε για ξεκλείδωμα."</string>
     <string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Συνδέστε ακουστικά για να ακούσετε τα πλήκτρα του κωδικού πρόσβασης να εκφωνούνται."</string>
@@ -1510,7 +1478,7 @@
     <string name="sha1_fingerprint" msgid="7930330235269404581">"Αποτύπωμα SHA-1"</string>
     <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"Εμφάνιση όλων"</string>
     <string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"Επιλογή δραστηριότητας"</string>
-    <string name="share_action_provider_share_with" msgid="5247684435979149216">"Κοινοποίηση με"</string>
+    <string name="share_action_provider_share_with" msgid="5247684435979149216">"Κοινή χρήση με"</string>
     <string name="list_delimeter" msgid="3975117572185494152">", "</string>
     <string name="sending" msgid="3245653681008218030">"Γίνεται αποστολή…"</string>
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Εκκίνηση προγράμματος περιήγησης;"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 33f0010..549c6d5 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sync"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Too many <xliff:g id="CONTENT_TYPE">%s</xliff:g> deletions."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Tablet storage is full. Delete some files to free space."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Watch storage is full. Delete some files to free up space."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Phone storage is full. Delete some files to free space."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Network may be monitored"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"By an unknown third party"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Ringer on"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Shutting down…"</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Your tablet will shut down."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Your watch will shut down."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Your phone will shut down."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Do you want to shut down?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Reboot to safe mode"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Aeroplane mode"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"uninstall shortcuts"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Allows the application to remove Home screen shortcuts without user intervention."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"reroute outgoing calls"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Allows the app to see the number being dialled during an outgoing call with the option to redirect the call to a different number or abort the call altogether."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Allows the app to process outgoing calls and change the number to be dialled. This permission allows the app to monitor, redirect or prevent outgoing calls."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"receive text messages (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Allows the app to receive and process SMS messages. This means that the app could monitor or delete messages sent to your device without showing them to you."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"receive text messages (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Allows the app to retrieve the content of the active window. Malicious apps may retrieve the entire window content and examine all its text except passwords."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"temporary enable accessibility"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Allows an application to temporarily enable accessibility on the device. Malicious apps may enable accessibility without user consent."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"retrieve window token"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Allows an application to retrieve the window token. Malicious apps may perform unauthorised interaction with the application window impersonating the system."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"retrieve frame statistics"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Allows an application to collect frame statistics. Malicious apps may observe the frame statistics of windows from other apps."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"retrieve window info"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Allows an application to retrieve information about the windows from the window manager. Malicious apps may retrieve information that is intended for internal system usage."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filter events"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Allows an application to register an input filter which filters the stream of all user events before they are dispatched. Malicious app may control the system UI without user intervention."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"magnify display"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Allows an application to magnify the content of a display. Malicious apps may transform the display content in a way that renders the device unusable."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"partial shutdown"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Puts the activity manager into a shut-down state. Does not perform a complete shut down."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"prevent app switches"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Allows the app to broadcast a notification that an SMS message has been received. Malicious apps may use this to forge incoming SMS messages."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"send WAP-PUSH-received broadcast"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Allows the app to broadcast a notification that a WAP PUSH message has been received. Malicious apps may use this to forge MMS message receipt or to silently replace the content of any web page with malicious variants."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"send score networks broadcast"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Allows the app to broadcast a notification that networks need to be scored. Never needed for normal apps."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"limit number of running processes"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Allows the app to control the maximum number of processes that will run. Never needed for normal apps."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"force background apps to close"</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Allows the holder to bind to the top-level interface of a Vpn service. Should never be needed for normal apps."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"bind to wallpaper"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Allows the holder to bind to the top-level interface of wallpaper. Should never be needed for normal applications."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind to a remote display"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Allows the holder to bind to the top-level interface of a remote display. Should never be needed for normal apps."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind to a widget service"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Allows the app to use any installed media decoder to decode for playback."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"manage trusted credentials"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Allows the app to install and uninstall CA certificates as trusted credentials."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"run application during idle time"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"This permission allows the Android system to run the application in the background while the device is not in use."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"bind to idle services"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"This permission allows the Android system to bind to an application\'s idle services."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"read/write to resources owned by diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Allows the app to read and write to any resource owned by the diag group; for example, files in /dev. This could potentially affect system stability and security. This should ONLY be used for hardware-specific diagnostics by the manufacturer or operator."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"enable or disable app components"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Allows the app to read personal profile information stored on your device, such as your name and contact information. This means that the app can identify you and may send your profile information to others."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"modify your own contact card"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Allows the app to change or add to personal profile information stored on your device, such as your name and contact information. This means that the app can identify you and may send your profile information to others."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"body sensors (like heart rate monitors)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Allows the app to access data from sensors that you use to measure what’s happening inside your body, such as heart rate."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"read your social stream"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Allows the app to access and sync social updates from you and your friends. Be careful when sharing information - this allows the app to read communications between you and your friends on social networks, regardless of confidentiality. Note: this permission may not be enforced on all social networks."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"write to your social stream"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Allows the app to control the phone features of the device. An app with this permission can switch networks, turn the phone radio on and off and the like without ever notifying you."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"read phone status and identity"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Allows the app to access the phone features of the device. This permission allows the app to determine the phone number and device IDs, whether a call is active and the remote number connected by a call."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"read precise phone states"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Allows the app to access the precise phone states. This permission allows the app to determine the real call status, whether a call is active or in the background, call fails, precise data connection status and data connection fails."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"prevent tablet from sleeping"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"prevent phone from sleeping"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Allows the app to prevent the tablet from going to sleep."</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"change WiMAX state"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Allows the app to connect the tablet to and disconnect the tablet from WiMAX networks."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Allows the app to connect the phone to and disconnect the phone from WiMAX networks."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"score networks"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Allows the app to rank networks and influence which networks the tablet should prefer."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Allows the app to rank networks and influence which networks the phone should prefer."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"pair with Bluetooth devices"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Allows the app to view the configuration of Bluetooth on the tablet and to make and accept connections with paired devices."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Allows the app to view the configuration of the Bluetooth on the phone and to make and accept connections with paired devices."</string>
@@ -703,18 +685,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invoke the carrier-provided configuration app"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"listen for observations on network conditions"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Allows an application to listen for observations on network conditions. Should never be needed for normal apps."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"change input device calibration"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Allows the app to modify the calibration parameters of the touch screen. Should never be needed for normal apps."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"access DRM certificates"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Allows an application to provision and use DRM certficates. 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="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Allows an application to access keyguard secure storage."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Control displaying and hiding keyguard"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Allows an application to control keyguard."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Listen to trust state changes."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Allows an application to listen for changes in trust state."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Bind to a trust agent service"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Allows an application to bind to a trust agent service."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interact with update and recovery system"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Allows an application to interact with the recovery system and system updates."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Touch twice for zoom control"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Change wallpaper"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Notification listener"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN activated"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN is activated by <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Touch to manage the network."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 33f0010..549c6d5 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sync"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Too many <xliff:g id="CONTENT_TYPE">%s</xliff:g> deletions."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Tablet storage is full. Delete some files to free space."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Watch storage is full. Delete some files to free up space."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Phone storage is full. Delete some files to free space."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Network may be monitored"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"By an unknown third party"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Ringer on"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Shutting down…"</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Your tablet will shut down."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Your watch will shut down."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Your phone will shut down."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Do you want to shut down?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Reboot to safe mode"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Aeroplane mode"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"uninstall shortcuts"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Allows the application to remove Home screen shortcuts without user intervention."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"reroute outgoing calls"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Allows the app to see the number being dialled during an outgoing call with the option to redirect the call to a different number or abort the call altogether."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Allows the app to process outgoing calls and change the number to be dialled. This permission allows the app to monitor, redirect or prevent outgoing calls."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"receive text messages (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Allows the app to receive and process SMS messages. This means that the app could monitor or delete messages sent to your device without showing them to you."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"receive text messages (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Allows the app to retrieve the content of the active window. Malicious apps may retrieve the entire window content and examine all its text except passwords."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"temporary enable accessibility"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Allows an application to temporarily enable accessibility on the device. Malicious apps may enable accessibility without user consent."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"retrieve window token"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Allows an application to retrieve the window token. Malicious apps may perform unauthorised interaction with the application window impersonating the system."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"retrieve frame statistics"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Allows an application to collect frame statistics. Malicious apps may observe the frame statistics of windows from other apps."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"retrieve window info"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Allows an application to retrieve information about the windows from the window manager. Malicious apps may retrieve information that is intended for internal system usage."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filter events"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Allows an application to register an input filter which filters the stream of all user events before they are dispatched. Malicious app may control the system UI without user intervention."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"magnify display"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Allows an application to magnify the content of a display. Malicious apps may transform the display content in a way that renders the device unusable."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"partial shutdown"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Puts the activity manager into a shut-down state. Does not perform a complete shut down."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"prevent app switches"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Allows the app to broadcast a notification that an SMS message has been received. Malicious apps may use this to forge incoming SMS messages."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"send WAP-PUSH-received broadcast"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Allows the app to broadcast a notification that a WAP PUSH message has been received. Malicious apps may use this to forge MMS message receipt or to silently replace the content of any web page with malicious variants."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"send score networks broadcast"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Allows the app to broadcast a notification that networks need to be scored. Never needed for normal apps."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"limit number of running processes"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Allows the app to control the maximum number of processes that will run. Never needed for normal apps."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"force background apps to close"</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Allows the holder to bind to the top-level interface of a Vpn service. Should never be needed for normal apps."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"bind to wallpaper"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Allows the holder to bind to the top-level interface of wallpaper. Should never be needed for normal applications."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind to a remote display"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Allows the holder to bind to the top-level interface of a remote display. Should never be needed for normal apps."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind to a widget service"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Allows the app to use any installed media decoder to decode for playback."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"manage trusted credentials"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Allows the app to install and uninstall CA certificates as trusted credentials."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"run application during idle time"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"This permission allows the Android system to run the application in the background while the device is not in use."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"bind to idle services"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"This permission allows the Android system to bind to an application\'s idle services."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"read/write to resources owned by diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Allows the app to read and write to any resource owned by the diag group; for example, files in /dev. This could potentially affect system stability and security. This should ONLY be used for hardware-specific diagnostics by the manufacturer or operator."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"enable or disable app components"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Allows the app to read personal profile information stored on your device, such as your name and contact information. This means that the app can identify you and may send your profile information to others."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"modify your own contact card"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Allows the app to change or add to personal profile information stored on your device, such as your name and contact information. This means that the app can identify you and may send your profile information to others."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"body sensors (like heart rate monitors)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Allows the app to access data from sensors that you use to measure what’s happening inside your body, such as heart rate."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"read your social stream"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Allows the app to access and sync social updates from you and your friends. Be careful when sharing information - this allows the app to read communications between you and your friends on social networks, regardless of confidentiality. Note: this permission may not be enforced on all social networks."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"write to your social stream"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Allows the app to control the phone features of the device. An app with this permission can switch networks, turn the phone radio on and off and the like without ever notifying you."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"read phone status and identity"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Allows the app to access the phone features of the device. This permission allows the app to determine the phone number and device IDs, whether a call is active and the remote number connected by a call."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"read precise phone states"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Allows the app to access the precise phone states. This permission allows the app to determine the real call status, whether a call is active or in the background, call fails, precise data connection status and data connection fails."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"prevent tablet from sleeping"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"prevent phone from sleeping"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Allows the app to prevent the tablet from going to sleep."</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"change WiMAX state"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Allows the app to connect the tablet to and disconnect the tablet from WiMAX networks."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Allows the app to connect the phone to and disconnect the phone from WiMAX networks."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"score networks"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Allows the app to rank networks and influence which networks the tablet should prefer."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Allows the app to rank networks and influence which networks the phone should prefer."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"pair with Bluetooth devices"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Allows the app to view the configuration of Bluetooth on the tablet and to make and accept connections with paired devices."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Allows the app to view the configuration of the Bluetooth on the phone and to make and accept connections with paired devices."</string>
@@ -703,18 +685,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invoke the carrier-provided configuration app"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"listen for observations on network conditions"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Allows an application to listen for observations on network conditions. Should never be needed for normal apps."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"change input device calibration"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Allows the app to modify the calibration parameters of the touch screen. Should never be needed for normal apps."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"access DRM certificates"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Allows an application to provision and use DRM certficates. 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="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Allows an application to access keyguard secure storage."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Control displaying and hiding keyguard"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Allows an application to control keyguard."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Listen to trust state changes."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Allows an application to listen for changes in trust state."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Bind to a trust agent service"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Allows an application to bind to a trust agent service."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interact with update and recovery system"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Allows an application to interact with the recovery system and system updates."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Touch twice for zoom control"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Change wallpaper"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Notification listener"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN activated"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN is activated by <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Touch to manage the network."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 620d745..f8e789c 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronización"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Se ha agotado el espacio de almacenamiento de la tablet. Elimina algunos archivos para liberar espacio."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"El almacenamiento del reloj está completo. Elimina algunos archivos para liberar espacio."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Se ha agotado el espacio de almacenamiento del dispositivo. Elimina algunos archivos para liberar espacio."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Es posible que la red esté supervisada"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Por un tercero desconocido"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Timbre activado"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Apagando…"</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tu tablet se apagará."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Se apagará el reloj."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Tu dispositivo se apagará."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"¿Deseas apagarlo?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Reiniciar en modo seguro"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avión"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"desinstalar accesos directos"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Permite que la aplicación elimine accesos directos de la pantalla principal sin que el usuario intervenga."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"redireccionar llamadas salientes"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Permite que la aplicación vea el número marcado al realizar una llamada, con la opción de redirigir esta llamada a un número distinto o cancelarla completamente."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Permite que la aplicación procese las llamadas salientes y cambie el número que se va a marcar. La aplicación puede utilizar este permiso para controlar o desviar llamadas salientes o para impedir que se realicen."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"recibir mensajes de texto (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Permite que la aplicación reciba y procese mensajes SMS, lo que significa que podría controlar o eliminar mensajes enviados al dispositivo sin mostrártelos."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"recibir mensajes de texto (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Permite que la aplicación recupere el contenido de la ventana activa. Las aplicaciones maliciosas pueden recuperar el contenido completo de la ventana y examinar todo el texto, excepto las contraseñas."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"Activación temporal de la accesibilidad"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Permite a una aplicación activar temporalmente la accesibilidad en el dispositivo. Las aplicaciones maliciosas pueden activar la accesibilidad sin el consentimiento del usuario."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"recuperar token de ventana"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Permite que una aplicación recupere el token de ventana. Las aplicaciones maliciosas pueden interaccionar sin autorización con la ventana de la aplicación al hacerse pasar por el sistema."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"recuperar estadísticas de marcos"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Permite que una aplicación recopile estadísticas de marcos. Las aplicaciones maliciosas pueden observar estas estadísticas de ventanas desde otras aplicaciones."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"recuperar información de ventanas"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Permite que una aplicación recupere la información del administrador de ventanas relacionada con estas. Las aplicaciones maliciosas pueden recuperar información destinada al uso interno del sistema."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filtrar eventos"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Permite que una aplicación registre un filtro de entrada que filtre la transmisión de todos los eventos del usuario antes de ser enviados. Las aplicaciones maliciosas pueden controlar la IU del sistema sin la intervención del usuario."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"ampliar la pantalla"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Permite que una aplicación amplíe el contenido de una pantalla. Las aplicaciones malintencionadas pueden transformar el contenido de la pantalla de manera que el dispositivo quede inutilizable."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"cierre parcial"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Pone al administrador de la actividad en estado de cierre. No realiza un cierre completo."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"impedir conmutadores de aplicación"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permite que la aplicación transmita una notificación acerca de la recepción de un mensaje SMS. Las aplicaciones maliciosas pueden utilizar este permiso para falsificar mensajes SMS entrantes."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar emisiones WAP-PUSH-recibido"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permite que la aplicación transmita una notificación acerca de la recepción de un mensaje WAP PUSH. Las aplicaciones maliciosas pueden utilizar este permiso para falsificar la recepción de mensajes MMS o para reemplazar sin aviso el contenido de cualquier página web con variantes maliciosas."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"enviar transmisión de puntuación de redes"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Permite que la aplicación transmita una notificación que las redes necesitan para recibir una puntuación. Las aplicaciones normales no necesitan nunca este permiso."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar la cantidad de procesos en ejecución"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permite que la aplicación controle la cantidad máxima de procesos que se ejecutarán. Las aplicaciones normales no deben utilizar este permiso."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forzar el cierre de aplicaciones de fondo"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permite al titular vincularse a la interfaz de nivel superior de un servicio de VPN. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"vincular a un fondo de pantalla"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite al propietario vincularse a la interfaz de nivel superior de un fondo de pantalla. Las aplicaciones normales no deben utilizar este permiso."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"vincular a una pantalla remota"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite al propietario vincularse a la interfaz de nivel superior de una pantalla remota. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincular a un servicio de widget"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Permite al propietario vincularse a la interfaz de nivel superior de una entrada de TV. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"agregar o eliminar un administrador de dispositivos"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite al propietario agregar o eliminar administradores de dispositivos activos. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar la orientación de la pantalla"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que la aplicación use cualquier decodificador de archivos multimedia instalado para la reproducción."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrar credenciales de confianza"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que la aplicación instale y desinstale certificados de CA como credenciales de confianza."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"ejecutar la aplicación durante el tiempo de inactividad"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Con este permiso, el sistema Android puede ejecutar la aplicación en segundo plano mientras el dispositivo no está en uso."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"vincular con servicios inactivos"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Este permiso autoriza al sistema Android a vincularse con los servicios inactivos de una aplicación."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"leer y escribir a recursos dentro del grupo de diagnóstico"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que la aplicación lea y escriba en cualquier recurso propiedad del grupo de diagnóstico como, por ejemplo, archivos in/dev. Este permiso podría afectar la seguridad y estabilidad del sistema. SOLO se debe utilizar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activar o desactivar componentes de la aplicación"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Permite que la aplicación consulte la información del perfil personal almacenada en el dispositivo, como el nombre o la información de contacto, lo que significa que la aplicación puede identificar al usuario y enviar la información de su perfil a otros usuarios."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"modif. tarjeta contacto propia"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Permite que la aplicación modifique la información del perfil personal almacenada en el dispositivo, como el nombre o la información de contacto, o que agregue contenido a esa información. Esto significa que puede identificarte y enviar la información de tu perfil a otros usuarios."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"sensores corporales (frec. card)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Permite que la aplicación acceda a datos de sensores que utilizas para medir lo que sucede en tu cuerpo, como la frecuencia cardíaca."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"Lectura de tu muro social"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Permite que la aplicación acceda a las actualizaciones de tus redes sociales y las de tus amigos, y que las sincronice. Ten cuidado al compartir información, ya que la aplicación puede utilizar este permiso para leer las conversaciones que tengas con tus amigos en las redes sociales sin tener en cuenta si son confidenciales. Nota: Este permiso no se puede utilizar en todas las redes sociales."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"Escritura en tu muro social"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permite que la aplicación controle las funciones de teléfono del dispositivo. Una aplicación con este permiso puede cambiar redes, encender y apagar la radio del teléfono y tareas similares sin siquiera notificártelo."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"leer la identidad y el estado del dispositivo"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que la aplicación acceda a las funciones de teléfono del dispositivo. La aplicación puede utilizar este permiso para descubrir identificadores de dispositivos y números de teléfono, para saber si una llamada está activa y para conocer el número remoto con el que se ha establecido conexión mediante una llamada."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"leer estados precisos del teléfono"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permite que la aplicación acceda a los estados precisos del teléfono y determine el estado real de la llamada, si hay una llamada activa o en segundo plano, si se produjeron fallos en la llamada, el estado preciso de la conexión de datos y si hubo fallos relacionados con la conexión de datos."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"evitar que el tablet entre en estado de inactividad"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"evitar que el dispositivo entre en estado de inactividad"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que la aplicación evite que la tablet entre en estado de inactividad."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Cambiar el estado de WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite que la aplicación conecte la tablet a una red WiMAX y que la desconecte de ella."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permite que la aplicación conecte el dispositivo a una red WiMAX y que lo desconecte de ella."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"puntuar redes"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Permite que la aplicación clasifique redes e influya en las redes que la tablet debería preferir."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Permite que la aplicación clasifique redes e influya en las redes que el teléfono debería preferir."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"vincular con dispositivos Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permite que la aplicación vea la configuración de Bluetooth de la tablet y que cree y acepte conexiones con los dispositivos sincronizados."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permite que la aplicación vea la configuración de Bluetooth del dispositivo y que cree y acepte conexiones con los dispositivos sincronizados."</string>
@@ -703,18 +683,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ejecutar la aplicación de configuración proporcionada por el proveedor"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite al propietario ejecutar la aplicación de configuración proporcionada por el proveedor. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Detectar cambios en el estado de la red"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que una aplicación detecte cambios en el estado de la red. Las aplicaciones normales no deberían necesitar este permiso."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"cambiar la calibración del dispositivo de entrada"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permite que la aplicación modifique los parámetros de calibración de la pantalla táctil. Las aplicaciones normales no deberían necesitar este permiso."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"Acceder a certificados DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Permite que una aplicación proporcione y utilice certificados DRM. Las aplicaciones normales no deberían necesitar este permiso."</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="policylab_watchLogin" msgid="914130646942199503">"Supervisa los intentos para desbloquear la pantalla"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permite que una aplicación acceda al almacenamiento seguro de bloqueos."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Controlar cuándo se muestra y se oculta el bloqueo"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permite que una aplicación controle los bloqueos."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Detectar cambios en estado de confianza"</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite que una aplicación detecte cambios en el estado de confianza."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Vincular con un servicio de agente de confianza"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite que una aplicación se vincule con un servicio de agente de confianza."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interaccionar con el sistema de recuperación y las actualizaciones"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Permite que una aplicación interaccione con el sistema de recuperación y las actualizaciones del sistema."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Toca dos veces para acceder al control de zoom."</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Papel tapiz"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Cambiar fondo de pantalla"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Agente de escucha de notificaciones"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN está activado por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Toca para administrar la red."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index cd96a08..5010841 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronización"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Se ha agotado el espacio de almacenamiento del tablet. Elimina algunos archivos para liberar espacio."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"El almacenamiento del reloj está lleno. Elimina algunos archivos para liberar espacio."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Se ha agotado el espacio de almacenamiento del teléfono. Elimina algunos archivos para liberar espacio."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Es posible que la red esté supervisada"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Por un tercero desconocido"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Timbre activado"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Apagando..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"El tablet se apagará."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"El reloj se apagará."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"El teléfono se apagará."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"¿Seguro que quieres apagar el teléfono?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Reiniciar en modo seguro"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avión"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt; 999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"desinstalar accesos directos"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Permite que la aplicación elimine accesos directos de la pantalla de inicio sin la intervención del usuario."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"redireccionar llamadas salientes"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Permite que la aplicación vea el número que se marca al realizar una llamada con la opción de redirigir la llamada a otro número o cancelar la llamada."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Permite que la aplicación procese las llamadas salientes y cambie el número que se va a marcar. La aplicación puede utilizar este permiso para controlar, desviar o impedir que se realicen llamadas salientes."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"recibir mensajes de texto (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Permite que la aplicación reciba y procese mensajes MMS, lo que significa que podría utilizar este permiso para controlar o eliminar mensajes enviados al dispositivo sin mostrárselos al usuario."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"recibir mensajes de texto (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Permite que la aplicación recupere el contenido de la ventana activa. Las aplicaciones malintencionadas pueden recuperar todo el contenido de la ventana y analizar todo el texto de la misma, excepto las contraseñas."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"habilitar la accesibilidad de forma temporal"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Permite que una aplicación habilite la accesibilidad en el dispositivo de forma temporal. Las aplicaciones maliciosas pueden habilitar la accesibilidad sin el consentimiento del usuario."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"recuperar token de ventana"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Permite que una aplicación recupere el token de ventana. Las aplicaciones maliciosas pueden interactuar sin autorización con la ventana de la aplicación suplantando la identidad del sistema."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"recuperar estadísticas de enmarcación"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Permite que una aplicación recopile estadísticas de enmarcación. Las aplicaciones maliciosas pueden observar estas estadísticas de ventanas desde otras aplicaciones."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"recuperar información de ventanas"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Permite que una aplicación recupere información sobre las ventanas del administrador de ventanas. Las aplicaciones malintencionadas pueden recuperar información destinada al uso interno del sistema."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filtrar eventos"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Permite que una aplicación registre un filtro de entrada que filtre el flujo de los eventos del usuario antes de que se envíe. Las aplicaciones malintencionadas pueden controlar la interfaz del sistema sin la intervención del usuario."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"ampliar pantalla"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Permite que una aplicación amplíe el contenido de una pantalla. Las aplicaciones maliciosas pueden transformar el contenido de la pantalla para que el dispositivo no se pueda utilizar."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"cierre parcial"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Pone el administrador de actividades en estado de cierre. No realiza un cierre completo."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"evitar cambios de aplicación"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permite que la aplicación emita una notificación cuando se haya recibido un mensaje SMS. Las aplicaciones malintencionadas pueden usar este permiso para falsificar mensajes SMS entrantes."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar emisión recibida mediante mensaje WAP PUSH"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permite que la aplicación envíe una notificación cuando se haya recibido un mensaje WAP PUSH. Las aplicaciones malintencionadas pueden usar este permiso para falsificar la recepción de un mensaje MMS o para reemplazar sin aviso el contenido de cualquier página web con variantes malintencionadas."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"enviar notificaciones sobre la puntuación de las redes"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Permite que la aplicación emita una notificación que la red necesita para recibir una puntuación. Las aplicaciones normales no necesitan nunca este permiso."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar el número de procesos en ejecución"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permite que la aplicación controle el número máximo de procesos que se ejecutarán. No es necesario nunca para las aplicaciones normales."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forzar el cierre de aplicaciones en segundo plano"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permite enlazar con la interfaz de nivel superior de un servicio de VPN. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"enlazar con un fondo de pantalla"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite enlazar con la interfaz de nivel superior de un fondo de pantalla. Las aplicaciones normales no deberían necesitar este permiso."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"enlazar a una pantalla remota"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite enlazar con la interfaz de nivel superior de una pantalla remota. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"enlazar con un servicio de widget"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Permite enlazar con la interfaz de nivel superior de una entrada de TV. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"añadir o eliminar un administrador de dispositivos"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite añadir o eliminar administradores de dispositivos activos. No debe ser necesario para aplicaciones normales."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar orientación de la pantalla"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que la aplicación use cualquier decodificador de archivos multimedia instalado para la reproducción."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrar credenciales de confianza"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que la aplicación instale y desinstale certificados de CA como credenciales de confianza."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"ejecutar la aplicación durante el tiempo de inactividad"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Esto permite que el sistema Android ejecute la aplicación en segundo plano mientras el dispositivo no se utiliza."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"ocultar para servicios inactivos"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Esto permite que el sistema Android enlace con servicios inactivos de una aplicación."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"leer/escribir en los recursos propiedad del grupo de diagnóstico"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que la aplicación consulte y escriba en cualquier recurso del grupo de diagnóstico como, por ejemplo, archivos en /dev. Este permiso podría afectar a la seguridad y estabilidad del sistema. SOLO se debe usar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"habilitar o inhabilitar componentes de la aplicación"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Permite que la aplicación consulte la información del perfil personal almacenada en el dispositivo (como el nombre o la información de contacto), lo que significa que la aplicación puede identificar al usuario y enviar la información de su perfil a otros usuarios."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"modificar tu propia tarjeta de contacto"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Permite que la aplicación modifique la información del perfil personal almacenada en el dispositivo (como el nombre o la información de contacto) o que añada contenido a esa información, lo que significa que puede identificar al usuario y enviar la información de su perfil a otros usuarios."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"sens. corp. (mon. frec. card.)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Permite que la aplicación acceda a datos de sensores que utilizas para medir lo que sucede en tu cuerpo, como la frecuencia cardíaca."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"consulta tu actividad social"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Permite que la aplicación acceda a novedades de redes sociales tuyas y de tus amigos y las sincronice. Ten cuidado al compartir información, ya que la aplicación puede utilizar este permiso para leer conversaciones privadas con tus amigos en las redes sociales sin tener en cuenta si son confidenciales. Nota: este permiso no se puede utilizar en todas las redes sociales."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"escribir en tu actividad social"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permite que la aplicación controle las funciones de teléfono del dispositivo. Las aplicaciones que tengan este permiso pueden cambiar de red, desactivar la señal móvil, etc., sin necesidad de informar al usuario."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"consultar la identidad y el estado del teléfono"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que la aplicación acceda a las funciones de teléfono del dispositivo. La aplicación puede utilizar este permiso para descubrir identificadores de dispositivos y números de teléfono, para saber si una llamada está activa y para conocer el número remoto con el que se ha establecido conexión mediante una llamada."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"leer estados precisos del teléfono"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permite que la aplicación acceda a estados precisos del teléfono y que pueda determinar el estado real de la llamada, si una llamada está activa o en segundo plano, si se ha producido un error en la llamada, el estado de conexión de datos preciso y si se ha producido un error en la conexión de datos."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"impedir que el tablet entre en modo de suspensión"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir que el teléfono entre en modo de suspensión"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que la aplicación impida que el tablet entre en modo de suspensión."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Cambiar estado de WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite que la aplicación conecte el tablet a redes WiMAX y lo desconecte de ellas."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permite que la aplicación conecte el teléfono a redes WiMAX y lo desconecte de ellas."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"puntuar redes"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Permite que la aplicación clasifique redes e influya en las redes que el tablet debe preferir."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Permite que la aplicación clasifique una red e influya en las redes que el teléfono debe preferir."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"vincular con dispositivos Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permite que la aplicación acceda a la configuración de Bluetooth del tablet y que establezca y acepte conexiones con los dispositivos sincronizados."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permite que la aplicación acceda a la configuración de Bluetooth del teléfono y que establezca y acepte conexiones con los dispositivos sincronizados."</string>
@@ -703,18 +683,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ejecutar la aplicación de configuración proporcionada por el operador"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite ejecutar la aplicación de configuración proporcionada por el operador. No debe ser necesario para aplicaciones normales."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"detectar cambios en el estado de la red"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que una aplicación detecte cambios en el estado de la red. No debe ser necesario para aplicaciones normales."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"cambiar la calibración del dispositivo de entrada"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permite que la aplicación modifique los parámetros de calibración de la pantalla táctil. No debe ser necesario para las aplicaciones normales."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"acceder a certificados DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Permite que una aplicación proporcione y utilice certificados DRM. 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="policylab_watchLogin" msgid="914130646942199503">"Control de intentos de bloqueo de pantalla"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permite que una aplicación acceda al almacenamiento seguro de bloqueos."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Controlar cuándo se muestra y se oculta el bloqueo"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permite que una aplicación controle los bloqueos."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Detectar cambios en el estado de confianza."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite que una aplicación detecte cambios en el estado de confianza."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Enlazar con un servicio de agente de confianza"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite a una aplicación enlazar con un servicio de agente de confianza."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interactuar con el sistema de recuperación y las actualizaciones"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Permite que una aplicación interactúe con el sistema de recuperación y las actualizaciones del sistema."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Toca dos veces para acceder al control de zoom."</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Fondo de pantalla"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Cambiar fondo de pantalla"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Detector de notificaciones"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN activada por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Toca para administrar la red."</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 1d905df..f16381c 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sünkroonimine"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Liiga palju üksuse <xliff:g id="CONTENT_TYPE">%s</xliff:g> kustutusi."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Tahvelarvuti mäluruum on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Kella talletusruum on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Telefonimälu on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Võrku võidakse jälgida"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Tundmatu kolmas osapool:"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Helin on sees"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Väljalülitamine ..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Teie tahvelarvuti lülitub välja."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Teie kell lülitub välja."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Teie telefon lülitub välja."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Kas soovite välja lülitada?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Ohutus režiimis taaskäivitamine"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Lennurežiim"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Turvarežiim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-süsteem"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"otseteede desinstallimine"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Lubab rakendusel eemaldada avaekraani otseteid ilma kasutaja sekkumiseta."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"marsruutige väljuvad kõned uuesti"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Lubab rakendusel näha, mis number valitakse väljahelistamisel, ning laseb suunata kõne teisele numbrile või selle üldse katkestada."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Võimaldab rakendusel töödelda väljuvaid kõnesid ja muuta valitavat numbrit. Luba võimaldab rakendusel jälgida, ümber suunata või takistada väljuvaid kõnesid."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"võtke vastu tekstisõnumeid (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Võimaldab rakendusel vastu võtta ja töödelda SMS-sõnumeid. See tähendab, et rakendus võib jälgida või kustutada teie seadmele saadetud sõnumeid neid teile näitamata."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"võtke vastu tekstisõnumeid (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Võimaldab rakendusel kätte saada aktiivse akna sisu. Pahatahtlikud rakendused võivad hankida kogu akna sisu ja uurida kogu selle teksti, välja arvatud paroole."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"ajutine hõlbustuse lubamine"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Lubab rakendusel ajutiselt lubada seadmes hõlbustuse. Pahatahtlikud rakendused võivad lubada hõlbustuse kasutaja nõusolekuta."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"aknaloa toomine"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Lubab rakendusel tuua aknaloa. Pahatahtlikud rakendused võivad jäljendada süsteemi ja suhelda rakenduse aknaga ilma loata."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"raamistatistika toomine"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Lubab rakendusel koguda raamistatistikat. Pahatahtlikud rakendused võivad jälgida teiste rakenduste akende raamistatistikat."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"hangi akna teave"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Võimaldab rakendusel hankida teavet aknahalduri akende kohta. Pahatahtlikud rakendused võivad hankida teavet, mis on mõeldud süsteemisiseseks kasutamiseks."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filtreeri sündmused"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Võimaldab rakendusel registreerida sisestusfiltri, mis filtreerib kõigi kasutaja sündmuste voo, enne kui need ära saadetakse. Pahatahtlik rakendus võib süsteemi kasutajaliidest juhtida ilma kasutaja sekkumiseta."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"kuva suurendamine"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Lubab rakendusel ekraani sisu suurendada. Pahatahtlikud rakendused võivad muundada kuva sisu nii, et seade muutub ebastabiilseks."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"osaline väljalülitamine"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Lülitab tegevushalduri väljalülitusolekusse. Ei lülita lõplikult välja."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"väldi rakenduste ümberlülitamist"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Võimaldab rakendusel edastada teatise SMS-sõnumi vastuvõtmise kohta. Pahatahtlikud rakendused võivad seda kasutada sissetulevate SMS-sõnumite võltsimiseks."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"saada WAP-PUSH-vastuvõetud saateid"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Võimaldab rakendusel edastada teatise WAP PUSH-sõnumi vastuvõtmise kohta. Pahatahtlikud rakendused võivad seda kasutada MMS-sõnumite vastuvõtmise võltsimiseks või mis tahes veebilehe sisu salaja asendamiseks pahatahtlikuga."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"võrkude levi hinnangu saatmine"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Lubab rakendusel levitada märguannet, et võrke tuleb hinnata. Seda ei ole kunagi vaja tavapäraste rakenduste puhul."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"piira töötavate protsesside arvu"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Võimaldab rakendusel juhtida töötavate protsesside maksimaalset arvu. Tavarakenduste puhul pole seda vaja."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"sundige taustarakendused sulguma"</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Võimaldab omanikul siduda VPN-teenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"taustapildiga sidumine"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Lubab omanikul siduda taustapildi ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"kaugekraaniga sidumine"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lubab omanikul siduda rakenduse kaugekraani ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vidinateenusega sidumine"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Võimaldab rakendusel taasesituseks kasutada mis tahes installitud meediumidekooderit."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"usaldusväärsete mandaatide haldamine"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lubab rakendusel installida ja desinstallida usaldusväärsete mandaatidena CA-sertifikaate."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"rakenduse käitamine tegevusetul ajal"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"See luba võimaldab Android-süsteemil käitada rakendust taustal siis, kui seadet ei kasutata."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"sidumine tegevusetute teenustega"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"See luba võimaldab Androidi süsteemil siduda end rakenduse tegevusetute teenustega."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"loe/kirjuta valija allikaid"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Võimaldab rakendusel lugeda valimisrühma mis tahes ressurssi ja sellesse kirjutada (näiteks kaustas /dev olevad failid). See võib mõjutada süsteemi stabiilsust ja turvet. Seda tohiks kasutada tootja või operaator AINULT riistvaraspetsiifiliseks diagnostikaks."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"Rakenduse komponentide lubamine või keelamine"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Võimaldab rakendusel lugeda seadmesse salvestatud isiklikku profiiliteavet, näiteks teie nime ja kontaktteavet. See tähendab, et rakendus saab teid tuvastada ja saata teie profiiliteavet teistele."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"muutke oma kontaktikaarti"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Võimaldab rakendusel muuta või lisada seadmesse salvestatud isiklikku profiiliteavet, näiteks teie nime ja kontaktteavet. See tähendab, et rakendus saab teid tuvastada ja saata teie profiiliteavet teistele."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"kehaandurid (nt pulsilugeja)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Lubab rakendusel saada juurdepääsu selliste andurite andmetele, mida kasutate kehas toimuva (nt pulsi) mõõtmiseks."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"Sotsiaalvoo lugemine"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Annab rakendusele juurdepääsu ja võimaldab sünkroonida teie ja teie sõprade sotsiaalseid värskendusi. Olge teabe jagamisel ettevaatlik – see võimaldab rakendusel lugeda teie suhtlusi sõpradega suhtlusvõrgustikes konfidentsiaalsusest hoolimata. Märkus: see luba ei pruugi jõustuda kõigis suhtlusvõrgustikes."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"Sotsiaalvoogu kirjutamine"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Võimaldab rakendusel juhtida seadme telefonifunktsioone. Selle loaga rakendus saab vahetada võrke, lülitada telefoniraadiot sisse ja välja ning teha muudki ilma teid teavitamata."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"lugege telefoni olekut ja identiteeti"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Annab rakendusele juurdepääsu seadme telefonifunktsioonidele. See luba võimaldab rakendusel määrata telefoninumbri ja seadme ID-d ning kontrollida, kas kõne on aktiivne ja kaugnumber on kõne kaudu telefoniga ühendatud."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"telefoni täpsete olekute lugemine"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Lubab rakendusel hankida juurdepääsu telefoni täpsetele olekutele. Selle loa korral saab rakendus tuvastada kõne tõelise oleku, kas kõne on aktiivne või taustal, kõnede ebaõnnestumised, täpse andmesideühenduse oleku ja andmesideühenduse ebaõnnestumised."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"tahvelarvuti uinumise vältimine"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"väldi telefoni uinumist"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Võimaldab rakendusel vältida tahvelarvuti uinumist."</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX-i oleku muutmine"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Võimaldab rakendusel luua ja katkestada tahvelarvuti ühenduse WiMAX-i võrkudega."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Võimaldab rakendusel luua ja katkestada telefoni ühenduse WiMAX-i võrkudega."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"võrkude hindamine"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Lubab rakendusel võrke hinnata ja mõjutada seda, milliseid võrke peaks tahvelarvuti eelistama."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Lubab rakendusel võrke hinnata ja mõjutada seda, milliseid võrke peaks telefon eelistama."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"siduge Bluetoothi seadmetega"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Võimaldab rakendusel vaadata tahvelarvuti Bluetooth-konfiguratsiooni ning luua ja heaks kiita ühendusi seotud seadmetega."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Võimaldab rakendusel vaadata telefoni Bluetooth-konfiguratsiooni ning luua ja heaks kiita ühendusi seotud seadmetega."</string>
@@ -703,18 +685,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"operaatoripoolse konfiguratsioonirakenduse aktiveerimine"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Lubab omanikul aktiveerida operaatoripoolse konfiguratsioonirakenduse. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"võrgutingimuste teabe kuulamine"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Lubab rakendusel kuulata võrgutingimuste teavet. Ei ole kunagi vajalik tavaliste rakenduste puhul."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"sisendseadme kalibreerimise muutmine"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Lubab rakendusel muuta puuteekraani kalibreerimisparameetreid. Ei tohiks kunagi olla vajalik tavaliste rakenduste puhul."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"juurdepääs DRM-i sertifikaatidele"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Lubab rakendusel ette valmistada ja kasutada DRM-i sertifikaate. Tavarakenduste puhul ei tohiks see vajalik olla."</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="policylab_watchLogin" msgid="914130646942199503">"Ekraani avamiskatsed"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Lubab rakendusel hankida juurdepääsu võtmekaitsega turvalisele talletusruumile."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Võtmekaitse kuvamise ja peitmise juhtimine"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Lubab rakendusel võtmekaitset juhtida."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Usaldusväärse oleku muudatuste tuvastamine."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Lubab rakendusel tuvastada muudatusi usaldusväärses olekus."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Usaldusväärse agendi teenusega sidumine"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Lubab rakendusel ennast siduda usaldusväärse agendi teenusega."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Suhtlemine värskenduse ja taastesüsteemiga"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Lubab rakendusel suhelda taastesüsteemi ja süsteemivärskendustega."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Suumi juhtimiseks puudutage kaks korda"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Taustapilt"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Muutke taustapilti"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Märguannete kuulamisteenus"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN on aktiveeritud"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN-i aktiveeris <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Võrgu haldamiseks puudutage."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index a198fbb..34ee392 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"همگام‌سازی"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"تعداد موارد حذف شده <xliff:g id="CONTENT_TYPE">%s</xliff:g> بسیار زیاد است."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"‏حافظه رایانهٔ لوحی پر است! برخی از فایل‎ها را حذف کنید تا فضا آزاد شود."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"حافظه ساعت پر است. برای آزادسازی فضا، چند فایل را حذف کنید."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"حافظه تلفن پر است. بعضی از فایل‌ها را حذف کنید تا فضا آزاد شود."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ممکن است شبکه نظارت شده باشد"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"توسط یک شخص ثالث ناشناس"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"زنگ روشن"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"در حال خاموش شدن…"</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"رایانهٔ لوحی شما خاموش می‌شود."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"ساعت شما خاموش می‌شود."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"گوشی شما خاموش می‌شود."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"‏آیا می‎خواهید تلفن خاموش شود؟"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"راه‌اندازی مجدد در حالت امن"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"حالت هواپیما"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"بیشتر از 999"</string>
     <string name="safeMode" msgid="2788228061547930246">"حالت ایمن"</string>
     <string name="android_system_label" msgid="6577375335728551336">"‏سیستم Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"حذف نصب میان‌برها"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"به برنامه اجازه می‌دهد میان‌برهای صفحه اصلی را بدون دخالت کاربر حذف کند."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"ترسیم مجدد مسیر تماس‌های خروجی"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"به برنامه اجازه می‌دهد عددی را که در طی یک تماس خروجی شماره‌گیری شده، ببیند و این اختیار را دارد که تماس را به شماره دیگری هدایت کند یا کلاً تماس را قطع کند."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"‏به برنامه اجازه می‎دهد تماس‌های خروجی را پردازش کند و شماره‎هایی که باید گرفته شوند را تغییر دهد. این مجوز به برنامه امکان می‌دهد به کنترل، هدایت مجدد یا جلوگیری از تماس‌های خروجی بپردازد."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"دریافت پیام‌های نوشتاری (پیامک)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"به برنامه اجازه می‌دهد پیامک‌ها را دریافت و پردازش کند. این یعنی برنامه می‌تواند پیام‌های ارسالی به دستگاه شما را بدون نمایش آن‌ها به شما حذف یا کنترل کند."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"‏دریافت پیام‌های نوشتاری (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"‏به برنامه اجازه می‎دهد تا محتوای پنجره فعال را بازیابی کند. برنامه‎های مخرب می‎توانند کل محتوای پنجره را بازیابی کنند و همه متن آنرا به غیر از گذرواژه‎ها امتحان کنند."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"قابلیت دسترسی به طور موقت فعال شود"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"به یک برنامه اجازه می‌دهد به صورت موقت قابلیت دسترسی را در دستگاه فعال کند. برنامه‌های مخرب می‌توانند قابلیت دسترسی را بدون رضایت کاربر فعال کنند."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"بازیابی کد پنجره"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"به یک برنامه کاربردی اجازه می‌دهد کد پنجره را بازیابی کند. برنامه‌های مخرب ممکن است با جعل کردن سیستم، تعامل غیرمجازی با پنجره برنامه انجام دهند."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"بازیابی آمار قاب‌ها"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"به یک برنامه کاربردی اجازه می‌دهد آمار قاب‌ها را جمع‌آوری کند. برنامه‌های مخرب ممکن است از برنامه‌های دیگر آمار قاب‌های مربوط به پنجره‌ها را مشاهده کنند."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"بازیابی اطلاعات پنجره"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"به یک برنامه کاربردی اجازه می‌دهد که اطلاعات مربوط به پنجره‌ها را از مدیریت پنجره بازیابی کند. برنامه‌های کاربردی مخرب ممکن است اطلاعاتی که برای استفاده سیستم داخلی درنظر گرفته شده‌اند را بازیابی کنند."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"فیلتر کردن رویدادها"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"به یک برنامه کاربردی اجازه می‌دهد یک فیلتر ورودی را که جریان تمام رویدادهای کاربران را قبل از ارسال شدن فیلتر می‌کند، ثبت نماید. برنامه‌ کاربردی مخرب ممکن است رابط کاربری سیستم را بدون مداخله کاربر، کنترل کند."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"بزرگ کردن صفحه نمایش"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"به یک برنامه کاربردی اجازه بزرگ کردن محتوای یک صفحه نمایش را می‌دهد. برنامه‌های کاربردی مضر می‌توانند محتوای صفحه نمایش را به طریقی منتقل کنند که باعث غیرقابل‌استفاده شدن دستگاه شود."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"خاموش شدن جزئی"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"مدیر فعالیت را در حالت خاموشی قرار می‌دهد. خاموشی را به صورت کامل انجام نمی‌دهد."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"ممانعت از جابجایی برنامه"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"‏به برنامه اجازه می‎دهد تا اعلان دریافت پیام کوتاه را پخش کند. برنامه‎های مخرب می‎توانند از این برای جعل پیام‌های کوتاه ورودی استفاده کنند."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"‏ارسال پخش دریافت شده توسط WAP-PUSH"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"‏به برنامه اجازه می‎دهد تا اعلانی را پخش کند که پیام WAP PUSH دریافت کرده است. برنامه‎های مخرب می‎توانند از آن استفاده کنند تا دریافت پیام MMS را جعل کنند یا محتوای هر صفحهٔ وب را با انواع مخرب جایگزین کنند."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ارسال اعلان پخش برای امتیازبندی شبکه‌ها"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"به برنامه اجازه می‌دهد تا اعلانی پخش کند که شبکه‌ها باید امتیازبندی شوند. هرگز برای برنامه‌های عادی مورد نیاز نیست."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"محدود کردن تعداد فرآیندهای در حال اجرا"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"‏به برنامه اجازه می‎دهد تا حداکثر تعداد پردازشهایی را که اجرا خواهد شد کنترل کند. هرگز برای برنامه‎های عادی لازم نیست."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"بستن اجباری برنامه‌های پس‌زمینه"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"‏به دارنده اجازه می‌دهد که به رابط سطح بالای سرویس Vpn متصل شود. هرگز برای برنامه‌های معمولی مورد نیاز نیست."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"پیوند شده به تصویر زمینه"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"‏به دارنده اجازه می‎دهد تا به رابط سطح بالای تصویر زمینه متصل شود. برنامه‎های معمولی هرگز به این ویژگی نیاز ندارند."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"اتصال به نمایشگر راه دور"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"به برنامه امکان می‌دهد که به رابط سطح بالای ورودی تلویزیون متصل شود. هرگز برای برنامه‌های معمولی مورد نیاز نیست."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"اضافه یا حذف سرپرست دستگاه"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"به دارنده اجازه می‌دهد سرپرستان دستگاه فعال را اضافه یا حذف کند.هرگز نباید برای برنامه‌های عادی مورد نیاز باشد."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"تغییر جهت صفحه"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"‏اجازه می‎دهد برنامه از هر رمزگشای رسانه نصب شده‌ای استفاده کند تا برای پخش رمزگشایی شود."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"مدیریت اطلاعات کاربری مورد اعتماد"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"‏به برنامه امکان می‌دهد گواهینامه‌های CA را به عنوان اطلاعات کاربری مورد اعتماد نصب یا حذف نصب کند."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"اجرای برنامه در هنگام بدون فعالیت بودن دستگاه"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"‏این مجوز به سیستم Android امکان می‌دهد تا وقتی دستگاه استفاده نمی‌شود برنامه را در پس‌زمینه اجرا کند."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"اتصال با سرویس‌های غیرفعال"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"‏این مجوز به سیستم Android امکان می‌دهد به سرویس‌های غیرفعال یک برنامه متصل شود."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"خواندن/نوشتن منابع متعلق به تشخیص"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"‏به برنامه اجازه می‌دهد هر منبعی را که متعلق به گروه تشخیص است بخواند و در آن بنویسد؛ به‌عنوان مثال، فایل‌های /dev. این امر به‌صورت بالقوه می‌تواند بر پایدار بودن و امنیت سیستم تأثیر بگذارد. این تنها باید برای تشخیص‎‌های مختص سخت‌افزار توسط تولیدکننده یا اپراتور استفاده شود."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"فعال یا غیر فعال کردن اجزای برنامه"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"‏به برنامه اجازه می‎دهد اطلاعات نمایه شخصی ذخیره شده در دستگاه شما، مانند نام و اطلاعات تماس شما را بخواند. یعنی برنامه می‎تواند شما را شناسایی کند و ممکن است اطلاعات نمایهٔ شما را به دیگران ارسال کند."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"اصلاح کارت تماس شما"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"‏به برنامه اجازه می‎دهد تا اطلاعات نمایه شخصی ذخیره شده در دستگاه شما، مانند نام و اطلاعات تماس شما را تغییر دهد یا اضافه کند. یعنی برنامه‎ می‎تواند شما را شناسایی کند و ممکن است اطلاعات نمایهٔ شما را برای دیگران ارسال کند."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"حسگرهای بدن (مانند پایشگرهای ضربان قلب)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"به برنامه امکان می‌دهد به اطلاعات حسگرهایی که استفاده می‌کنید، دسترسی پیدا کند تا اندازه‌گیری‌های مربوط به آنچه که درون بدنتان رخ می‌دهد، مانند ضربان قلب، را انجام دهد."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"خواندن جریان اجتماعی شما"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"به برنامه اجازه می‌دهد به به‌روزرسانی‌های اجتماعی از طرف شما و دوستان شما دسترسی پیدا کرده و آن‌ها را همگام‌سازی کند. دقت کنید که هنگام اشتراک‌گذاری -- این ویژگی به برنامه اجازه می‌دهد ارتباطات بین شما و دوستان شما را در شبکه‌های اجتماعی، صرفنظر از محرمانه بودن آن‌ها بخواند. توجه: این مجوز ممکن است در همه شبکه‌های اجتماعی اجرا نشود."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"نوشتن در جریان اجتماعی شما"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"‏به برنامه اجازه می‎دهد ویژگی‌های دستگاه را کنترل کند. برنامه‎ای که این مجوز را دارد می‎تواند بدون اطلاع شما تعویض شبکه داشته باشد، رادیوی تلفن را روشن یا خاموش کند و کارهایی از این قبیل را انجام دهد."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"خواندن وضعیت تلفن و شناسه"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"به برنامه اجازه می‌دهد به ویژگی‌های تلفن دستگاه شما دسترسی پیدا کند. این مجوز به برنامه اجازه می‌دهد شماره تلفن و شناسه‌های دستگاه، فعال بودن یک تماس و شماره راه دوری که با یک تماس متصل شده است را مشخص کند."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"خواندن وضعیت‌های دقیق تلفن"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"به برنامه امکان می‌دهد به وضعیت‌های دقیق تلفن دسترسی داشته باشد. این مجوز به برنامه امکان می‌دهد وضعیت واقعی تماس، اینکه آیا تماس فعال است یا در پس‌زمینه قرار دارد، تماس‌های ناموفق، وضعیت دقیق اتصال داده و اتصال‌های ناموفق داده را تعیین کند."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ممانعت از به خواب رفتن رایانهٔ لوحی"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ممانعت از به خواب رفتن تلفن"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"‏به برنامه اجازه می‎دهد تا از غیرفعال شدن رایانهٔ لوحی جلوگیری کند."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"‏تغییر وضعیت WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"به برنامه امکان می‌دهد رایانهٔ لوحی را به شبکه‌های وایمکس متصل کرده یا اتصال آن را از این شبکه‌ها قطع کند."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"‏به برنامه امکان می‎دهد تا تلفن را به شبکه‌های وایمکس متصل کرده یا اتصال آنرا از این شبکه‌ها قطع کند."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"امتیازبندی شبکه‌ها"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"به برنامه اجازه می‌دهد که شبکه‌ها را درجه‌بندی کند و روی اینکه رایانه لوحی باید کدام شبکه را در اولویت قرار دهد تأثیر می‌گذارد."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"به برنامه اجازه می‌دهد که شبکه‌ها را درجه‌بندی کند و روی اینکه تلفن باید کدام شبکه را در اولویت قرار دهد تأثیر می‌گذارد."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"جفت کردن با دستگاه‌های بلوتوث"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"‏به برنامه اجازه می‎دهد تا پیکربندی بلوتوث در رایانهٔ لوحی را مشاهده کند و اتصال با دستگاه‌های مرتبط را برقرار کرده و بپذیرد."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"‏به برنامه اجازه می‎دهد تا پیکربندی بلوتوث در تلفن را مشاهده کند، و اتصالات دستگاه‌های مرتبط را برقرار کرده و بپذیرد."</string>
@@ -703,18 +683,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"به برنامه اجازه می‌دهد به بازیابی، بررسی و پاک کردن اعلان‌ها از جمله موارد پست شده توسط سایر برنامه‌ها بپردازد."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"اتصال به یک سرویس شنونده اعلان"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"به دارنده اجازه می‌دهد به یک رابط سطح بالای سرویس شنونده اعلان متصل شود. هرگز نباید برای برنامه‌های عادی لازم شود."</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"لغو برنامه پیکربندی ارائه شده توسط شرکت مخابراتی"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"به دارنده اجازه می‌دهد که تنظیمات برنامه شرکت مخابراتی را لغو کند. هرگز برای برنامه‌های معمولی مورد نیاز نیست."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"گوش دادن برای بررسی شرایط شبکه"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"به برنامه امکان می‌دهد برای بررسی شرایط شبکه گوش دهد. این امکان هرگز نباید برای برنامه‌های معمولی مورد نیاز باشد."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"تغییر کالیبراسیون دستگاه ورودی"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"به برنامه امکان می‌دهد پارامترهای کالیبراسیون صفحه لمسی را تغییر دهد. هرگز نباید برای برنامه‌های عادی مورد نیاز باشد."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"‏دسترسی به گواهی‌های DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"‏به یک برنامه کاربردی اجازه ارائه مجوز و استفاده از گواهی‌های DRM را می‌دهد. هرگز برای برنامه‌های عادی مورد نیاز نیست."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"تنظیم قوانین رمز ورود"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"‏طول و نویسه‎های مجاز در گذرواژه‌های بازکردن قفل صفحه را کنترل کنید."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"نمایش تلاش‌های قفل گشایی صفحه"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"به یک برنامه کاربردی برای دسترسی به فضای ذخیره‌سازی ایمن محافظ کلید اجازه می‌دهد."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"کنترل نمایش و پنهان کردن محافظ کلید"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"اجازه می‌دهد برنامه‌ای محافظ کلید را کنترل کند."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"‏گوش دادن به تغییرات وضعیت trust."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"‏به یک برنامه کاربردی برای گوش دادن به تغییرات در trust اجازه می‌دهد."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"‏اتصال به یک سرویس trust agent"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"‏به یک برنامه کاربردی برای اتصال به یک سرویس trust agent اجازه می‌دهد."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"تعامل با سیستم به‌روزرسانی و بازیابی"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"به یک برنامه کاربردی اجازه می‌دهد با سیستم بازیابی و به‌روزرسانی‌های سیستم تعامل داشته باشد."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"دوبار لمس کنید تا بزرگنمایی کنترل شود"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"تصویر زمینه"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"تغییر تصویر زمینه"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"شنونده اعلان"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"‏VPN فعال شد"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"‏VPN توسط <xliff:g id="APP">%s</xliff:g> فعال شده است"</string>
     <string name="vpn_text" msgid="3011306607126450322">"برای مدیریت شبکه لمس کنید."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 5a01910..01f37d5 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synkronointi"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Liikaa <xliff:g id="CONTENT_TYPE">%s</xliff:g>-poistoja."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Tablet-laitteen tallennustila on täynnä. Vapauta tilaa poistamalla tiedostoja."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Kellon tallennustila on täynnä. Vapauta tilaa poistamalla tiedostoja."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Puhelimen tallennustila on täynnä. Vapauta tilaa poistamalla tiedostoja."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Verkkoa saatetaan valvoa"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Valvoja on tuntematon kolmas osapuoli."</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Soittoääni: normaali"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Suljetaan..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tablet-laitteesi sammutetaan."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Kello sammutetaan."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Puhelin suljetaan."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Haluatko sammuttaa?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Käynnistä vikasietotilassa"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Lentokonetila"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Suojattu tila"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-järjestelmä"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"poista pikakuvakkeita"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Antaa sovelluksen poistaa aloitusruudun pikakuvakkeita ilman käyttäjän toimia."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"ohjaa uudelleen lähtevät puhelut"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Sallii sovelluksen nähdä numeron, joka valitaan lähtevää puhelua soitettaessa, ja antaa mahdollisuuden ohjata puhelun eri numeroon tai keskeyttää puhelun kokonaan."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Antaa sovelluksen käsitellä lähteviä puheluita ja muuttaa kohdenumeroita. Sovellus voi valvoa, uudelleenohjata tai estää lähteviä puheluita."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"vastaanota tekstiviestejä (teksti)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Antaa sovelluksen vastaanottaa ja käsitellä tekstiviestejä. Sovellus voi valvoa tai poistaa laitteeseesi lähetettyjä viestejä näyttämättä niitä sinulle."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"vastaanota tekstiviestejä (multimedia)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Antaa sovelluksen noutaa aktiivisen ikkunan sisällön. Haitalliset sovellukset voivat noutaa koko ikkunan sisällön ja tarkastella sen kaikkea tekstiä lukuun ottamatta salasanoja."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"ota esteettömyystila käyttöön väliaikaisesti"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Antaa sovelluksen ottaa esteettömyystilan käyttöön laitteessa väliaikaisesti. Haitalliset sovellukset voivat ottaa esteettömyystilan käyttöön ilman käyttäjän lupaa."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"ikkunan tunnisteen noutaminen"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Antaa sovelluksen noutaa ikkunan tunnisteen. Haitalliset sovellukset saattavat käyttää sovelluksen ikkunaa luvattomasti esiintymällä järjestelmänä."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"kehystilastojen noutaminen"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Antaa sovelluksen kerätä kehystilastoja. Haitalliset sovellukset saattavat tarkkailla toisten sovellusten ikkunoiden kehystilastoja."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"nouda ikkunoiden tietoja"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Antaa sovelluksen noutaa ikkunoiden tietoja ikkunanhallinnasta. Haitalliset sovellukset voivat noutaa tietoja, jotka on tarkoitettu järjestelmän sisäiseen käyttöön."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"suodata tapahtumat"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Antaa sovelluksen rekisteröidä syöttösuodattimen, joka suodattaa kaikkien käyttäjätapahtumien streamin ennen tapahtumien näyttämistä. Haitalliset sovellukset voivat hallita järjestelmän käyttöliittymää ilman käyttäjän lupaa."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"suurenna ruutu"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Antaa sovelluksen suurentaa ruudun sisällön. Haitalliset sovellukset voivat muuttaa näytettävää sisältöä siten, ettei laitetta enää voi käyttää."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"sulje puhelin osittain"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Asettaa toimintojen hallinnan sulkeutumistilaan. Ei sulje puhelinta kokonaan."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"estä sovellusten vaihto"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Sallii sovelluksen lähettää ilmoituksen tekstiviestin vastaanotosta. Haitalliset sovellukset voivat käyttää tätä saapuvien tekstiviestien väärentämiseen."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"lähetä WAP-PUSH-vastaanotettu lähetys"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Antaa sovelluksen lähettää ilmoituksen WAP PUSH -viestin vastaanotosta. Haitalliset sovellukset voivat käyttää tätä MMS-viestien vastaanoton väärentämiseen tai sivujen sisällön korvaamiseen huomaamattomasti haitallisella sisällöllä."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"lähetä verkkojen pisteet"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Sallii sovelluksen lähettää ilmoituksen verkon pisteytystarpeesta. Ei tarvita tavallisissa sovelluksissa."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"rajoita käynnissä olevien prosessien määrää"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Antaa sovelluksen hallita suoritettavien sovellusten enimmäismäärää. Ei tavallisten sovellusten käyttöön."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"pakota taustasovelluksia sulkeutumaan"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Antaa sovelluksen sitoutua VPN-palvelun ylemmän tason käyttöliittymään. Ei tavallisten sovellusten käyttöön."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"sido taustakuvaan"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Antaa sovelluksen sitoutua taustakuvan ylätason käyttöliittymään. Ei tavallisten sovellusten käyttöön."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"etänäyttöön sitoutuminen"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Antaa sovelluksen sitoutua etänäytön ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"sitoudu widget-palveluun"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Antaa sovelluksen sitoutua TV-tulon ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"lisää tai poista laitteen järjestelmänvalvoja"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Haltija voi lisätä tai poistaa aktiivisen laitteen järjestelmänvalvojia. Tätä ei pitäisi tarvita tavallisille sovelluksille."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"muuta näytön suuntaa"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Sallii sovelluksen käyttää mitä tahansa asennettua tietovälineen koodin purkajaa toistoa varten."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"hallinnoi luotettavia varmenteita"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Antaa sovellukselle luvan asentaa ja poistaa luotettavia CA-varmenteita."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"suorita sovellus laitteen ollessa käyttämättömänä"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Tämä oikeus sallii Android-järjestelmän siirtää sovelluksen suorituksen taustalle, kun laite ei ole käytössä."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"sido käyttämättömiin palveluihin"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Tämä käyttöoikeus antaa Android-järjestelmän sitoa sovelluksen käyttämättömiä palveluita."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lue diag:in omistamia resursseja / kirjoita resursseihin"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Antaa sovelluksen lukea ja kirjoittaa diag-ryhmän omistamiin resursseihin, esimerkiksi /dev-hakemistossa oleviin tiedostoihin. Tämä voi vaikuttaa järjestelmän vakauteen ja turvallisuuteen. Tämä lupa tulee myöntää VAIN valmistajan tai operaattorin laitteistotesteille."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"sovelluskomponenttien ottaminen käyttöön tai pois käytöstä"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Antaa sovelluksen lukea laitteelle tallennettuja henkilökohtaisia tietoja, kuten nimen ja yhteystietoja. Sovellus voi tunnistaa sinut ja lähettää profiilitietojasi muille."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"muokkaa omia yhteystietoja"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Antaa sovelluksen muuttaa laitteelle tallennettuja henkilökohtaisia tietoja, kuten nimeä ja yhteystietoja, tai lisätä niitä. Sovellus voi tunnistaa sinut ja lähettää profiilitietojasi muille."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"kehon anturit (kuten sykemittarit)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Antaa sovelluksen käyttää tietoja antureista, joita käytetään kehon toimintojen kuten sykkeen mittaamiseen."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"lue sosiaalista streamia"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Antaa sovelluksen käyttää ja synkronoida sinun tai kavereidesi päivityksiä sosiaalisista palveluista. Mieti tarkkaan ennen tietojen jakamista: tämän luvan saaneet sovellukset voivat lukea sinun ja kavereidesi välisiä viestejä sosiaalisissa verkkopalveluissa huolimatta viestien arkaluonteisuudesta. Huom: tätä lupaa ei saa ottaa käyttöön kaikissa sosiaalisissa verkkopalveluissa."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"kirjoita sosiaaliseen streamiin"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Antaa sovelluksen hallita laitteen puhelinominaisuuksia. Jos sovelluksella on tämä oikeus, se voi esimerkiksi vaihtaa verkkoa tai ottaa puhelinradion käyttöön tai poistaa sen käytöstä ilmoittamatta käyttäjälle."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"lue puhelimen tila ja identiteetti"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Antaa sovelluksen käyttää laitteen puhelinominaisuuksia. Sovellus voi määrittää puhelinnumeron ja laitteen tunnuksen, puhelun tilan sekä soitetun numeron."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"lue puhelimen tarkat tilat"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Antaa sovelluksen käyttää puhelimen tarkkoja tiloja. Tämän oikeus antaa sovelluksen määrittää puhelun todellisen tilan, eli onko puhelu aktiivinen vai taustalla, puhelujen epäonnistumiset, tietoliikenneyhteyden tarkan tilan ja tietoliikenneyhteyden muodostuksen epäonnistumiset."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"estä tablet-laitetta menemästä virransäästötilaan"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"estä puhelinta menemästä virransäästötilaan"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Antaa sovelluksen estää tablet-laitetta siirtymästä virransäästötilaan."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Vaihda WiMAX-verkon tilaa"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Antaa sovelluksen muodostaa tablet-laitteella yhteyden WiMAX-verkkoon ja katkaista yhteyden."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Antaa sovelluksen muodostaa puhelimella yhteyden WiMAX-verkkoon ja katkaista yhteyden."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"pisteytä verkot"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Sallii sovelluksen asettaa verkkoja paremmuusjärjestykseen ja vaikuttaa siihen, mikä verkko tablet-laitteen kannattaa valita."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Sallii sovelluksen asettaa verkkoja paremmuusjärjestykseen ja vaikuttaa siihen, mikä verkko puhelimen kannattaa valita."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"muodosta laitepari Bluetooth-laitteiden kanssa"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Antaa sovelluksen tarkastella tablet-laitteen Bluetooth-asetuksia sekä muodostaa ja hyväksyä laitepariyhteyksiä."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Antaa sovelluksen tarkastella puhelimen Bluetooth-asetuksia sekä muodostaa ja hyväksyä laitepariyhteyksiä muihin laitteisiin."</string>
@@ -703,18 +683,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"Palveluntarjoajan määrityssovelluksen käynnistäminen"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Antaa luvanhaltijan käynnistää palveluntarjoajan määrityssovelluksen. Ei tavallisten sovelluksien käyttöön."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"verkon tilahavaintojen kuunteleminen"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Antaa sovellukselle luvan kuunnella verkon tilahavaintoja. Ei tavallisten sovellusten käyttöön."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"Muuttaa syöttölaitteen kalibrointia."</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Antaa sovelluksen muokata kosketusnäytön kalibrointiparametreja. Ei tavallisten sovellusten käyttöön."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM-varmenteiden käyttö"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Antaa sovelluksen käyttää DRM-varmenteita ja hallita niiden käyttäjiä. 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="policylab_watchLogin" msgid="914130646942199503">"Tarkkaile ruudun lukituksen poistoyrityksiä"</string>
@@ -1216,8 +1188,8 @@
     <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>
+    <item quantity="one" msgid="6654123987418168693">"Wifi-verkko käytettävissä"</item>
+    <item quantity="other" msgid="4192424489168397386">"Wifi-verkkoja käytettävissä"</item>
   </plurals>
   <plurals name="wifi_available_detailed">
     <item quantity="one" msgid="1634101450343277345">"Avoin wifi-verkko käytettävissä"</item>
@@ -1227,10 +1199,10 @@
     <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" msgid="7904214231651546347">"Wifi-yhteyden muodostaminen epäonnistui"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" : huono internetyhteys."</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Suora wifi-yhteys"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käynnistä suora wifi-yhteys. Wi-Fi-asiakas/-hotspot poistetaan käytöstä."</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käynnistä suora wifi-yhteys. Wifi-asiakas/-hotspot poistetaan käytöstä."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Suoran wifi-yhteyden käynnistäminen epäonnistui."</string>
     <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct on käytössä"</string>
     <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tarkastele asetuksia koskettamalla"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Sallii sovelluksen käyttää salasanalla suojattua tallennustilaa."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Hallinnoi näppäinvahdin näyttämistä ja piilottamista"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Antaa sovelluksen hallita näppäinvahtia."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Seuraa luottamuksen tilamuutoksia."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Antaa sovelluksen seurata luottamuksen tilamuutoksia."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Luotettavaan tahoon sitoutuminen"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Antaa sovelluksen sitoutua luotettavaan tahoon."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Vuorovaikutus päivitys- ja palautusjärjestelmän kanssa"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Sallii sovelluksen vuorovaikutuksen palautusjärjestelmän ja järjestelmäpäivitysten kanssa."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Ohjaa zoomausta napauttamalla kahdesti"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Taustakuva"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Vaihda taustakuvaa"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Ilmoituskuuntelija"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN on aktivoitu"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> on aktivoinut VPN-yhteyden"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Voit hallinnoida verkkoa koskettamalla."</string>
@@ -1485,12 +1451,12 @@
     <string name="data_usage_3g_limit_title" msgid="7093334419518706686">"2G-3G-tiedonsiirto pois käytöstä"</string>
     <string name="data_usage_4g_limit_title" msgid="7636489436819470761">"4G-tiedonsiirto pois käytöstä"</string>
     <string name="data_usage_mobile_limit_title" msgid="7869402519391631884">"Mobiilitiedonsiirto pois käytöstä"</string>
-    <string name="data_usage_wifi_limit_title" msgid="8992154736441284865">"Wi-Fi-tiedonsiirto pois käytöstä"</string>
+    <string name="data_usage_wifi_limit_title" msgid="8992154736441284865">"Wifi-tiedonsiirto pois käytöstä"</string>
     <string name="data_usage_limit_body" msgid="3317964706973601386">"Ota käyttöön koskettamalla."</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"2G-3G-tiedonsiirtoraja ylitetty"</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4G-tiedonsiirtoraja ylitetty"</string>
     <string name="data_usage_mobile_limit_snoozed_title" msgid="279240572165412168">"Mobiilitiedonsiirtoraja ylitetty"</string>
-    <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Wi-Fi-tiedonsiirtoraja ylitetty"</string>
+    <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Wifi-tiedonsiirtoraja ylitetty"</string>
     <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> yli asetetun rajan"</string>
     <string name="data_usage_restricted_title" msgid="5965157361036321914">"Rajoitettu taustatietojen käyttö"</string>
     <string name="data_usage_restricted_body" msgid="6741521330997452990">"Poista rajoitus koskettamalla."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 17cda8d..fe29fb8 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchroniser"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Trop de contenus supprimés (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"La mémoire de la tablette est pleine. Supprimez des fichiers pour libérer de l\'espace."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"La mémoire de la montre est pleine. Supprimez des fichiers pour libérer de l\'espace."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"La mémoire du téléphone est pleine. Veuillez supprimer des fichiers pour libérer de l\'espace."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Le réseau peut être surveillé"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Par un tiers inconnu"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Sonnerie activée"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Arrêt en cours..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Votre tablette va s\'éteindre."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Votre montre va s\'éteindre."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Votre téléphone va s\'éteindre."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Voulez-vous éteindre l\'appareil?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Redémarrer en mode sans échec"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mode Avion"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"désinstaller des raccourcis"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Permet à l\'application de supprimer des raccourcis de la page d\'accueil sans intervention de l\'utilisateur."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"transférer les appels sortants"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Permet à l\'application de lire le numéro composé lors d\'un appel sortant et lui donne la possibilité de rediriger l\'appel vers un autre numéro ou d\'abandonner l\'appel."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Permet à l\'application de traiter les appels sortants et de modifier le numéro à composer. Cette autorisation lui permet de surveiller, rediriger ou empêcher les appels sortants."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"recevoir des messages texte"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Permet à l\'application de recevoir et de traiter les messages texte. Cette autorisation lui donne la possibilité de surveiller ou de supprimer les messages envoyés à votre appareil sans vous les montrer."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"recevoir des messages multimédias"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Permet à l\'application de récupérer le contenu de la fenêtre active. Des applications malveillantes peuvent exploiter cette fonctionnalité pour récupérer et lire la totalité du contenu de la fenêtre, à l\'exception des mots de passe."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"activer temporairement l\'accessibilité"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Permet à une application d\'activer temporairement l\'accessibilité sur l\'appareil. Des applications malveillantes peuvent activer l\'accessibilité sans le consentement de l\'utilisateur."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"récupérer les jetons de fenêtre"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Permet à une application de récupérer les jetons de fenêtre. Des applications malveillantes peuvent effectuer des interactions non autorisées avec la fenêtre de l\'application, se faisant passer pour le système."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"récupérer les statistiques de référence"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Permet à une application d\'obtenir des statistiques de référence. Des applications malveillantes peuvent observer les statistiques de référence de fenêtres dans d\'autres applications."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"récupérer les données sur les fenêtres"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Permet à une application de récupérer les données sur les fenêtres dans le gestionnaire de fenêtres. Des applications malveillantes peuvent récupérer des données destinées à un usage interne du système."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filtrer les événements"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Permet à une application d\'enregistrer un filtre d\'entrée pour filtrer le flux de tous les événements des utilisateurs avant qu\'ils ne soient traités. Des applications malveillantes peuvent contrôler l\'interface utilisateur du système sans l\'intervention de l\'utilisateur."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"agrandir l\'écran"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Permet à une application d\'agrandir le contenu à l\'écran. Les applications malveillantes peuvent transformer ce contenu et rendre l\'appareil inutilisable."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"arrêt partiel"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Place le gestionnaire d\'activités en état d\'arrêt, mais n\'effectue pas d\'arrêt complet."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"empêcher les changements d\'applications"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permet à l\'application d\'envoyer une notification indiquant la réception d\'un message texte. Des applications malveillantes peuvent utiliser cette fonctionnalité pour créer de faux messages entrants."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"envoyer une diffusion de réception de WAP par poussée"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permet à l\'application d\'envoyer une notification indiquant la réception d\'un message WAP par poussée. Des applications malveillantes peuvent utiliser cette fonctionnalité pour créer de faux messages multimédias entrants ou pour remplacer le contenu d\'une page Web par du contenu malveillant."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"diffuser le classement des réseaux"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Autorise l\'application à diffuser une notification signalant que les réseaux doivent être évalués. Cela n\'est jamais nécessaire pour les applications normales."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"restreindre le nombre de processus en cours d\'exécution"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permet à l\'application de définir le nombre maximal de processus devant s\'exécuter. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forcer la fermeture des applications en arrière-plan"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service RPV. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"se fixer à un fond d\'écran"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un fond d\'écran. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"lier à un écran distant"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un écran distant. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"s\'associer à un service de widget"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'une entrée de téléviseur. Les applications standards ne devraient pas avoir à utiliser cette fonctionnalité."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ajouter ou supprimer un administrateur de l\'appareil"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permet à l\'application d\'ajouter ou de supprimer des administrateurs actifs de l\'appareil. Les applications standards ne devraient jamais utiliser cette autorisation."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"modifier l\'orientation de l\'écran"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet à une application d\'utiliser n\'importe quel décodeur installé pour lire les fichiers multimédias."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gérer les certificats de confiance"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet à l\'application d\'installer et de désinstaller les certificats CA en tant que certificats de confiance."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"exécuter l\'application lorsque l\'appareil est inactif"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Cette autorisation permet au système Android d\'exécuter l\'application en arrière-plan lorsque l\'appareil est inactif."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"lier aux services inactifs"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Cette autorisation permet à la plateforme Android de se lier aux services inactifs d\'une application."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lire ou modifier les ressources appartenant au groupe de diagnostics"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet à l\'application d\'obtenir des droits en lecture et en écriture pour toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers du répertoire /dev). Cela peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou le fournisseur de services."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activer ou désactiver les composants d\'une application"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Permet à l\'application d\'accéder aux données de profil enregistrées sur votre appareil, comme votre nom et vos coordonnées. L\'application peut alors vous identifier et envoyer les données de votre profil à des tiers."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"modifier votre fiche de contact"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Permet à l\'application de modifier les données de profil enregistrées sur votre appareil, telles que votre nom et vos coordonnées, ou d\'en ajouter. Elle peut alors vous identifier et envoyer vos données de profil à des tiers."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"capteurs corporels (tels que les moniteurs de fréquence cardiaque)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Permet à l\'application d\'accéder aux données des capteurs utilisés pour mesurer des valeurs physiologiques, telles que votre fréquence cardiaque."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"lire les flux de réseaux sociaux"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Permet à l\'application d\'accéder à vos mises à jour sur les réseaux sociaux, ainsi qu\'à celles de vos amis, et de les synchroniser. Soyez prudent lorsque vous partagez de l\'information. Cette autorisation permet à l\'application de lire les communications entre vous et vos amis sur les réseaux sociaux, indépendamment de leur caractère confidentiel. Remarque : Il est possible que cette autorisation ne soit pas appliquée sur tous les réseaux sociaux."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"modifier vos flux de réseaux sociaux"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permet à l\'application de contrôler les fonctionnalités de téléphonie de l\'appareil. Une application disposant de cette autorisation peut, par exemple, basculer d\'un réseau à l\'autre et activer ou désactiver le signal radio du téléphone à votre insu."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"voir l\'état et l\'identité du téléphone"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permet à l\'application d\'accéder aux fonctionnalités téléphoniques de l\'appareil. Cette autorisation permet à l\'application de déterminer le numéro de téléphone et les identifiants de l\'appareil, si un appel est actif et le numéro distant connecté par un appel."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"Accéder aux états précis du téléphone"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permet à l\'application d\'accéder aux états précis du téléphone. Cette autorisation lui permet de déterminer le statut d\'appel réel, si un appel est actif ou en arrière-plan, si des appels ont échoué, l\'état précis de la connexion et si cette dernière a échoué."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"empêcher la tablette de passer en mode veille"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"empêcher le téléphone de passer en mode veille"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permet à l\'application d\'empêcher la tablette de passer en mode veille."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Modifier l\'état du WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permet à l\'application de connecter la tablette aux réseaux WiMAX et de l\'en déconnecter."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permet à l\'application de connecter le téléphone aux réseaux WiMAX et de l\'en déconnecter."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"classer les réseaux"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Autorise l\'application à classer les réseaux et à influencer la sélection du réseau par la tablette."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Autorise l\'application à classer les réseaux et à influencer la sélection du réseau par le téléphone."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"s\'associer à des appareils Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permet à l\'application d\'accéder à la configuration du Bluetooth sur la tablette, et d\'établir et accepter des connexions avec les appareils associés."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permet à l\'application d\'accéder à la configuration du Bluetooth sur le téléphone, et d\'établir et accepter des connexions avec les appareils associés."</string>
@@ -703,18 +683,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"faire appel à l\'application de configuration du fournisseur de services"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permet à l\'application autorisée de faire appel à l\'application de configuration fournie par le fournisseur de services. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"détecter des observations sur les conditions du réseau"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permet à une application de détecter les observations sur les conditions du réseau. Ne devrait jamais être nécessaire pour les applications standards."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"modifier le calibrage du périphérique d\'entrée"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permet à l\'application de modifier les paramètres de calibrage de l\'écran tactile. Ne devrait jamais être nécessaire pour les applications standards."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"accéder aux certificats GDN"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Permet à une application de fournir et d\'utiliser les certificats de GDN. Cela ne devrait jamais être nécessaire pour les applications normales."</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="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string>
@@ -1292,11 +1264,11 @@
     <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"Si vous activez la mémoire de stockage USB, certaines applications en cours d\'utilisation vont être fermées et risquent de rester indisponibles jusqu\'à ce que la mémoire de stockage USB soit désactivée."</string>
     <string name="dlg_error_title" msgid="7323658469626514207">"Échec du fonctionnement de la mémoire de stockage USB."</string>
     <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_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_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>
+    <string name="usb_notification_message" msgid="2290859399983720271">"Appuyez ici pour accéder aux autres options USB."</string>
     <string name="extmedia_format_title" product="nosdcard" msgid="9020092196061007262">"Formater mémoire?"</string>
     <string name="extmedia_format_title" product="default" msgid="3648415921526526069">"Formater la carte SD?"</string>
     <string name="extmedia_format_message" product="nosdcard" msgid="3934016853425761078">"Tous les fichiers stockés sur la mémoire de stockage USB vont être effacés. Cette action est irréversible."</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permet à une application d\'accéder au stockage sécurisé keyguard."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Contrôler l\'affichage et le masquage de la protection des touches"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permet à une application de contrôler la protection des touches."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Détecter les modifications de l\'état de confiance"</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permet à une application de détecter les modifications de l\'état de confiance."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Lier à un service d\'agent de confiance"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permet à une application de se lier à un service d\'agent de confiance."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interagir avec le système de récupération et de mise à jour"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Permet à une application d\'interagir avec le système de récupération et les mises à jour système."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Appuyer deux fois pour régler le zoom"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Fond d\'écran"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Changer de fond d\'écran"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Outil d\'écoute des notifications"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN activé"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN activé par <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Appuyez ici pour gérer le réseau."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 3c0266f..dae681d 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronisation"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Trop de contenus supprimés (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"La mémoire de la tablette est pleine. Supprimez des fichiers pour libérer de l\'espace."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"La mémoire de la montre est saturée. Veuillez supprimer des fichiers pour libérer de l\'espace."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"La mémoire du téléphone est pleine. Veuillez supprimer des fichiers pour libérer de l\'espace."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Il est possible que le réseau soit surveillé."</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Par un tiers inconnu"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Sonnerie activée"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Arrêt en cours..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Votre tablette va s\'éteindre."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"La montre va s\'éteindre."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Votre téléphone va s\'éteindre."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Voulez-vous éteindre l\'appareil ?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Redémarrer en mode sans échec"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mode Avion"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"désinstaller des raccourcis"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Permettre à l\'application de supprimer des raccourcis de l\'écran d\'accueil sans l\'intervention de l\'utilisateur"</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"transférer les appels sortants"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Permettre à l\'application de lire le numéro composé lors d\'un appel sortant, et lui donner la possibilité de rediriger l\'appel vers un autre numéro ou d\'abandonner l\'appel"</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Permet à l\'application de traiter les appels sortants et de modifier le numéro à composer. Cette autorisation lui permet de surveiller, rediriger ou empêcher les appels sortants."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"recevoir des messages texte (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Permet à l\'application de recevoir et de traiter les SMS. Cette autorisation lui donne la possibilité de surveiller ou supprimer les messages envoyés à votre appareil sans vous les montrer."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"recevoir des messages texte (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Permet à l\'application de récupérer le contenu de la fenêtre active. Des applications malveillantes peuvent exploiter cette fonctionnalité pour récupérer et lire la totalité du contenu de la fenêtre, à l\'exception des mots de passe."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"activer temporairement l\'accessibilité"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Permet à une application d\'activer temporairement l\'accessibilité sur l\'appareil. Des applications malveillantes peuvent activer l\'accessibilité sans le consentement de l\'utilisateur."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"récupérer les jetons de fenêtre"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Permettre à une application de récupérer les jetons de fenêtre. Des applications malveillantes peuvent interagir avec la fenêtre de l\'application sans votre autorisation en se faisant passer pour le système."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"récupérer des statistiques de référence"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Permettre à une application de collecter des statistiques de référence. Des applications malveillantes peuvent suivre les statistiques de référence de fenêtres dans d\'autres applications."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"récupérer les informations sur les fenêtres"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Permet à une application de récupérer les informations sur les fenêtres depuis le gestionnaire de fenêtres. Des applications malveillantes peuvent récupérer des informations destinées à un usage interne du système."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filtrer les événements"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Permet à une application d\'enregistrer un filtre d\'entrée pour filtrer le flux de tous les événements des utilisateurs avant qu\'ils ne soient traités. Des applications malveillantes peuvent contrôler l\'interface utilisateur du système sans l\'intervention de l\'utilisateur."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"agrandir l\'écran"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Permet à une application d\'agrandir le contenu à l\'écran. Les applications malveillantes peuvent transformer ce contenu et rendre l\'appareil inutilisable."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"arrêt partiel"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Place le gestionnaire d\'activités en état d\'arrêt. N\'effectue pas un arrêt complet."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"empêcher les changements d\'applications"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permet à l\'application d\'envoyer une notification indiquant la réception d\'un SMS. Des applications malveillantes peuvent exploiter cette fonctionnalité pour créer de faux SMS entrants."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"Envoi de diffusion de réception de WAP PUSH"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permet à l\'application d\'envoyer une notification indiquant la réception d\'un message WAP PUSH. Des applications malveillantes peuvent exploiter cette fonctionnalité pour créer de faux MMS entrants ou pour remplacer le contenu d\'une page Web par du contenu malveillant."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"diffuser des notifications pour l\'évaluation des réseaux"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Autoriser l\'application à diffuser une notification signalant que les réseaux doivent être évalués. Cette autorisation n\'est pas nécessaire pour les applications standards."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"Nombre maximal de processus en cours d\'exécution"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permet à l\'application de contrôler le nombre maximal de processus devant s\'exécuter. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forcer la fermeture des applications en arrière-plan"</string>
@@ -358,7 +353,7 @@
     <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Permet à l\'application de lancer l\'interface utilisateur de confirmation de sauvegarde complète. Seules certaines applications peuvent bénéficier de cette permission."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"Affichage de fenêtres non autorisées"</string>
     <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Permet à l\'application de créer des fenêtres destinées à être utilisées par l\'interface utilisateur du système interne. Les applications standards ne doivent pas utiliser cette fonctionnalité."</string>
-    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"Se superposer aux autres applis"</string>
+    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"S\'afficher en surimpression dans les autres applis"</string>
     <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Permet à l\'application d\'ignorer d\'autres applications ou certaines parties de l\'interface utilisateur. Cela peut altérer votre utilisation de l\'interface de n\'importe quelle application, ou modifier ce que vous pensez voir dans d\'autres applications."</string>
     <string name="permlab_setAnimationScale" msgid="2805103241153907174">"Réglage de la vitesse des animations"</string>
     <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Permet à l\'application de modifier à tout moment la vitesse générale des animations pour les ralentir ou les accélérer."</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service VPN. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"Se fixer sur un fond d\'écran"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un fond d\'écran. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"s\'associer à un écran à distance"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permettre à l\'application autorisée de s\'associer à l\'interface de niveau supérieur d\'un écran à distance. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"associer à un service widget"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Permettre à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'une entrée TV. Ne devrait pas être nécessaire pour les applications standards."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ajouter ou supprimer un administrateur de l\'appareil"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permet à l\'application autorisée d\'ajouter ou de supprimer des administrateurs actifs de l\'appareil. Les applications standards ne devraient pas nécessiter cette autorisation."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"Changement d\'orientation de l\'écran"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet à une application d\'utiliser n\'importe quel décodeur installé pour lire les fichiers multimédias."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gérer les certificats de confiance"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet à l\'application d\'installer et de désinstaller les certificats CA en tant que certificats de confiance."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"exécuter l\'application lorsque l\'appareil est inactif"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Cette autorisation permet au système Android d\'exécuter l\'application en arrière-plan lorsque l\'appareil est inactif."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"associer aux services d\'inactivité"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Cette autorisation permet à la plate-forme Android de se lier aux services inactifs d\'une application."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"Lecture/écriture dans les ressources appartenant aux diagnostics"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet à l\'application d\'obtenir des droits en lecture/écriture concernant toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers du répertoire /dev). Ceci peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou l\'opérateur."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activer ou désactiver les composants de l\'application"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Permet à l\'application d\'accéder aux informations de profil stockées sur votre appareil, telles que votre nom et vos coordonnées. L\'application peut alors vous identifier et envoyer vos informations de profil à des tiers."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"modifier votre fiche de contact"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Permet à l\'application de modifier les informations de profil stockées sur votre appareil, telles que votre nom et vos coordonnées, ou d\'en ajouter. Elle peut alors vous identifier et envoyer vos informations de profil à des tiers."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"capteurs corporels (tels que les cardiofréquencemètres)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Permet à l\'application d\'accéder aux données des capteurs utilisés pour mesurer des valeurs physiologiques, telles que votre fréquence cardiaque."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"lire votre flux de réseau social"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Permet à l\'application d\'accéder à vos mises à jour sur les réseaux sociaux, ainsi qu\'à celles de vos amis, et de les synchroniser. Soyez prudent lorsque vous partagez des informations. Cette autorisation permet à l\'application de lire les communications entre vous et vos amis sur les réseaux sociaux, indépendamment de leur caractère confidentiel. Remarque : il est possible que cette autorisation ne soit pas appliquée sur tous les réseaux sociaux."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"écrire sur votre flux social"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permet à l\'application de contrôler les fonctionnalités de téléphonie de l\'appareil. Une application disposant de cette autorisation peut, par exemple, basculer d\'un réseau à l\'autre et activer ou désactiver le signal radio du téléphone à votre insu."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"voir l\'état et l\'identité du téléphone"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permet à l\'application d\'accéder aux fonctionnalités téléphoniques de l\'appareil. Cette autorisation permet à l\'application de déterminer le numéro de téléphone et les identifiants de l\'appareil, si un appel est actif et le numéro distant connecté par un appel."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"Accéder aux états précis du téléphone"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permet à l\'application d\'accéder aux états précis du téléphone. Cette autorisation lui permet de déterminer le statut d\'appel réel, si un appel est actif ou en arrière-plan, si des appels ont échoué, l\'état précis de la connexion et si cette dernière a échoué."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"empêcher la tablette de passer en mode veille"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"empêcher le téléphone de passer en mode veille"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permet à l\'application d\'empêcher la tablette de passer en mode veille."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Modifier l\'état du WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permet à l\'application de connecter la tablette aux réseaux WiMAX et de l\'en déconnecter."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permet à l\'application de connecter le téléphone aux réseaux WiMAX et de l\'en déconnecter."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"évaluer les réseaux"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Autoriser l\'application à classer les réseaux et à influencer la sélection du réseau sur la tablette"</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Autoriser l\'application à classer les réseaux et à influencer la sélection du réseau sur le téléphone"</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"associer à des appareils Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permet à l\'application d\'accéder à la configuration du Bluetooth sur la tablette, et d\'établir et accepter des connexions avec les appareils associés."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permet à l\'application d\'accéder à la configuration du Bluetooth sur le téléphone, et d\'établir et accepter des connexions avec les appareils associés."</string>
@@ -703,18 +683,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"faire appel à l\'application de configuration fournie par l\'opérateur"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permet à l\'application autorisée de faire appel à l\'application de configuration fournie par l\'opérateur. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"détecter des observations sur les conditions du réseau"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permet à une application de détecter des observations sur les conditions du réseau. Les applications standards ne devraient pas nécessiter cette autorisation."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"modifier le calibrage du périphérique d\'entrée"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permettre à l\'application de modifier les paramètres de calibrage de l\'écran tactile. Ne devrait jamais être nécessaire pour les applications standards."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"accéder aux certificats de GDN"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Permettre à une application de fournir et d\'utiliser des certificats de GDN. 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="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string>
@@ -743,7 +715,7 @@
     <item msgid="7897544654242874543">"Bureau"</item>
     <item msgid="1103601433382158155">"Télécopie bureau"</item>
     <item msgid="1735177144948329370">"Télécopie domicile"</item>
-    <item msgid="603878674477207394">"Bipeur"</item>
+    <item msgid="603878674477207394">"Pager"</item>
     <item msgid="1650824275177931637">"Autre"</item>
     <item msgid="9192514806975898961">"Personnalisé"</item>
   </string-array>
@@ -786,7 +758,7 @@
     <string name="phoneTypeWork" msgid="8863939667059911633">"Bureau"</string>
     <string name="phoneTypeFaxWork" msgid="3517792160008890912">"Télécopie bureau"</string>
     <string name="phoneTypeFaxHome" msgid="2067265972322971467">"Télécopie domicile"</string>
-    <string name="phoneTypePager" msgid="7582359955394921732">"Bipeur"</string>
+    <string name="phoneTypePager" msgid="7582359955394921732">"Pager"</string>
     <string name="phoneTypeOther" msgid="1544425847868765990">"Autre"</string>
     <string name="phoneTypeCallback" msgid="2712175203065678206">"Rappel"</string>
     <string name="phoneTypeCar" msgid="8738360689616716982">"Voiture"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permet à une application d\'accéder au stockage sécurisé keyguard."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Contrôler l\'affichage et le masquage de la protection des touches"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permet à une application de contrôler la protection des touches."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Détecter les modifications de l\'état de confiance"</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permettre à une application de détecter les modifications de l\'état de confiance."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"S\'associer à un service d\'agent de confiance"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permettre à une application de s\'associer à un service d\'agent de confiance."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interagir avec le système de récupération et de mise à jour"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Permet à une application d\'interagir avec le système de récupération et les mises à jour du système."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Appuyez deux fois pour régler le zoom."</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Fond d\'écran"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Changer de fond d\'écran"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Outil d\'écoute des notifications"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN activé"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN activé par <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Appuyez ici pour gérer le réseau."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 1638b6b..c240cb2 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"समन्वयन"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"बहुत से <xliff:g id="CONTENT_TYPE">%s</xliff:g> हटाए जाते हैं."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"टेबलेट संग्रहण भर गया है. स्‍थान रिक्त करने के लिए कुछ फ़ाइलें हटाएं."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"घड़ी संग्रहण भर गया है. स्‍थान रिक्त करने के लिए कुछ फ़ाइलें हटाएं."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"फ़ोन संग्रहण भर गया है. स्‍थान रिक्त करने के लिए कुछ फ़ाइलें हटाएं."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"नेटवर्क को मॉनिटर किया जा सकता है"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"किसी अज्ञात तृतीय पक्ष के द्वारा"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"रिंगर चालू"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"शट डाउन हो रहा है..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"आपकी टेबलेट शट डाउन हो जाएगी."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"आपकी घड़ी बंद हो जाएगी."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"आपका फ़ोन शट डाउन हो जाएगा."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"क्‍या आप शट डाउन करना चाहते हैं?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"सुरक्षित मोड में रीबूट करें"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"हवाई जहाज मोड"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android सिस्‍टम"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"शॉर्टकट अनइंस्टॉल करें"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"एप्‍लिकेशन को उपयोगकर्ता के हस्‍तक्षेप के बिना होमस्‍क्रीन शॉर्टकट निकालने की अनुमति देता है."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"आउटगोइंग कॉल को कहीं और भेजें"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"ऐप्स को किसी कॉल को भिन्न नंबर पर रिडायरेक्ट करने या पूरी तरह से कॉल निरस्त करने के विकल्प के साथ आउटगोइंग कॉल के दौरान डायल किए जा रहे नंबर को देखने की अनुमति देती है."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"ऐप्स को आउटगोइंग कॉल संसाधित करने और डायल किए जाने वाला नंबर बदलने देता है. यह अनुमति ऐप्स को आउटगोइंग कॉल की निगरानी करने, रीडायरेक्‍ट करने, या उन्‍हें रोकने देती है."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"पाठ संदेश (SMS) प्राप्त करें"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"ऐप्स  को SMS संदेशों को प्राप्‍त और संसाधित करने देता है. इसका अर्थ है कि ऐप्स  आपके उपकरण पर भेजे गए संदेशों की निगरानी आपको दिखाए बिना कर सकता है और उन्‍हें हटा सकता है."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"पाठ संदेश (MMS) प्राप्त करें"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"ऐप्स को सक्रिय विंडो की सामग्री पुनर्प्राप्त करने देता है. दुर्भावनापूर्ण ऐप्स विंडो की संपूर्ण सामग्री प्राप्त कर सकते हैं और पासवर्ड को छोड़कर इसके सभी पाठ जांच सकते हैं."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"आसान तरीका को अस्थायी रूप से सक्षम करें"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"ऐप्स  को उपकरण पर आसान तरीका को अस्थायी रूप से सक्षम करने देता है. दुर्भावनापूर्ण ऐप्स  उपयोगकर्ता की सहमति के बिना आसान तरीका को सक्षम कर सकते हैं."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"विंडो टोकन प्राप्त करें"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"एप्लिकेशन को विंडो टोकन प्राप्त करने देती है. दुर्भावनापूर्ण ऐप्स सिस्टम का प्रतिरूपण करने वाली एप्लिकेशन विंडो से अनधिकृत इंटरैक्शन कर सकते हैं."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"फ़्रेम के आंकड़े प्राप्त करें"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"एप्लिकेशन को फ़्रेम के आंकड़े एकत्र करने देती है. दुर्भावनापूर्ण ऐप्स अन्य ऐप्स से विंडो के फ़्रेम के आंकड़ों को देख सकते हैं."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"विंडो जानकारी प्राप्त करें"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"ऐप्स को विंडो प्रबंधक से windows के बारे में जानकारी प्राप्त करने देता है. दुर्भावनापूर्ण ऐप्स आंतरिक सिस्टम उपयोग के लिए अभिप्रेत जानकारी को प्राप्त कर सकते हैं."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"ईवेंट फ़िल्टर करें"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"ऐप्स को इनपुट फ़िल्‍टर पंजीकृत करने देता है, जो सभी उपयोगकर्ता ईवेंट के स्‍ट्रीम को भेजे जाने से पहले फ़िल्‍टर करता है. दुर्भावनापूर्ण ऐप्स उपयोगकर्ता के हस्‍तक्षेप के बिना सिस्‍टम UI को नियंत्रित कर सकता है."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"डिस्प्ले को आवर्धित करें"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"ऐप्स  को डिस्प्ले की सामग्री आवर्धित करने देता है. दुर्भावनापूर्ण ऐप्स  डिस्प्ले सामग्री को इस तरह से बदल सकते हैं कि उपकरण अनुपयोगी रेंडर होता है."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"आंशिक शटडाउन"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"गतिविधि प्रबंधक को शटडाउन स्‍थिति में रखता है. पूर्ण शटडाउन निष्‍पादित नहीं करता है."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"ऐप्स स्‍विच करने से रोकता है"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"ऐप्स  को वह सूचना प्रसारित करने देता है जो SMS संदेश ने प्राप्त की है. दुर्भावनापूर्ण ऐप्स  इसका उपयोग नकली इनकमिंग संदेश गढ़ने के लिए कर सकते हैं."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH-प्राप्त प्रसारण भेजें"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"ऐप्स  को वह सूचना प्रसारित करने देता है जो WAP PUSH संदेश को प्राप्त हुआ है. दुर्भावनापूर्ण ऐप्स  इसका उपयोग नकली MMS संदेश प्राप्त करने या किसी वेबपृष्ठ की सामग्री को दुर्भावनापूर्ण दूसरे रूप से चुपचाप प्रतिस्थापित करने के लिए कर सकते हैं."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"स्कोर नेटवर्क प्रसारण भेजें"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"ऐप्स को यह सूचना प्रसारित करने देती है कि नेटवर्क को स्कोर किए जाने की आवश्यकता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"चल रही प्रक्रियाओं की संख्‍या सीमित करें"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"ऐप्स  को चलाई जाने वाली अधिकतम प्रक्रियाओं को नियंत्रित करने देता है. सामान्य ऐप्स  के लिए कभी आवश्यक नहीं होती."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"पृष्ठभूमि ऐप्स को बलपूर्वक बंद करें"</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"धारक को किसी Vpn सेवा के शीर्ष-स्‍तर इंटरफ़ेस से आबद्ध होने देता है. सामान्‍य ऐप्स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"वॉलपेपर से आबद्ध करें"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"धारक को किसी वॉलपेपर के शीर्ष-स्‍तर इंटरफ़ेस से आबद्ध होने देता है. सामान्‍य ऐप्स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"रिमोट डिस्प्ले से आबद्ध करें"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ऐप्स  को प्लेबैक डीकोड करने के लिए किसी भी इंस्टॉल किए गए डीकोडर का उपयोग करने देता है."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"विश्वसनीय क्रेडेंशियल प्रबंधित करें"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"ऐप्स  को CA प्रमाणपत्रों को विश्वसनीय क्रेडेंशियल के रूप में इंस्टॉल और अनइंस्टॉल करने दें"</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"निष्क्रिय समय के दौरान एप्लिकेशन चलाएं"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"यह अनुमति Android सिस्टम को उपकरण के उपयोग में नहीं रहने पर एप्लिकेशन को पृष्ठभूमि में चलाने देती है."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"निष्क्रिय सेवाओं से आबद्ध करें"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"यह अनुमति Android सिस्टम को किसी एप्लिकेशन की निष्क्रिय सेवाओं से आबद्ध होने देती है."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"निदान के स्‍वामित्‍व वाले संसाधनों को पढ़ें/लिखें"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"ऐप्स को diag समूह के स्‍वामित्‍व वाले किसी संसाधन को पढ़ने और उसमें लिखने देता है; उदाहरण के लिए, /dev की फ़ाइलें. यह सिस्‍टम की स्‍थिरता और सुरक्षा को संभावित रूप से प्रभावित कर सकता है. इसका उपयोग निर्माता या ऑपरेटर द्वारा केवल हार्डवेयर-विशिष्ट निदान के लिए किया जाना चाहिए."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"ऐप्स घटकों को सक्षम या अक्षम करें"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"ऐप्स  को आपके उपकरण में संग्रहीत व्यक्तिगत प्रोफ़ाइल जानकारी, जैसे आपका नाम और संपर्क जानकारी, पढ़ने देता है. इसका अर्थ है कि ऐप्स  आपको पहचान सकता है और आपकी प्रोफ़ाइल जानकारी अन्य लोगों को भेज सकता है."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"स्‍वयं का संपर्क कार्ड बदलें"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"ऐप्स  को आपके उपकरण में संग्रहीत निजी प्रोफ़ाइल जानकारी, जैसे आपका नाम और संपर्क जानकारी को बदलने या उसमें कुछ जोड़ने देता है. इसका अर्थ है कि ऐप्स  आपको पहचान सकता है और आपकी प्रोफ़ाइल जानकारी अन्य लोगों को भेज सकता है."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"बॉडी सेंसर (जैसे हृदय गति मॉनीटर)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"एप्लिकेशन को ऐसे सेंसर का डेटा एक्सेस करने देती है जिनका उपयोग आप यह मापने के लिए करते हैं कि आपके शरीर के भीतर क्या चल रहा है, जैसे हृदय गति."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"अपनी सामाजिक स्‍ट्रीम पढ़ें"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"एप को आपके और आपके मित्रों की नई सामाजिक जानकारी तक पहुंचने और उन्हें समन्‍वयित करने देता है. जानकारी साझा करते समय सावधान रहें - इससे गोपनीयता पर ध्यान दिए बिना, एप सामाजिक नेटवर्क पर आपके और आपके मित्रों के बीच संचारों को पढ़ सकता है. ध्‍यान दें: यह अनुमति सभी सामाजिक नेटवर्क पर लागू नहीं की जा सकती."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"सामाजिक स्‍ट्रीम में लिखें"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"ऐप्स को उपकरण की फ़ोन सुविधाएं नियंत्रित करने देता है. इस अनुमति वाला कोई ऐप्स आपको सूचित किए बिना नेटवर्क स्‍विच कर सकता है, फ़ोन का रेडियो चालू और बंद कर सकता है और ऐसे ही अन्य कार्य कर सकता है."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"फ़ोन की स्‍थिति और पहचान पढ़ें"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"ऐप्स  को उपकरण की फ़ोन सुविधाओं तक पहुंचने देता है. यह अनुमति ऐप्स  को फ़ोन नंबर और उपकरण आईडी, कॉल सक्रिय है या नहीं, और कॉल द्वारा कनेक्ट किया गया दूरस्‍थ नंबर निर्धारित करने देती है."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"सटीक फ़ोन स्थितियों को पढ़ना"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"ऐप्स को सटीक फ़ोन स्थितियों की एक्सेस देती है. यह अनुमति ऐप्स को कॉल की वास्तविक स्थिति, चाहे वह कॉल सक्रिय हो या पृष्ठभूमि में हो, कॉल विफलताओं, सटीक डेटा कनेक्शन की स्थिति और डेटा कनेक्शन विफलताओं का पता लगाने देती है."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"टेबलेट को निष्‍क्रिय होने से रोकें"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"फ़ोन को निष्‍क्रिय होने से रोकें"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"ऐप्स  को टेबलेट को प्रयोग में नहीं हो जाने से रोकता है."</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX स्‍थिति बदलें"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"ऐप्स को WiMAX नेटवर्क से टेबलेट को कनेक्‍ट और डिस्‍कनेक्‍ट करने देता है."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"ऐप्स को WiMAX नेटवर्क से फ़ोन को कनेक्‍ट और डिस्‍कनेक्‍ट करने देता है."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"स्कोर नेटवर्क"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"ऐप्स को नेटवर्क को रैंक करने देती है और इस बात पर ज़ोर देती है कि टेबलेट को किस नेटवर्क को प्राथमिकता देनी चाहिए."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"ऐप्स को नेटवर्क को रैंक करने देती है और इस बात पर ज़ोर देती है कि फ़ोन को किस नेटवर्क को प्राथमिकता देनी चाहिए."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"Bluetooth उपकरणों के साथ युग्मित करें"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"ऐप्स को टेबलेट पर Bluetooth का कॉन्‍फ़िगरेशन देखने, और युग्‍मित उपकरणों के साथ कनेक्‍शन बनाने और स्‍वीकार करने देता है."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"ऐप्स को फ़ोन पर Bluetooth का कॉन्‍फ़िगरेशन देखने, और युग्‍मित उपकरणों के साथ कनेक्‍शन बनाने और स्‍वीकार करने देता है."</string>
@@ -663,9 +645,9 @@
     <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"ऐप्स  को किसी खाते की समन्वयन सेटिंग संशोधित करने देता है. उदाहरण के लिए, इसका उपयोग लोग ऐप्स  का समन्‍वयन किसी खाते से सक्षम करने में हो सकता है."</string>
     <string name="permlab_readSyncStats" msgid="7396577451360202448">"समन्वयन आंकड़े पढ़ें"</string>
     <string name="permdesc_readSyncStats" msgid="1510143761757606156">"ऐप्स  को किसी खाते के समन्वयन आंकड़े, साथ ही समन्‍वयित ईवेंट का इतिहास और समन्‍वयित डेटा की मात्रा पढ़ने देता है."</string>
-    <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"सदस्यता-प्राप्त फ़ीड पढ़ें"</string>
+    <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ग्राहकी-प्राप्त फ़ीड पढ़ें"</string>
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"ऐप्स को वर्तमान में समन्वयित फ़ीड के बारे में विवरण प्राप्त करने देता है."</string>
-    <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"सदस्यता-प्राप्त फ़ीड लिखें"</string>
+    <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"ग्राहकी-प्राप्त फ़ीड लिखें"</string>
     <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"ऐप्स  को आपके वर्तमान समन्वयित फ़ीड को संशोधित करने देता है. दुर्भावनापूर्ण ऐप्स  आपके समन्वयित फ़ीड को बदल सकते है."</string>
     <string name="permlab_readDictionary" msgid="4107101525746035718">"शब्दकोश में आपके द्वारा जोड़े गए शब्‍दों को पढ़ें"</string>
     <string name="permdesc_readDictionary" msgid="659614600338904243">"ऐप्स को ऐसे सभी शब्‍दों, नामों और वाक्यांशों को पढ़ने देता है जो संभवत: उपयोगकर्ता द्वारा उपयोगकर्ता ‍शब्दकोश में संग्रहीत किए गए हों."</string>
@@ -703,18 +685,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"ऐप्स  को सूचनाओं को प्राप्त करने, जांच करने, और साफ़ करने देता है, जिनमें अन्य ऐप्स  के द्वारा पोस्ट की गई सूचनाएं भी शामिल हैं."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"सूचना श्रवणकर्ता सेवा से जुड़ें"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"धारक को सूचना श्रवणकर्ता सेवा के शीर्ष स्तरीय इंटरफ़ेस से जुड़ने देती है. सामान्य ऐप्स  के लिए कभी भी आवश्यक नहीं होनी चाहिए."</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन ऐप्स  प्रारंभ करें"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"धारक को वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन ऐप्स  प्रारंभ करने देता है. सामान्‍य ऐप्स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"नेटवर्क स्थितियों के अवलोकनों को सुनें"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"ऐप्स  को नेटवर्क स्थितियों के अवलोकनों को सुनने देता है. सामान्य ऐप्स  के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"इनपुट उपकरण कैलिब्रेशन बदलें"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"ऐप्स को टच स्क्रीन के कैलिब्रेशन पैरामीटर को बदलने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM प्रमाणपत्र एक्सेस करें"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"एप्लिकेशन को DRM प्रमाणपत्रों का प्रावधान और उपयोग करने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यकता नहीं होना चाहिए."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियम सेट करें"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"स्‍क्रीन-अनलॉक पासवर्ड में अनुमति प्राप्त लंबाई और वर्णों को नियंत्रित करें."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"स्‍क्रीन-अनलॉक के प्रयासों पर निगरानी रखें"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"ऐप्स  को कीगार्ड सुरक्षित संग्रहण एक्सेस करने देती है."</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>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ट्रस्ट एजेंट सेवा से आबद्ध करना"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"किसी एप्लिकेशन को ट्रस्ट एजेंट सेवा से आबद्ध करने की अनुमति देती है."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"अपडेट और पुनर्प्राप्ति सिस्टम के साथ सहभागिता करें"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"एप्लिकेशन को पुनर्प्राप्ति सिस्टम और सिस्टम अपडेट के साथ सहभागिता करने देती है."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"ज़ूम नियंत्रण के लिए दो बार स्पर्श करें"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"वॉलपेपर"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"वॉलपेपर बदलें"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"सूचना श्रवणकर्ता"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN सक्रिय"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN को <xliff:g id="APP">%s</xliff:g> द्वारा सक्रिय किया गया है"</string>
     <string name="vpn_text" msgid="3011306607126450322">"नेटवर्क प्रबंधित करने के लिए स्‍पर्श करें."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 6e44150..cfd6974 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinkronizacija"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Previše brisanja stavki <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Prostor za pohranu tabletnog računala pun je. Izbrišite nekoliko datoteka kako biste oslobodili prostor."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Memorija sata je puna. Izbrišite neke datoteke da biste oslobodili prostor."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Prostor za pohranu na telefonu je pun. Izbrišite nekoliko datoteka kako biste oslobodili prostor."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mreža se možda nadzire"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Od strane nepoznate treće strane"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Zvono uključeno"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Isključivanje..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Vaš tabletni uređaj će se isključiti."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Sat će se isključiti."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Vaš će se telefon isključiti."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Želite li isključiti uređaj?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Ponovno pokretanje u sigurnom načinu rada"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Način rada u zrakoplovu"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sustav Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"deinstaliranje prečaca"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Aplikaciji omogućuje uklanjanje prečaca početnog zaslona bez intervencije korisnika."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"preusmjeravanje odlaznih poziva"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Omogućuje aplikaciji da vidi broj koji se bira prilikom odlaznog poziva uz opciju preusmjeravanja poziva na neki drugi broj ili prekidanja poziva."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Aplikaciji omogućuje obradu odlaznih poziva i promjenu broja za biranje. Ta dozvola aplikaciji omogućuje nadziranje, preusmjeravanje ili sprječavanje odlaznih poziva."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"primanje tekstnih poruka (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Aplikaciji omogućuje primanje i obradu SMS poruka. To znači da aplikacija može nadzirati ili izbrisati poruke poslane na vaš uređaj, a da vam ih ne prikaže."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"primanje tekstnih poruka (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Omogućuje aplikaciji dohvaćanje sadržaja aktivnog prozora. Zlonamjerne aplikacije mogu dohvatiti sav sadržaj prozora i pregledati sav njegov tekst osim zaporki."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"privremeno omogući dostupnost"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Aplikacija može privremeno omogućiti dostupnost na uređaju. Zlonamjerne aplikacije mogu omogućiti dostupnost bez korisnikova odobrenja."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"učitavanje prozora tokena"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Omogućuje aplikaciji učitavanje tokena prozora. Zlonamjerne aplikacije mogu stupati u neovlaštenu interakciju s prozorom aplikacije lažno se predstavljajući kao sustav."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"učitavanje statističkih pokazatelja okvira"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Omogućuje aplikaciji prikupljanje statističkih podataka okvira. Zlonamjerne aplikacije mogu pratiti statističke podatke okvira prozora iz drugih aplikacija."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"dohvaćanje informacija o prozoru"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Aplikaciji omogućuje dohvaćanje informacija o prozorima iz upravitelja prozora. Zlonamjerne aplikacije mogu dohvaćati informacije koje su namijenjene za internu uporabu sustava."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filtriranje događaja"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Aplikaciji omogućuje registraciju ulaznog filtra koji filtrira strujanje svih korisničkih događaja prije otpreme. Zlonamjerne aplikacije mogu kontrolirati korisničko sučelje sustava bez znanja korisnika."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"uvećaj prikaz"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Omogućuje aplikaciji uvećavanje sadržaja zaslona. Zlonamjerne aplikacije mogu izmijeniti sadržaj zaslona tako da uređaj postane neupotrebljiv."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"djelomično isključivanje"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Postavlja upravitelja za aktivnost u stanje mirovanja. Ne isključuje ga u potpunosti."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"sprečavanje promjene aplikacije"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Omogućuje aplikaciji emitiranje obavijesti da je primljena SMS poruka. Zlonamjerne aplikacije mogu to upotrijebiti za krivotvorenje dolaznih SMS poruka."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"slanje WAP-PUSH-primljenih prijenosa"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Omogućuje aplikaciji emitiranje obavijesti da je primljena WAP PUSH poruka. Zlonamjerne aplikacije mogu to upotrijebiti da bi krivotvorile prijem MMS poruka ili da bi potajno zamijenile sadržaj bilo koje web-stranice zlonamjernim varijantama."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"slanje obavijesti za ocjenjivanje mreža"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Aplikaciji omogućuje emitiranje obavijesti da se mreža treba ocijeniti. Nije potrebno za normalne aplikacije."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"ograničavanje broja pokrenutih postupaka"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Omogućuje aplikaciji upravljanje maksimalnim brojem postupaka koji će biti pokrenuti. Nikada nije potrebno za uobičajene aplikacije."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"prisilno zatvaranje pozadinskih aplikacija"</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Nositelju omogućuje vezanje uz sučelje najviše razine VPN usluge. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"povezano s pozadinskom slikom"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Nositelju omogućuje povezivanje sa sučeljem pozadinske slike najviše razine. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"vezanje uz udaljeni zaslon"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Nositelju omogućuje vezanje uza sučelje najviše razine udaljenog zaslona. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vezanje na uslugu widgeta"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Aplikaciji omogućuje korištenje bilo kojim instaliranim dekoderom medija za dekodiranje radi reprodukcije."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"upravljanje pouzdanim vjerodajnicama"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Omogućuje aplikaciji instaliranje i deinstaliranje CA certifikata kao pouzdanih vjerodajnica."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"izvodi aplikaciju tijekom mirovanja"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"To dopuštenje omogućuje sustavu Android da izvodi aplikaciju u pozadini dok se uređaj ne upotrebljava."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"veži uz usluge u mirovanju"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"To dopuštenje omogućuje sustavu Android da se veže uz aplikacijine usluge u mirovanju."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"pisanje/čitanje u resursima čije je vlasnik dijagnostika"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Aplikaciji omogućuje čitanje i pisanje na bilo koji resurs u vlasništvu dijag. grupe; na primjer, datoteke u sustavu /dev. To bi moglo utjecati na stabilnost sustava i sigurnost. Dozvolu bi trebao upotrebljavati proizvođač ili operater SAMO za dijagnostiku koja se odnosi na hardver."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"omogućavanje ili onemogućavanje komponenti aplikacije"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Aplikaciji omogućuje čitanje osobnih podataka profila pohranjenih na uređaju, kao što su vaše ime ili kontaktni podaci. To znači da vas aplikacija može identificirati i slati informacije s vašeg profila drugima."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"izmjena vaše kontaktne kartice"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Aplikaciji omogućuje promjenu ili dodavanje osobnih podataka profila pohranjenih na uređaju, kao što su vaše ime i kontaktni podaci. To znači da vas aplikacija može identificirati i slati informacije s vašeg profila drugima."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"senzori tjelesnih funkcija (npr. monitori otkucaja srca)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Aplikaciji omogućuje pristup podacima iz senzora koje upotrebljavate za mjerenje onoga što se odvija u vašem tijelu, poput otkucaja srca."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"čitanje društvenog streama"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Aplikaciji omogućuje pristup vašim ažuriranjima na društvenim mrežama i ažuriranjima vaših prijatelja, kao i sinkronizaciju tih ažuriranja. Budite oprezni kad dijelite informacije – to aplikaciji omogućuje čitanje poruka između vas i vaših prijatelja na društvenim mrežama, neovisno o povjerljivosti. Napomena: ta se dozvola možda ne primjenjuje na svim društvenim mrežama."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"pisanje društvenog streama"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Omogućuje aplikaciji upravljanje telefonskim značajkama uređaja. Aplikacija s tom dozvolom može izmjenjivati mreže, uključiti i isključiti radiouređaj telefona i tome slično, a da vas o tome uopće ne obavijesti."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"čitanje statusa i identiteta telefona"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Aplikaciji omogućuje pristup telefonskim značajkama uređaja. Ta dozvola aplikaciji omogućuje utvrđivanje telefonskog broja i ID-ova uređaja, je li poziv aktivan te udaljeni broj koji je povezan pozivom."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"čitaj precizna stanja telefona"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Omogućuje aplikaciji pristup preciznim stanjima telefona. To dopuštenje omogućuje aplikaciji da odredi stvarni status poziva, je li poziv aktivan ili u pozadini, neuspjele pozive, precizne podatke o statusu veze te neuspjela uspostavljanja podatkovnih veza."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"spriječi mirovanje tabletnog uređaja"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"sprečava telefon da prijeđe u stanje mirovanja"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Aplikaciji omogućuje sprječavanje prelaska tabletnog računala u mirovanje."</string>
@@ -647,13 +632,10 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Promjena stanja WiMAX mreže"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Aplikaciji omogućuje povezivanje tabletnog računala s WiMAX mrežama i prekidanje veze tabletnog računala s njima."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Aplikaciji omogućuje povezivanje telefona s WiMAX mrežama i prekidanje veze telefona s njima."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ocjenjivanje mreža"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Aplikaciji omogućuje rangiranje mreža i utjecanje na odabir preferiranih mreža na tabletu."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Aplikaciji omogućuje rangiranje mreža i utjecanje na odabir preferiranih mreža na telefonu."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"uparivanje s Bluetooth uređajima"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Aplikaciji omogućuje pregled konfiguracije Bluetootha na tabletnom računalu te uspostavljanje i prihvaćanje veza s uparenim uređajima."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Aplikaciji omogućuje pregled konfiguracije Bluetootha na telefonu te uspostavljanje i prihvaćanje veza s uparenim uređajima."</string>
-    <string name="permlab_nfc" msgid="4423351274757876953">"upravljanje beskontaktnom komunikacijom (NFC)"</string>
+    <string name="permlab_nfc" msgid="4423351274757876953">"upravljaj beskontaktnom (NFC) komunikacijom"</string>
     <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>
@@ -675,7 +657,7 @@
     <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"čitanje sadržaja SD kartice"</string>
     <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Aplikaciji omogućuje čitanje sadržaja vaše USB pohrane."</string>
     <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Aplikaciji omogućuje čitanje sadržaja vaše SD kartice."</string>
-    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"izmjena/brisanje sadržaja USB-a"</string>
+    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"izmjena/brisanje sadrž. USB-a"</string>
     <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"izmjena ili brisanje sadržaja SD kartice"</string>
     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Dopušta pisanje u USB pohranu."</string>
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Aplikaciji omogućuje pisanje na SD karticu."</string>
@@ -703,18 +685,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"pozovi operaterovu aplikaciju za konfiguraciju"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Dopušta nositelju pozivanje operaterove aplikacije za konfiguraciju. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"praćenje motrenja mrežnih uvjeta"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Omogućuje aplikaciji praćenje motrenja mrežnih uvjeta. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"promjena kalibracije uređaja za unos"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Omogućuje aplikaciji izmjenu parametara kalibracije dodirnog zaslona. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"pristup DRM certifikatima"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Aplikaciji omogućuje pružanje i korištenje DRM certifikata. 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="policylab_watchLogin" msgid="914130646942199503">"Nadgledaj pokušaje otključavanja zaslona"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Omogućuje aplikaciji pristupanje zaključanoj sigurnoj pohrani."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Upravljanje prikazivanjem i skrivanjem zaključavanja tipkovnice"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Omogućuje aplikaciji upravljanje zaključavanjem tipkovnice."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Prati promjene pouzdanog stanja."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Omogućuje aplikaciji praćenje promjena pouzdanog stanja."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Povezivanje s uslugom pouzdanog predstavnika"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Omogućuje aplikaciji povezivanje s uslugom pouzdanog predstavnika."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interakcija s ažuriranjem i sustavom za oporavak"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Omogućuje aplikaciji interakciju sa sustavom za oporavak i ažuriranjima sustava."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Dodirnite dvaput za upravljanje zumiranjem"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Pozadinska slika"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Promjena pozadinske slike"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Slušatelj obavijesti"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN aktiviran"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Aplikacija <xliff:g id="APP">%s</xliff:g> aktivirala je VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Dodirnite za upravljanje mrežom."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 9697bae..8d55245 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Szinkronizálás"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Túl sok <xliff:g id="CONTENT_TYPE">%s</xliff:g> törlés."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"A táblagép tárhelye tele van. Szabadítson fel helyet néhány fájl törlésével."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Az óra tárhelye megtelt. Szabadítson fel helyet néhány fájl törlésével."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"A telefon tárhelye megtelt. Hely felszabadításához töröljön néhány fájlt."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Lehet, hogy a hálózat felügyelt"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Ismeretlen harmadik fél által"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Csengő bekapcsolva"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Leállítás..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"A táblagép ki fog kapcsolni."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Az óra ki fog kapcsolni."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"A telefon le fog állni."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Kikapcsolja?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Újraindítás csökkentett módban"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Repülőgép üzemmód"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Biztonsági üzemmód"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android rendszer"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"parancsikonok eltávolítása"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Lehetővé teszi egy alkalmazás számára, hogy felhasználói beavatkozás nélkül távolítson el parancsikonokat a kezdőképernyőről."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"kimenő hívások átirányítása"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Lehetővé teszi, hogy az alkalmazás kimenő híváskor lássa a tárcsázott számot, valamint a hívást átirányítsa egy másik számra, vagy megszakítsa."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Lehetővé teszi az alkalmazás számára a kimenő hívások kezdeményezését, és a tárcsázandó szám módosítását. Az engedéllyel rendelkező alkalmazás felügyelheti, átirányíthatja vagy megakadályozhatja a kimenő hívásokat."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"szöveges üzenetek (SMS) fogadása"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Lehetővé teszi az alkalmazás számára, hogy SMS-eket fogadjon és dolgozzon fel. Ez azt jelenti, hogy az alkalmazás megfigyelheti vagy törölheti a beérkező üzeneteket anélkül, hogy Ön látná azokat."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"szöveges üzenetek (MMS) fogadása"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Lehetővé teszi az alkalmazás számára az aktív ablak tartalmának letöltését. A rosszindulatú alkalmazások letölthetik az ablak teljes tartalmát, és a jelszavak kivételével az összes szöveget megvizsgálhatják."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"Ideiglenes hozzáférés engedélyezése"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Engedélyezi egy alkalmazás számára, hogy ideiglenesen hozzáférést biztosítson az eszközhöz. A kártékony alkalmazások a felhasználó beleegyezése nélkül engedélyezhetik a hozzáférést."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"ablaktoken lekérése"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Lehetővé teszi, hogy az alkalmazás lekérje az ablaktokent. A kártékony alkalmazások jogosulatlan kapcsolatot létesíthetnek az alkalmazásablakkal a rendszer nevében."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"keretstatisztikák lekérése"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Lehetővé teszi, hogy az alkalmazás keretstatisztikákat gyűjtsön. A kártékony alkalmazások figyelhetik a más alkalmazások ablakainak keretstatisztikáit."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"ablakkal kapcsolatos információk lekérése"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Lehetővé teszi, hogy az alkalmazás információkat kérjen le az ablakkezelőben lévő ablakokkal kapcsolatban. A rosszindulatú alkalmazások belső rendszerhasználathoz szükséges információkat kérhetnek le."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"események szűrése"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Lehetővé teszi az alkalmazás számára, hogy egy bemeneti szűrőt használjon, amely megszűri a falon megjelenő felhasználói eseményeket, még mielőtt megjelennének. A rosszindulatú alkalmazások felhasználói beavatkozás nélkül irányíthatják a rendszer kezelőfelületét."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"kijelző nagyítása"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Lehetővé teszi egy alkalmazás számára, hogy kinagyítsa a kijelzőn megjelenő tartalmat. Előfordulhat, hogy a rosszindulatú alkalmazások úgy alakítják át a kijelző tartalmát, hogy használhatatlanná válik az eszköz."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"részleges rendszerleállítás"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Leállítás állapotba helyezi a tevékenységkezelőt. Nem hajtja végre a teljes leállítást."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"alkalmazásváltás megakadályozása"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Lehetővé teszi az alkalmazás számára értesítés küldését SMS érkezéséről. A rosszindulatú alkalmazások beérkező SMS-ek hamisítására használhatják fel ezt."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH alapú üzenetek küldése"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Lehetővé teszi az alkalmazás számára értesítés küldését WAP PUSH üzenet érkezése esetén. A rosszindulatú alkalmazások arra használhatják ezt, hogy MMS-kézbesítési jelentést hamisítsanak, vagy hogy a háttérben rosszindulatú variánssal cseréljék le bármelyik weboldal tartalmát."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"hálózatpontozási értesítés küldése"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Lehetővé teszi, hogy az alkalmazás szétküldjön egy értesítést, amely szerint a hálózatokat pontozni kell. A normál alkalmazásoknak erre soha nincs szükségük."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"futó folyamatok számának korlátozása"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Lehetővé teszi az alkalmazás számára a futtatható folyamatok maximális számának vezérlését. Soha nem lehet rá szüksége a normál alkalmazásoknak."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"háttéralkalmazások leállításának kényszerítése"</string>
@@ -387,20 +382,14 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Lehetővé teszi a használó számára, hogy csatlakozzon egy VPN-szolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"összekapcsolás háttérképpel"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Lehetővé teszi, hogy a tulajdonos kötelezővé tegye egy háttérkép legfelső szintű felületét. A normál alkalmazásoknak erre soha nincs szüksége."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"csatlakozás egy távoli kijelzőhöz"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lehetővé teszi a használó számára, hogy csatlakozzon egy távoli kijelző legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"csatlakozás modulszolgáltatáshoz"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Lehetővé teszi, hogy a tulajdonos kapcsolódjon egy tévébemenet legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Lehetővé teszi, hogy a tulajdonos kapcsolódjon egy tévébemenet legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"eszközrendszergazda hozzáadása vagy eltávolítása"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Lehetővé teszi a tulajdonos számára, hogy aktív eszközrendszergazdákat adjon meg vagy távolítson el. A normál alkalmazásoknál erre soha nincs szükség."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"képernyő irányának módosítása"</string>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Lehetővé teszi egy alkalmazás számára bármely telepített médiadekóder használatát a lejátszás dekódolásához."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"megbízható tanúsítványok kezelése"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lehetővé teszi az alkalmazás számára a CA tanúsítványok telepítését és eltávolítását."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"alkalmazás futtatása tétlen időszakban"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Ezzel az engedéllyel az Android a háttérben futtathatja az alkalmazást, amikor az eszközt nem használják."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"csatolás tétlen szolgáltatásokhoz"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Ez az engedély lehetővé teszi az Android számára, hogy összekapcsolódjon egy alkalmazás tétlen szolgáltatásaival."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"a diag tulajdonában lévő erőforrások olvasása és írása"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Lehetővé teszi egy alkalmazás számára, hogy olvassa és írja a diagnosztikai csoport minden erőforrását, például a /dev könyvtárban lévő fájlokat. Ez potenciálisan befolyásolhatja a rendszer stabilitását és biztonságát, ezért CSAK a gyártó vagy a szolgáltató használhatja hardverspecifikus diagnosztizálásra."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"alkalmazáskomponensek be- és kikapcsolása"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Lehetővé teszi az alkalmazás számára, hogy hozzáférést biztosítson az eszközön tárolt személyes profiladatokhoz, például a névhez és az elérhetőségekhez. Ez azt jelenti, hogy az alkalmazás azonosíthatja Önt, és elküldheti másoknak profiladatait."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"saját névjegykártya módosítása"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Lehetővé teszi az alkalmazás számára az eszközön tárolt személyes profiladatok, például a név és az elérhetőségek módosítását vagy hozzáadását. Ez azt jelenti, hogy az alkalmazás azonosíthatja Önt, és elküldheti másoknak profiladatait."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"testérzékelők (pl. pulzusmérő)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Lehetővé teszi, hogy az alkalmazás hozzáférjen az olyan érzékelők által észlelt adatokhoz, amelyek az Ön életfunkcióit – például a pulzusszámát – figyelik."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"közösségi adatfolyam olvasása"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Lehetővé teszi az alkalmazás számára, hogy hozzáférjen az Ön és ismerősei közösségi oldalakon szereplő frissítéseihez. Legyen elővigyázatos, amikor információt tesz közzé -- így az alkalmazás hozzáférhet az ismerőseivel a közösségi hálózatokon folytatott magánbeszélgetésekhez, a tartalom titkos jellegétől függetlenül. Megjegyzés: előfordulhat, hogy ez nincs minden közösségi hálózaton engedélyezve."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"írás a közösség adatfolyamra"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Lehetővé teszi az alkalmazás számára, hogy az eszköz telefonálási funkcióit vezérelje. Egy ilyen engedéllyel rendelkező alkalmazás váltani tud a hálózatok között, be- és kikapcsolhatja a telefon rádióját, és hasonlókat tehet anélkül, hogy valaha értesítené Önt."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"telefonállapot és azonosító olvasása"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Lehetővé teszi az alkalmazás számára, hogy hozzáférjen az eszköz telefonálási funkcióihoz. Az engedéllyel rendelkező alkalmazás meghatározhatja a telefonszámot és eszközazonosítókat, hogy egy hívás aktív-e, valamint híváskor a másik fél telefonszámát."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"pontos telefonállapot megállapítása"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Engedélyezi, hogy az alkalmazás hozzáférjen a pontos telefonállapothoz. Az ilyen engedéllyel rendelkező alkalmazás képes meghatározni a valós hívási állapotot, azt, hogy egy hívás aktív-e vagy a háttérben van, a hívás meghiúsult-e, illetve képes meghatározni az adatkapcsolat pontos állapotát és az adatkapcsolati műveletek meghiúsulását."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"táblagép alvás üzemmódjának megakadályozása"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"telefon alvó üzemmódjának megakadályozása"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Lehetővé teszi az alkalmazás számára, hogy megakadályozza, hogy a táblagép alvó üzemmódra váltson."</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX-állapot módosítása"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Lehetővé teszi az alkalmazás számára, hogy a táblagépet csatlakoztassa WiMAX-hálózathoz vagy leválassza azt róla."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Lehetővé teszi az alkalmazás számára, hogy a telefont csatlakoztassa WiMAX-hálózathoz vagy leválassza azt róla."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"hálózatok pontozása"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Lehetővé teszi, hogy az alkalmazás rangsorolja a hálózatokat, illetve befolyásolja, hogy a táblagép mely hálózatokat részesítse előnyben."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Lehetővé teszi, hogy az alkalmazás rangsorolja a hálózatokat, illetve befolyásolja, hogy a telefon mely hálózatokat részesítse előnyben."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"Bluetooth-eszközök párosítása"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Lehetővé teszi az alkalmazás számára a táblagépen lévő Bluetooth beállításainak megtekintését, valamint kapcsolatok kezdeményezését és fogadását a párosított eszközökkel."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Lehetővé teszi az alkalmazás számára a telefonon lévő Bluetooth beállításainak megtekintését, valamint kapcsolatok kezdeményezését és fogadását a párosított eszközökkel."</string>
@@ -703,18 +685,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"a szolgáltatói konfigurációs alkalmazás hívása"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Lehetővé teszi a használó számára a szolgáltató által biztosított konfigurációs alkalmazás hívását. A normál alkalmazásoknak erre soha nincs szükségük."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"hálózati körülményekkel kapcsolatos észrevételek figyelemmel kísérése"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Lehetővé teszi egy alkalmazás számára, hogy figyelemmel kísérje a hálózati körülményekkel kapcsolatos észrevételeket. A normál alkalmazásoknak erre soha nincs szükségük."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"beviteli eszköz kalibrációjának módosítása"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Lehetővé teszi, hogy az alkalmazás módosítsa az érintőképernyő kalibrációs paramétereit. A normál alkalmazásoknál erre elvileg soha nincs szükség."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM-tanúsítványokhoz való hozzáférés"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Engedélyezi egy alkalmazás számára a DRM-tanúsítványokhoz való hozzáférést és azok használatát. Átlagos alkalmazásoknak erre nem lehet 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="policylab_watchLogin" msgid="914130646942199503">"Képernyőzár-feloldási kísérletek figyelése"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Lehetővé teszi egy alkalmazás számára, hogy hozzáférjen a kóddal védett tárhelyhez."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Billentyűzár megjelenítésének és elrejtésének vezérlése"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Lehetővé teszi egy alkalmazás számára a billentyűzár vezérlését."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Trust-állapot változásának figyelése"</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Lehetővé teszi, hogy az alkalmazás figyelje a trust-állapot változásait."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Csatlakozás egy trust agent szolgáltatáshoz"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Lehetővé teszi, hogy az alkalmazás egy trust agent szolgáltatáshoz csatlakozzon."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Kapcsolatfelvétel a frissítési és helyreállítási rendszerrel"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Lehetővé teszi egy alkalmazás számára, hogy kapcsolatba lépjen a helyreállítási rendszerrel és a rendszerfrissítésekkel."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Érintse meg kétszer a nagyítás beállításához"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Háttérkép"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Háttérkép megváltoztatása"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Értesítésfigyelő"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN aktiválva"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"A(z) <xliff:g id="APP">%s</xliff:g> aktiválta a VPN-t"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Érintse meg a hálózat kezeléséhez."</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 682e191..c544ddb 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Համաժամել"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Չափից շատ <xliff:g id="CONTENT_TYPE">%s</xliff:g> հեռացումներ:"</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Գրասալիկի պահոցը լիքն է: Ջնջեք մի քանի ֆայլ` տարածք ազատելու համար:"</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Ժամացույցի ֆայլերի պահեստը լիքն է: Ջնջեք որոշ ֆայլեր՝ տարածք ազատելու համար:"</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Հեռախոսի պահոցը լիքն է: Ջնջեք մի քանի ֆայլեր` տարածություն ազատելու համար:"</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Ցանցը կարող է վերահսկվել"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Անհայտ երրորդ կողմի կողմից"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Զանգակը միացված է"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Անջատվում է…"</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Ձեր գրասալիկը կանջատվի:"</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Ձեր ժամացույցը կանջատվի:"</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Ձեր հեռախոսը կանջատվի:"</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Ցանկանու՞մ եք անջատել:"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Վերաբեռնել անվտանգ ռեժիմի"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Ինքնաթիռային ռեժիմ"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Անվտանգ ռեժիմ"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android համակարգ"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"ապատեղադրել դյուրանցումները"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Հավելվածին թույլ է տալիս հեռացնել գլխավոր էկրանի դյուրանցումները՝ առանց օգտագործողի միջամտության:"</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"վերաուղղել ելքային զանգերը"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Թույլ է տալիս ծրագրին ելքային զանգի ընթացքում տեսնել արդեն հավաքած համարը՝ հնարավորություն տալով վերահղել կամ անջատել զանգը։"</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Թույլ է տալիս հավելվածին մշակել ելքային զանգերը և փոխել համարհավաքումը: Վնասարար հավելվածները կարող են վերահսկել, վերահասցեավորել կամ կանխել ելքային զանգերը:"</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"ստանալ տեքստային հաղորդագրություններ (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Թույլ է տալիս հավելվածին ստանալ և մշակել SMS հաղորդագրությունները: Սա նշանակում է, որ հավելվածը կարող է ստուգել կամ ջնջել ձեր սարքին ուղարկված հաղորդագրությունները` առանց դրանք ձեզ ցուցադրելու:"</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"ստանալ տեքստային հաղորդագրություններ (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Թույլ է տալիս հավելվածին առբերել ակտիվ պատուհանի պարունակությունը: Վնասարար հավելվածները կարող են առբերել պատուհանի լրիվ պարունակությունը և հետազոտել դրա ամբողջ տեքստը` բացառությամբ գաղտնաբառերի:"</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"ժամանակավոր միացնել մուտքի հնարավորությունը"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Թույլ է տալիս հավելվածին ժամանակավորապես մուտքի հնարավորություն տալ սարքին: Վնասարար հավելվածները կարող են մուտքի հնարավորություն ընձեռել առանց օգտվողի համաձայնության:"</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"առբերել պատուհանի այլանիշը"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Ծրագրին թույլ է տալիս առբերել պատուհանի այլանիշը: Վնասակար ծրագրերը կարող են չթույլատրված ազդեցություն ունենալ ծրագրի պատուհանին՝ նմանակելով համակարգը:"</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"առբերել շրջանակի վիճակագրությունը"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Ծրագրին թույլ է տալիս հավաքել շրջանակի վիճակագրությունը: Վնասակար ծրագրերը կարող են այլ ծրագրերից հետևել շրջանակի վիճակագրությանը պատուհանների համար:"</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"առբերել պատուհանի տեղեկություները"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Թույլ է տալիս հավելվածին առբերել պատուհանների մասին տեղեկատվություններ  պատուհանի կառավարչից: Վնասարար հավելվածները կարող են առբերել տեղեկություններ, որը նախատեսված է ներքին համակարգի օգտագործման համար:"</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"զտել իրադարձությունները"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Թույլ է տալիս հավելվածին գրանցել մուտքագրման զտիչ, որը զտում է օգտվողի իրադարձությունների ամբողջ հոսքը` նախքան դրանք կուղարկվեն: Վնասարար հավելվածը կարող է կառավարել համակարգի UI-ը` առանց ձեր միջամտության:"</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"խոշորացնել ցուցադրիչը"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Թույլ է տալիս հավելվածին խոշորացնել ցուցադրիչի բովանդակությունը: Վնասարար հավելվածները կարող են փոխակերպել ցուցադրիչի բովանդակությունը այնպես, որ սարքը դառնա անպիտան:"</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"մասնակի անջատում"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Դնում է գործունեության կառավարչին անջատման կարգավիճակի մեջ: Չի իրականացնում ամբողջական անջատում:"</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"կանխել ծրագրի փոխարկումները"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Թույլ է տալիս հավելվածին հաղորդել ծանուցում, որ ստացվել է SMS հաղորդագրություն: Վնասարար հավելվածները կարող են օգտագործել սա` կեղծելու մուտքային SMS հաղորդագրությունները:"</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"ուղարկել ստացված WAP-PUSH-ի  հաղորդում"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Թույլ է տալիս հավելվածին հաղորդել ծանուցում, որ ստացվել է WAP PUSH հաղորդագրություն: Վնասարար հավելվածները կարող են օգտագործել սա` կեղծելու MMS հաղորդագրության ստացումը կամ աննկատ փոխարինելու ցանկացած կայքի բովանդակությունը վնասարար տարբերակներով:"</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ուղարկել ցանցերի գնահատականի հեռարձակում"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Ծրագրին թույլ է տալիս հեռարձակել ծանուցում, որ ցանցերը պետք է հաշվարկվեն: Նորմալ ծրագրերում երբեք պետք չի գալիս:"</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"սահմանափակել աշխատող գործընթացների թիվը"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Թույլ է տալիս հավելվածին վերահսկել գործընթացների առավելագույն թիվը, որ աշխատելու են: Երբևէ անհրաժեշտ չէ սովորական հավելվածների համար:"</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"ստիպել, որ առաջին պլանի հավելվածները փակվեն"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Թույլ է տալիս սեփականատիրոջը միանալ Vpn ծառայության վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"միանալ պաստառին"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Թույլ է տալիս սեփականատիրոջը միանալ պաստառի վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"միանալ հեռակա էկրանին"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Թույլ է տալիս սեփականատիրոջը միանալ հեռուստացույցի մուտքի վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ավելացնել կամ հեռացնել սարքի արդմինիստրատոր"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Թույլ է տալիս սեփականատիրոջը ավելացնել կամ հեռացնել սարքի ակտիվ ադմինիստրատորներ: Երբեք չպետք է անհրաժեշտ լինի սովորական ծրագրերին:"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"փոխել էկրանի դիրքավորումը"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Թույլ է տալիս հավելվածին օգտագործել ցանկացած տեղադրված մեդիա վերծանիչ` նվագարկումը ապակոդավորելու համար:"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"կառավարել վստահելի հավաստագրերը"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Թույլատրում է հավելվածին տեղադրել և ապատեղադրել CA վկայագրերը՝ որպես վստահելի հավաստագրեր:"</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"գործադրել ծրագրեր պարապուրդի ժամանակ"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Այս թույլտվությունը հնարավորություն է տալիս, որ Android համակարգը ծրագրեր գործադրի ֆոնային ռեժիմում, երբ սարքը չի օգտագործվում:"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"կապակցել ոչ ակտիվ ծառայությունների հետ"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Այս թույլտվությունը հնարավորություն է տալիս Android համակարգին կապ հաստատել ծրագրի չաշխատող ծառայությունների հետ:"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"կարդալ կամ գրել ախտորոշիչին պատկանող ռեսուրսները"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Թույլ է տալիս հավելվածին կարդալ և գրել ախտորոշիչ խմբին պատկանող ցանկացած ռեսուրսում, ինչպես օրինակ ֆայլերը /dev-ում: Դա կարող է ազդել համակարգի կայունության և անվտանգության վրա: Սա պետք է օգտագործել միայն արտադրողի կամ օպերատորի կողմից սարքին հատուկ ախտորոշման համար:"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"միացնել կամ անջատել հավելվածի բաղադրիչները"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Թույլ է տալիս հավելվածին կարդալ ձեր սարքում պահված անհատական ​​պրոֆիլի տվյալները, ինչպիսիք են ձեր անունը և կոնտակտային տվյալները: Սա նշանակում է, որ հավելվածը կարող է ձեզ ճանաչել և ուղարկել ձեր պրոֆիլի տվյալները ուրիշներին:"</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"փոփոխել ձեր սեփական կոնտակտային քարտը"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Թույլ է տալիս հավելվածին փոխել կամ ավելացնել ձեր սարքում պահված անհատական ​​պրոֆիլի տվյալները, ինչպիսիք են ձեր անունը և կոնտակտային տվյալները: Սա նշանակում է, որ հավելվածը կարող է ձեզ ճանաչել և ուղարկել ձեր պրոֆիլի տվյալները ուրիշներին:"</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"մարմնի սենսորներ (օր.` սրտի)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Ծրագրին թույլ է տալիս մատչել ձեր կողմից օգտագործվող սենսորների տվյալները՝ չափելու, թե ինչ է տեղի ունենում ձեր մարմնի ներսում, ինչպես օրինակ՝ սրտի զարկերը:"</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"կարդալ ձեր սոցիալական հոսքը"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Թույլ է տալիս հավելվածին մուտք գործել և համաժամեցնել ձեր և ձեր ընկերների սոցիալական թարմացումները: Զգույշ եղեք տեղեկություններ տարածելիս. այն թույլ է տալիս հավելվածին կարդալ ձեր և ձեր ընկերների միջև անձնական հաղորդագրությունները սոցիալական ցանցերում` անկախ գաղտնիությունից: Նշում. այս թույլտվությունը չի կարող գործածվել բոլոր սոցիալական ցանցերում:"</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"գրել ձեր սոցիալական հոսքում"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Թույլ է տալիս հավելվածին կառավարել սարքի հեռախոսային գործիքները: Այս թույլտվությամբ հավելվածը կարող է փոխարկել ցանցերը, միացնելև անջատել հեռախոսի ռադիոն և նման այլ բաներ` առանց ձեզ երբևէ տեղեկացնելու:"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"կարդալ հեռախոսի կարգավիճակը և ինքնությունը"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Թույլ է տալիս հավելվածին օգտագործել սարքի հեռախոսային գործիքները: Այս թույլտվությունը հավելվածին հնարավորություն է տալիս որոշել հեռախոսահամարը և սարքի ID-ները, արդյոք զանգը ակտիվ է և միացված զանգի հեռակա հեռախոսահամարը:"</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"դիտել հեռախոսի ճշգրիտ կարգավիճակները"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Թույլ է տալիս ծրագրին մուտք ունենալ հեռախոսի ճշգրիտ կարգավիճակներին: Այս թույլատվության շնորհիվ ծրագիրը կարող է որոշել զանգի իրական կարգավիճակը, արդյոք զանգը ակտիվ է, թե հետին պլանում է, զանգերի ժամանակ տեղի ունեցած սխալները, տվյալների միացման ճշգրիտ կարգավիճակը և տվյալների միացման ժամանակ տեղի ունեցած սխալները:"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"զերծ պահել գրասալիկը քնելուց"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"կանխել հեռախոսի քնի ռեժիմին անցնելը"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Թույլ է տալիս հավելվածին կանխել գրասալիկի` քնի ռեժիմին անցնելը:"</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Փոխել WiMAX-ի կարգավիճակը"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Թույլ է տալիս հավելվածին գրասալիկը միացնել WiMAX ցանցին և անջատվել այդ ցանցից:"</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Թույլ է տալիս հավելվածին հեռախոսը միացնել WiMAX ցանցին և անջատել այդ ցանցից:"</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ցանցերի գնահատական"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Ծրագրին թույլ է տալիս դասակարգել ցանցերը և ազդել գրասալիկի նախընտրելի ցանցի ընտրության գործընթացի վրա:"</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Ծրագրին թույլ է տալիս դասակարգել ցանցերը և ազդել հեռախոսի նախընտրելի ցանցի ընտրության գործընթացի վրա:"</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"զուգակցվել Bluetooth սարքերի հետ"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Թույլ է տալիս հավելվածին տեսնել Bluetooth-ի կարգավորումը գրասալիկի վրա և կապվել ու կապեր ընդունել զուգակցված սարքերի հետ:"</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Թույլ է տալիս հավելվածին տեսնել Bluetooth-ի կարգավորումը հեռախոսի վրա և կապվել ու կապեր ընդունել զուգակցված սարքերի հետ:"</string>
@@ -703,18 +683,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Թույլ է տալիս հավելվածին առբերել, ուսումնասիրել և մաքրել ծանուցումներն, այդ թվում նաև այլ հավելվածների կողմից գրառվածները:"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"միանալ ծանուցումների ունկնդրիչ ծառայությանը"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Թույլ է տալիս սեփականատիրոջը միանալ ծանուցումները ունկնդրող ծառայության վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"գործարկել օպերատորի կողմից տրամադրված կազմաձևման ծրագիրը"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Թույլ է տալիս սեփականատիրոջը գործարկել օպերատորի կողմից տրամադրված կազմաձևման ծրագիրը: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"լսել դիտարկումներ ցանցային պայմանների վերաբերյալ"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Հավելվածին թույլ է տալիս լսել դիտարկումներ ցանցային պայմանների վերաբերյալ: Սովորական հավելվածների համար երբեք պետք չի գալիս:"</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"փոփոխել մուտքի սարքի չափաբերումը"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Թույլ է տալիս ծրագրին փոփոխել հպէկրանի չափաբերման կարգավորումները: Սովորական ծրագրերի համար երբեք պետք չի գալու:"</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM հավաստագրերի մատչում"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Ծրագրին թույլ է տալիս տրամադրել և օգտագործել DRM վկայագրեր: Սովորական ծրագրերի համար երբեք պետք չի գալիս:"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Սահմանել գաղտնաբառի կանոնները"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Վերահսկել էկրանի ապակողպման գաղտնաբառերի թույլատրելի երկարությունն ու գրանշանները:"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Վերահսկել էկրանի ապակողպման փորձերը"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Թույլ է տալիս հավելվածին մուտք գործել ստեղնակողպեքով պաշտպանված պահոց:"</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>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Կապվել վստահելի գործակալի ծառայությանը"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ծրագրին թույլ է տալիս կապվել վստահելի գործակալի ծառայությանը:"</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Փոխազդել թարմացման և վերականգնման համակարգի հետ"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Թույլ է տալիս ծրագրին փոխազդել վերականգնման համակարգի և համակարգի թարմացումների հետ:"</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Հպեք երկու անգամ` դիտափոխման կարգավորման համար"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Պաստառ"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Փոխել պաստառը"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Ծանուցման ունկնդիր"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN-ը ակտիվացված է"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN-ն ակտիվացված է <xliff:g id="APP">%s</xliff:g>-ի կողմից"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Հպեք` ցանցի կառավարման համար:"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 105da53..791d5b9 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinkron"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Terlalu banyak <xliff:g id="CONTENT_TYPE">%s</xliff:g> penghapusan."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Penyimpanan tablet penuh. Hapus beberapa file untuk mengosongkan ruang."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Penyimpanan arloji penuh. Hapus beberapa file untuk mengosongkan ruang."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Penyimpanan di ponsel penuh. Hapus sebagian file untuk mengosongkan ruang."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Jaringan mungkin dipantau"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Oleh pihak ketiga yang tidak dikenal"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Pendering nyala"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Sedang mematikan..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tablet Anda akan dimatikan."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Arloji Anda akan dimatikan."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Ponsel Anda akan dimatikan."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Anda ingin mematikannya?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Reboot ke mode aman"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mode pesawat"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode aman"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"mencopot pemasangan pintasan"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Mengizinkan aplikasi menghapus pintasan Layar Utama tanpa tindakan dari pengguna."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"ubah rute panggilan keluar"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Memungkinkan aplikasi melihat nomor yang dihubungi saat melakukan panggilan keluar dengan opsi untuk mengalihkan panggilan ke nomor lain atau membatalkan panggilan sepenuhnya."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Memungkinkan aplikasi memproses panggilan keluar dan mengubah nomor yang akan dipanggil. Izin ini memungkinkan aplikasi memantau, mengalihkan, atau mencegah panggilan keluar."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"terima pesan teks (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Memungkinkan aplikasi menerima dan memproses pesan SMS. Ini artinya aplikasi dapat memantau atau menghapus pesan yang dikirim ke perangkat Anda tanpa menunjukkannya kepada Anda."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"terima pesan teks (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Mengizinkan apl mengambil konten jendela aktif. Apl berbahaya dapat mengambil seluruh konten jendela dan memeriksa semua teksnya kecuali sandi."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"aktifkan aksesibilitas untuk sementara"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Memungkinkan aplikasi mengaktifkan aksesibilitas pada perangkat untuk sementara. Aplikasi berbahaya dapat mengaktifkan aksesibilitas tanpa izin pengguna."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"mengambil token jendela"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Memungkinkan aplikasi mengambil token jendela. Aplikasi berbahaya dapat melakukan interaksi yang tidak sah dengan jendela aplikasi dengan meniru sistem."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"mengambil statistik bingkai"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Memungkinkan aplikasi mengumpulkan statistik bingkai. Aplikasi berbahaya dapat mengamati statistik bingkai jendela dari aplikasi lain."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"mengambil info jendela"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Mengizinkan aplikasi mengambil informasi tentang jendela dari pengelola jendela. Aplikasi berbahaya dapat mengambil informasi yang ditujukan untuk penggunaan sistem internal."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"memfilter acara"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Mengizinkan aplikasi mendaftarkan filter masukan yang memfilter streaming semua acara pengguna sebelum acara dikirimkan. Aplikasi berbahaya dapat mengontrol UI sistem tanpa campur tangan pengguna."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"memperbesar tampilan"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Izinkan aplikasi memperbesar konten tampilan. Aplikasi berbahaya dapat mengubah konten tampilan dengan merender perangkat menjadi tidak dapat digunakan."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"penghentian sebagian"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Letakkan pengelola aktivitas dalam kondisi mati. Tidak melakukan penonaktifan penuh."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"cegah pergantian aplikasi"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Mengizinkan apl menyiarkan pemberitahuan bahwa pesan SMS telah diterima. Apl berbahaya dapat menggunakan ini untuk memalsukan pesan SMS masuk."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"kirim siaran WAP-PUSH-diterima"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Mengizinkan apl menyiarkan pemberitahuan bahwa pesan WAP PUSH telah diterima. Apl berbahaya dapat menggunakan ini untuk memalsukan penerimaan pesan MMS atau diam-diam mengganti konten laman web apa pun dengan varian berbahaya."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"mengirim siaran beri skor jaringan"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Memungkinkan aplikasi menyiarkan pemberitahuan bahwa jaringan perlu diberi skor. Tidak pernah diperlukan untuk aplikasi normal."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"batasi jumlah dari proses yang berjalan"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Mengizinkan apl mengontrol jumlah maksimum proses yang akan berjalan. Tidak pernah diperlukan oleh apl normal."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"paksa aplikasi latar belakang agar menutup"</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan Vpn. Tidak pernah diperlukan oleh apl normal."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"mengikat ke wallpaper"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu wallpaper. Tidak pernah diperlukan oleh apl normal."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"mengikat ke layar jarak jauh"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Mengizinkan pemegang mengikat ke antarmuka tingkat atas dari layar jarak jauh. Tidak pernah diperlukan untuk aplikasi normal."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"mengikat ke layanan widget"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Mengizinkan apl menggunakan pengawasandi media apa pun yang terpasang guna mengawasandikan media untuk diputar."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"kelola kredensial tepercaya"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Izinkan aplikasi memasang dan mencopot pemasangan sertifikat CA sebagai kredensial tepercaya."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"menjalankan aplikasi selama waktu nganggur"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Izin ini memungkinkan sistem Android menjalankan aplikasi di latar belakang saat perangkat tidak digunakan."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"mengikat ke layanan yang sedang menganggur"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Izin ini memungkinkan sistem Android mengikat layanan waktu menganggur aplikasi."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"baca/tulis ke sumber daya yang dimiliki oleh diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Mengizinkan apl membaca dan menulis ke sumber daya apa pun yang dimiliki oleh grup diag; misalnya, file dalam /dev. Izin ini berpotensi memengaruhi kestabilan dan keamanan sistem. Sebaiknya ini HANYA digunakan untuk diagnosis khusus perangkat keras oleh pabrikan atau operator."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"mengaktifkan atau menonaktifkan komponen apl"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Memungkinkan aplikasi membaca informasi profil pribadi yang tersimpan di perangkat Anda, misalnya nama dan informasi kontak Anda. Ini artinya aplikasi dapat mengenali dan mengirim informasi profil Anda ke orang lain."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"ubah kartu kontak Anda"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Memungkinkan aplikasi mengubah atau menambah informasi profil pribadi yang tersimpan di perangkat Anda, seperti nama dan informasi kontak. Ini berarti aplikasi tersebut dapat mengenali Anda dan mengirim informasi profil Anda ke orang lain."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"sensor tubuh (misal: monitor detak jantung)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Memungkinkan aplikasi mengakses data dari sensor yang Anda gunakan untuk mengukur yang terjadi di dalam tubuh, misalnya detak jantung."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"membaca aliran sosial Anda"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Memungkinkan aplikasi mengakses dan menyinkronkan pembaruan sosial dari Anda dan teman. Hati-hati ketika berbagi informasi -- izin ini memungkinkan aplikasi membaca komunikasi antara Anda dan teman di jejaring sosial, terlepas dari kerahasiaan. Catatan: izin ini tidak dapat diberlakukan di semua jejaring sosial."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"menulis ke aliran sosial Anda"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Mengizinkan apl mengontrol fitur telepon perangkat. Apl dengan izin ini dapat mengalihkan jaringan, menyalakan dan mematikan radio ponsel, dan melakukan hal serupa lainnya tanpa pernah memberi tahu Anda."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"baca identitas dan status ponsel"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Memungkinkan aplikasi mengakses fitur telepon perangkat. Izin ini memungkinkan aplikasi menentukan nomor telepon dan ID perangkat, apakah suatu panggilan aktif atau tidak, dan nomor jarak jauh yang tersambung oleh sebuah panggilan."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"membaca keadaan ponsel dengan akurat"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Memungkinkan aplikasi mengakses keadaan ponsel dengan akurat. Izin ini memungkinkan aplikasi menentukan status panggilan yang sebenarnya, apakah panggilan sedang aktif atau di latar belakang, kegagalan panggilan, status sambungan data yang akurat, dan kegagalan sambungan data."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"cegah tablet dari tidur"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"mencegah ponsel menjadi tidak aktif"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Mengizinkan apl mencegah tablet tidur."</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Ubah status WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Memungkinkan aplikasi menyambungkan tablet ke dan memutus tablet dari jaringan WiMAX."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Memungkinkan aplikasi menyambungkan ponsel ke dan memutus ponsel dari jaringan WiMAX."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"memberi skor jaringan"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Memungkinkan aplikasi menilai jaringan dan memengaruhi jaringan mana yang sebaiknya dipilih tablet."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Memungkinkan aplikasi menilai jaringan dan memengaruhi jaringan mana yang sebaiknya dipilih ponsel."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"sandingkan dengan perangkat Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Memungkinkan aplikasi melihat konfigurasi Bluetooth di tablet, dan membuat serta menerima sambungan dengan perangkat yang disandingkan."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Memungkinkan aplikasi melihat konfigurasi Bluetooth di ponsel, dan membuat serta menerima sambungan dengan perangkat yang disandingkan."</string>
@@ -703,18 +685,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"memanggil aplikasi konfigurasi yang disediakan operator"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Memungkinkan pemegang meminta aplikasi konfigurasi yang disediakan operator. Tidak pernah diperlukan aplikasi normal."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"mendengar untuk observasi kondisi jaringan"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Memungkinkan aplikasi mendengar untuk observasi kondisi jaringan. Tidak pernah dibutuhkan oleh aplikasi normal."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"mengubah kalibrasi perangkat masukan"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Memungkinkan aplikasi mengubah parameter kalibrasi layar sentuh. Tidak diperlukan oleh aplikasi normal."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"mengakses sertifikat DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Memungkinkan aplikasi menyediakan dan menggunakan sertifikat DRM. Tidak pernah dibutuhkan untuk 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="policylab_watchLogin" msgid="914130646942199503">"Upaya pembukaan kunci layar monitor"</string>
@@ -1007,7 +981,7 @@
     <string name="save_password_remember" msgid="6491879678996749466">"Ingat"</string>
     <string name="save_password_never" msgid="8274330296785855105">"Jangan"</string>
     <string name="open_permission_deny" msgid="7374036708316629800">"Anda tidak memiliki izin untuk membuka laman ini."</string>
-    <string name="text_copied" msgid="4985729524670131385">"Teks disalin ke papan klip."</string>
+    <string name="text_copied" msgid="4985729524670131385">"Teks disalin ke clipboard."</string>
     <string name="more_item_label" msgid="4650918923083320495">"Lainnya"</string>
     <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
     <string name="menu_space_shortcut_label" msgid="2410328639272162537">"spasi"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Mengizinkan aplikasi mengakses pengaman penyimpanan aman."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Kontrol untuk menampilkan dan menyembunyikan pengaman"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Izinkan aplikasi untuk mengontrol pengaman."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Dengarkan perubahan status kepercayaan."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Mengizinkan aplikasi mendengarkan perubahan dalam status kepercayaan."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Ikat ke layanan agen kepercayaan"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Mengizinkan aplikasi mengikat ke layanan agen kepercayaan."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Berinteraksi dengan sistem pemulihan dan pembaruan"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Mengizinkan aplikasi berinteraksi dengan sistem pemulihan dan pembaruan sistem."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Sentuh dua kali untuk mengontrol perbesar/perkecil"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Ubah wallpaper"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Pendengar pemberitahuan"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN diaktifkan"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN diaktifkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Sentuh untuk mengelola jaringan."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 17530b6..a16e5d0 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronizzazione"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Troppe eliminazioni di <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Spazio di archiviazione del tablet esaurito. Elimina alcuni file per liberare spazio."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"La memoria dell\'orologio è piena. Elimina alcuni file per liberare spazio."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Spazio di archiviazione del telefono esaurito. Elimina alcuni file per liberare spazio."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"La rete potrebbe essere monitorata"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Da una terza parte sconosciuta"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Suoneria attiva"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Spegnimento..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Il tablet verrà spento."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"L\'orologio verrà spento."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Il telefono verrà spento."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Spegnere?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Riavvia in modalità provvisoria"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modalità aereo"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modalità provvisoria"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"eliminazione di scorciatoie"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Consente all\'applicazione di rimuovere le scorciatoie della schermata Home automaticamente."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"reindirizzamento chiamate in uscita"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Consente all\'app di rilevare il numero digitato durante una chiamata in uscita, con la possibilità di reindirizzare la telefonata a un numero diverso o interromperla del tutto."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Consente all\'applicazione di elaborare le chiamate in uscita e di modificare il numero da comporre. Questa autorizzazione consente all\'applicazione di monitorare, reindirizzare o impedire le chiamate in uscita."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"ricezione messaggi di testo (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Consente all\'applicazione di ricevere ed elaborare messaggi SMS. Significa che l\'applicazione potrebbe monitorare o eliminare i messaggi inviati al tuo dispositivo senza mostrarteli."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"ricezione messaggi di testo (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Consente all\'applicazione di recuperare i contenuti della finestra attiva. Le applicazioni dannose potrebbero recuperare l\'intero contenuto della finestra ed esaminare tutto il testo, tranne le password."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"attivazione temporanea dell\'accessibilità"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Consente a un\'applicazione di attivare temporaneamente l\'accessibilità sul dispositivo. Le applicazioni dannose potrebbero attivare l\'accessibilità senza il consenso dell\'utente."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"recupero del token delle finestre"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Consente a un\'applicazione di recuperare il token delle finestre. Le app dannose potrebbero effettuare interazioni non consentite con la finestra dell\'applicazione identificandosi come il sistema."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"recupero di statistiche del frame"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Consente a un\'applicazione di raccogliere statistiche del frame. Le app dannose potrebbero osservare le statistiche del frame relative alle finestre da altre app."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"recupero di informazioni sulle finestre"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Consente a un\'applicazione di recuperare informazioni sulle finestre dalla gestione finestre. Le applicazioni dannose potrebbero recuperare informazioni destinate all\'utilizzo da parte del sistema interno."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filtro eventi"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Consente a un\'applicazione di registrare un filtro di ingresso che filtra lo stream di tutti gli eventi degli utenti prima che vengano inviati. Un\'applicazione dannosa potrebbe controllare l\'interfaccia utente del sistema senza l\'intervento dell\'utente."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"ingrandimento dello schermo"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Consente a un\'applicazione di ingrandire i contenuti di uno schermo. Le applicazioni dannose potrebbero trasformare i contenuti dello schermo in modo da rendere inutilizzabile il dispositivo."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"chiusura parziale"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Mette il gestore delle attività in uno stato di chiusura. Non esegue una chiusura completa."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"impedire commutazione applicazione"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Consente all\'applicazione di trasmettere una notifica che informa della ricezione di un messaggio SMS. Le applicazioni dannose potrebbero farne uso per creare messaggi SMS in arrivo."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"invio broadcast ricevuti tramite WAP-PUSH"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Consente all\'applicazione di trasmettere una notifica che informa della ricezione di un messaggio WAP PUSH. Le applicazioni dannose potrebbero farne uso per simulare la ricezione di messaggi MMS o per sostituire di nascosto i contenuti di qualsiasi pagina web con varianti dannose."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"invio trasmissione classificazione reti"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Consente all\'app di trasmettere una notifica indicante che le reti devono essere classificate. Opzione non necessaria per le app normali."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"numero limite di processi in esecuzione"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Consente all\'applicazione di controllare il numero massimo di processi che verranno eseguiti. Mai necessaria per le applicazioni normali."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"chiusura forzata applicazioni di background"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Consente l\'associazione all\'interfaccia principale di un servizio VPN. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"associazione a sfondo"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Consente l\'associazione di uno sfondo all\'interfaccia principale. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"collega a un display remoto"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un display remoto. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"associazione a un servizio widget"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un ingresso TV. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"aggiungere o rimuovere un amministratore del dispositivo"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Consente al titolare di aggiungere o rimuovere gli amministratori attivi del dispositivo. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"modifica orientamento dello schermo"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Consente all\'applicazione di utilizzare qualsiasi decoder multimediale installato per la decodifica ai fini della riproduzione."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestione di credenziali attendibili"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Consente all\'app di installare e disinstallare certificati CA come credenziali attendibili."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"esegui l\'applicazione nel tempo di inattività del sistema"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Questa autorizzazione consente al sistema Android di eseguire l\'applicazione in background mentre il dispositivo non è in uso."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"associazione a servizi non disponibili"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Questa autorizzazione consente al sistema Android di associarsi ai servizi inattivi di un\'applicazione."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lettura/scrittura risorse di proprietà di diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Consente all\'applicazione di leggere le risorse del gruppo diag e scrivere in esse, ad esempio i file in /dev. Ciò potrebbe influire su stabilità e sicurezza del sistema. Dovrebbe essere utilizzata SOLTANTO per diagnostiche specifiche dell\'hardware effettuate dal produttore o dall\'operatore."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"attivazione/disattivazione componenti applicazioni"</string>
@@ -471,12 +458,10 @@
     <string name="permlab_writeCallLog" msgid="8552045664743499354">"scrittura del registro chiamate"</string>
     <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Consente all\'applicazione di modificare il registro chiamate del tablet, inclusi i dati sulle chiamate in arrivo e in uscita. Le applicazioni dannose potrebbero farne uso per cancellare o modificare il registro chiamate."</string>
     <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Consente all\'applicazione di modificare il registro chiamate del telefono, inclusi i dati sulle chiamate in arrivo e in uscita. Le applicazioni dannose potrebbero farne uso per cancellare o modificare il registro chiamate."</string>
-    <string name="permlab_readProfile" msgid="4701889852612716678">"lettura scheda contatti pers."</string>
+    <string name="permlab_readProfile" msgid="4701889852612716678">"lettura scheda cont. personale"</string>
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Consente all\'applicazione di leggere informazioni del profilo personale memorizzate sul dispositivo, come il tuo nome e le tue informazioni di contatto. Ciò significa che l\'applicazione può identificarti e inviare le informazioni del tuo profilo ad altri."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"modifica scheda contatti"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Consente all\'applicazione di modificare o aggiungere informazioni ai dati del profilo personale memorizzati sul dispositivo, come il tuo nome e le tue informazioni di contatto. Significa che l\'applicazione può identificarti e inviare le informazioni del tuo profilo ad altri."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"sensori per il corpo (come il cardiofrequenzimetro)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Consente all\'app di accedere a dati derivanti dai sensori utilizzati per rilevare cosa sta accadendo nel tuo corpo, ad esempio la frequenza cardiaca."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"lettura del tuo stream sociale"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Consente all\'applicazione di accedere agli aggiornamenti dei social network tra te e i tuoi amici e di sincronizzarli. Fai attenzione quando condividi informazioni: questa autorizzazione consente all\'applicazione di leggere le comunicazioni tra te e i tuoi amici sui social network, indipendentemente dal livello di riservatezza. Nota. È possibile che questa autorizzazione non sia applicabile su tutti i social network."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"scrittura nel tuo stream sociale"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Consente all\'applicazione di controllare le funzioni telefoniche del dispositivo. Un\'applicazione con questa autorizzazione può cambiare rete, attivare/disattivare il segnale radio del telefono e così via a tua insaputa."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"lettura stato e identità telefono"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Consente all\'applicazione di accedere alle funzioni telefoniche del dispositivo. Questa autorizzazione consente all\'applicazione di determinare il numero di telefono e gli ID dei dispositivi, se una chiamata è attiva e il numero remoto connesso da una chiamata."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"rileva gli stati esatti del telefono"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Consente all\'app di accedere allo stato esatto del telefono. Questa autorizzazione consente all\'app di determinare il reale stato della chiamata: se una chiamata è attiva, in sottofondo o non riuscita. Inoltre, rileva l\'esatto stato della connessione dati nonché le connessioni dati non riuscite."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"disattivazione stand-by del tablet"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"disattivazione stand-by del telefono"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Consente all\'applicazione di impedire lo stand-by del tablet."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Modifica stato WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Consente all\'applicazione di connettere/disconnettere il tablet dalle reti WiMAX."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Consente all\'applicazione di connettere/disconnettere il telefono dalle reti WiMAX."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"valutazione reti"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Consente all\'app di stilare una classifica delle reti e determinare quali di queste il tablet deve prediligere."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Consente all\'app di stilare una classifica delle reti e determinare quali di queste il telefono deve prediligere."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"accoppiamento con dispositivi Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Consente all\'applicazione di visualizzare la configurazione del Bluetooth sul tablet e di stabilire e accettare connessioni con dispositivi accoppiati."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Consente all\'applicazione di visualizzare la configurazione del Bluetooth sul telefono e di stabilire e accettare connessioni con dispositivi accoppiati."</string>
@@ -703,18 +683,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"richiamo dell\'app di configurazione operatore-provider"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Consente al titolare di richiamare l\'app di configurazione dell\'operatore-provider. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ascolto delle osservazioni sulle condizioni di rete"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Consente a un\'applicazione di ascoltare le osservazioni sulle condizioni di rete. Da non utilizzare mai con app normali."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"modifica calibrazione del dispositivo di immissione"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Consente all\'app di modificare i parametri di calibrazione del touch screen. Questa opzione non deve essere utilizzata per le app normali."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"accesso a certificati DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Consente a un\'app di fornire e utilizzare ceritificati DRM. Questa opzione non deve essere utilizzata per app normali."</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="policylab_watchLogin" msgid="914130646942199503">"Controllo tentativi di sblocco dello schermo"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Consente a un\'applicazione di accedere all\'archivio sicuro keguard."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Controllo della visualizzazione e dell\'occultamento di keyguard"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Consente a un\'applicazione di controllare keguard."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Rilevamento modifiche dello stato trust."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Consente a un\'applicazione di rilevare le modifiche nello stato trust."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Associazione a un servizio trust agent"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Consente a un\'applicazione di associarsi a un servizio trust agent."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interazione con il sistema di ripristino e aggiornamento"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Consente a un\'applicazione di interagire con il sistema di ripristino e con gli aggiornamenti di sistema."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Tocca due volte per il comando dello zoom"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Sfondo"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Cambia sfondo"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Listener di notifica"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN attiva"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN attivata da <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Tocca per gestire la rete."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index a633d1f..d412dfb 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"סינכרון"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"יש מחיקות רבות מדי של <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"שטח האחסון של הטאבלט מלא. מחק קבצים כדי לפנות מקום."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"שטח האחסון של השעון מלא. מחק כמה קבצים כדי לפנות שטח."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"שטח האחסון של הטלפון מלא. מחק חלק מהקבצים כדי לפנות שטח."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ייתכן שהרשת מנוטרת"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"על ידי צד שלישי לא מוכר"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"צלצול מופעל"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"מכבה..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"הטאבלט שלך יכבה."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"השעון יכבה."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"הטלפון שלך יכובה."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"האם ברצונך לבצע כיבוי?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"אתחל למצב בטוח"</string>
@@ -165,7 +163,7 @@
     <string name="global_action_lock" msgid="2844945191792119712">"נעילת מסך"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"כיבוי"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"דיווח על באג"</string>
-    <string name="bugreport_title" msgid="2667494803742548533">"שלח דיווח על באג"</string>
+    <string name="bugreport_title" msgid="2667494803742548533">"מלא דיווח על באג"</string>
     <string name="bugreport_message" msgid="398447048750350456">"פעולה זו תאסוף מידע על מצב המכשיר הנוכחי שלך על מנת לשלוח אותו כהודעת דוא\"ל. היא תימשך זמן קצר מרגע פתיחת דיווח הבאג ועד שיהיה ניתן לבצע שליחה. התאזר בסבלנות."</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"מצב שקט"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"הקול כבוי"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"מצב טיסה"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"מצב בטוח"</string>
     <string name="android_system_label" msgid="6577375335728551336">"‏מערכת Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"הסר התקנה של קיצורי דרך"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"מאפשר לאפליקציה להסיר קיצורי דרך במסך דף הבית ללא התערבות המשתמש."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"ניתוב מחדש של שיחות יוצאות"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"מאפשרת לאפליקציה לראות את המספר המחויג במהלך ביצוע שיחה יוצאת, עם האפשרות להפנות את השיחה למספר אחר או לבטל את השיחה לחלוטין."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"מאפשר לאפליקציה לעבד שיחות יוצאות ולשנות את המספר שיש לחייג. אישור זה מאפשר לאפליקציה לעקוב אחר שיחות יוצאות, לבצע הפניה מחדש שלהן או אף למנוע את ביצוען."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"‏קבלת הודעות טקסט (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"‏מאפשר לאפליקציה לקבל ולעבד הודעות SMS. משמעות הדבר היא שהאפליקציה יכולה לעקוב אחר הודעות שנשלחו למכשיר או למחוק אותן מבלי להציג לך אותן."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"‏קבלת הודעות טקסט (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"מאפשר לאפליקציה לאחזר את התוכן של החלון הפעיל. אפליקציות זדוניות עלולות לאחזר את תוכן החלון כולו ולבחון את כל הטקסט שבו, מלבד סיסמאות."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"הפעלת נגישות זמנית"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"מאפשר לאפליקציה להפעיל באופן זמני נגישות במכשיר. אפליקציות זדוניות עלולות לאפשר נגישות ללא הסכמת משתמש."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"אחזור אסימון חלון"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"מאפשרת לאפליקציה לאחזר את אסימון החלון. אפליקציות זדוניות עשויות לבצע אינטראקציה בלתי מורשית עם חלון האפליקציה, ולהעמיד פנים שהן המערכת."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"אחזור סטטיסטיקת מסגרת"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"מאפשרת לאפליקציה לאסוף סטטיסטיקת מסגרת. אפליקציות זדוניות עשויות לבחון את סטטיסטיקת המסגרת של חלונות מאפליקציות אחרות."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"אחזר מידע חלון"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"מאפשר לאפליקציה לאחזר מידע לגבי החלונות ממנהל החלונות. אפליקציות זדוניות עשויות לאחזר מידע המיועד לשימוש מערכת פנימי."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"סנן אירועים"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"‏מאפשר לאפליקציה לרשום מסנן קלט שמסנן את הזרם של כל אירועי המשתמש לפני שהם נשלחים. אפליקציה זדונית עשויה לשלוט ב-UI של המערכת ללא התערבות משתמש."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"הגדלת תצוגה"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"מאפשר לאפליקציה להגדיל את התוכן של תצוגה. אפליקציות זדוניות עלולות לשנות את תוכן התצוגה כך שהמכשיר יהפוך לבלתי שמיש."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"כיבוי חלקי"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"מעביר את מנהל הפעילויות למצב כיבוי. לא מבצע כיבוי מלא."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"מנע החלפת אפליקציות"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"‏מאפשר לאפליקציה לשדר התראה על כך שהתקבלה הודעת SMS. אפליקציות זדוניות עלולות להשתמש בכך כדי לזייף הודעות SMS נכנסות."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"‏שלח שידור שהתקבל באמצעות WAP-PUSH"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"‏מאפשר לאפליקציה לשדר התראה על כך שהתקבלה הודעה מסוג WAP PUSH. אפליקציות זדוניות עלולות להשתמש בכך כדי לזייף קבלה של הודעות MMS או כדי להחליף בחשאי את התוכן של דף אינטרנט כלשהו בגירסאות זדוניות."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"שלח שידור לדירוג רשתות"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"מאפשר לאפליקציה לשדר התראה על כדי שיש לדרג את הרשתות. לא בשימוש עבור אפליקציות רגילות."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"הגבל את מספר התהליכים הפועלים"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"מאפשר לאפליקציה לשלוט על המספר המרבי של תהליכים שיפעלו. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"אילוץ סגירה של אפליקציות ברקע"</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"‏מאפשר למשתמש לבצע איגוד לממשק ברמה עליונה של שירות VPN. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"קשור לטפט"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"מאפשר למשתמש לבצע איגוד לממשק הרמה העליונה של טפט. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"איגוד לצג מרוחק"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"הרשאה זו מאפשרת לאפליקציה להשתמש בכל מפענח מדיה מותקן כדי לבצע פענוח להשמעה."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"ניהול פרטי כניסה מהימנים"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"‏מאפשרת לאפליקציה להתקין ולהסיר אישורי CA כפרטי כניסה מהימנים."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"הרצת אפליקציה בזמן מצב לא פעיל"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"‏ההרשאה הזו מאפשרת למערכת Android להריץ את האפליקציה ברקע כשהמכשיר אינו בשימוש."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"אגד עם שירותים במצב לא פעיל"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"‏ההרשאה הזו מאפשרת למערכת Android לאגד אל שירותי אפליקציה במצב לא פעיל."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"‏קרא/כתוב במשאבים בבעלות diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"‏מאפשר לאפליקציה לקרוא ולכתוב בכל משאב שבבעלות קבוצת ה-diag; לדוגמה, קבצים ב-‎/dev. פעולה זו עשויה להשפיע על היציבות והאבטחה של המערכת. אפשרות זו צריכה לשמש רק את היצרן או המפעיל, לצורך אבחונים ספציפיים לחומרה."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"הפעלה או השבתה של רכיבי אפליקציות"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"מאפשר לאפליקציה לקרוא פרטים מהפרופיל האישי המאוחסנים במכשיר, כגון שמך ופרטי אנשי הקשר שלך. משמעות הדבר שהאפליקציה תוכל לזהות אותך ולשלוח את פרטי הפרופיל שלך לאנשים אחרים."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"שינוי כרטיס איש הקשר שלך"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"מאפשר לאפליקציה לשנות או להוסיף נתונים לפרטי הפרופיל האישי המאוחסנים במכשיר, כגון שמך ופרטי הקשר שלך. משמעות הדבר שהאפליקציה יכולה לזהות אותך ועשוי לשלוח את פרטי הפרופיל שלך לאנשים אחרים."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"חיישני גוף (כמו מוניטורים עבור קצב לב)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"מאפשר לאפליקציה לגשת לנתוני חיישנים שבהם אתה משתמש כדי למדוד פעילות המתרחשת בתוך הגוף, כמו קצב לב."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"קריאת הזרם החברתי שלך"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"מאפשר לאפליקציה גישה ויכולת סנכרון של עדכונים חברתיים שאתה וחבריך מבצעים. היזהר בעת שיתוף מידע -- הדבר מתיר לאפליקציה לקרוא התכתבויות בינך ובין חבריך ברשתות חברתיות, ללא התחשבות בסודיות. שים לב: ייתכן שאישור זה לא נאכף בכל הרשתות החברתיות."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"כתיבה בזרם החברתי שלך"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"מאפשר לאפליקציה לשלוט בתכונות הטלפון של המכשיר. אפליקציה בעלת הרשאה זו יכולה לעבור בין רשתות, להפעיל ולכבות את הרדיו בטלפון ולבצע פעולות נוספות דומות מבלי ליידע אותך."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"קריאת הסטטוס והזהות של הטלפון"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"מאפשר לאפליקציה לגשת לתכונות הטלפון של המכשיר. אישור זה מתיר לאפליקציה לגלות את מספר הטלפון ואת זיהויי המכשיר, האם שיחה פעילה ואת המספר המרוחק המחובר באמצעות שיחה."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"קריאת מצבי טלפון מדויקים"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"מאפשר לאפליקציה לגשת למצבי הטלפון המדויקים. ההרשאה הזו מאפשרית לאפליקציה לדעת מה סטטוס השיחה בפועל, האם שיחה פעילה או ברקע, כשלי שיחות, סטטוס מדויק על חיבור נתונים וכשלים בחיבור נתונים."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"מנע מהטאבלט לעבור למצב שינה"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"מניעת מעבר הטלפון למצב שינה"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"מאפשר לאפליקציה למנוע מהטאבלט לעבור למצב שינה."</string>
@@ -620,7 +605,7 @@
     <string name="permlab_accessNetworkState" msgid="4951027964348974773">"הצג חיבורי רשת"</string>
     <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"מאפשר לאפליקציה להציג מידע לגבי חיבורי רשת, למשל, אילו רשתות קיימות ומחוברות."</string>
     <string name="permlab_createNetworkSockets" msgid="8018758136404323658">"גישת רשת מלאה"</string>
-    <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"‏מאפשר לאפליקציה ליצור Sockets ולהשתמש בפרוטוקולי רשת מותאמים אישית. הדפדפן, כמו אפליקציות  אחרות, מספק אמצעים לשליחת נתונים לאינטרנט, כך שאישור זה אינו נחוץ לשליחת נתונים לאינטרנט."</string>
+    <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"‏מאפשר לאפליקציה ליצור Sockets ולהשתמש בפרוטוקולי רשת מותאמים אישית. הדפדפן ואפליקציות  אחרות מספקות אמצעים לשליחת נתונים לאינטרנט, כך שאישור זה אינו נחוץ לשליחת נתונים לאינטרנט."</string>
     <string name="permlab_writeApnSettings" msgid="505660159675751896">"שנה/עכב הגדרות רשת ותנועה"</string>
     <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"‏מאפשר לאפליקציה לשנות את הגדרות הרשת ולעכב ולבדוק את כל תנועת הרשת, לדוגמה, לשנות את ה-proxy והיציאה של כל רשת APN. אפליקציות זדוניות עלולות לעקוב אחר חבילות רשת, לבצע הפניה מחדש שלהן או לשנות אותן, ללא ידיעתך."</string>
     <string name="permlab_changeNetworkState" msgid="958884291454327309">"שנה את קישוריות הרשת"</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"‏שנה את מצב WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"‏מאפשר לאפליקציה לחבר את הטאבלט לרשתות WiMAX ולהתנתק מהן."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"‏מאפשר לאפליקציה לחבר את הטלפון לרשתות WiMAX ולהתנתק מהן."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"דרג רשתות"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"מאפשר ליישום לדרג רשתות ולהשפיע על הרשתות שאותן הטאבלט יעדיף."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"מאפשר ליישום לדרג רשתות ולהשפיע על הרשתות שאותן הטלפון יעדיף."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"‏התאמה למכשירי Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"‏מאפשר לאפליקציה להציג את תצורת ה-Bluetooth בטאבלט, וכן ליצור ולקבל חיבורים עם מכשירים מותאמים."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"‏מאפשר לאפליקציה להציג את תצורת ה-Bluetooth בטלפון, וכן ליצור ולקבל חיבורים עם מכשירים מותאמים."</string>
@@ -703,18 +685,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"מאפשר לאפליקציה לאחזר, לבדוק ולמחוק התראות, כולל כאלה שפורסמו על ידי אפליקציות אחרות."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"איגוד לשירות של מאזין להתראות"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"הרשאה זו מאפשרת למשתמש לבצע איגוד לממשק הרמה העליונה של שירות מאזין להתראות. הרשאה זו אף פעם אינה נחוצה לאפליקציות רגילים."</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"הפעלה של אפליקציית תצורה שסופקה על ידי ספק"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ההרשאה הזו מאפשרת לבעלים להפעיל את אפליקציית התצורה שסופקה על ידי ספק. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"קליטת מעקב אחר תנאי רשת"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"מאפשרת לאפליקציה לקלוט מעקב אחר תנאי רשת. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"שינוי הכיול של מכשיר קלט"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"מאפשרת לאפליקציה לשנות את פרמטרי הכיול של מסך המגע. לעולם לא אמורה להיות נחוצה לאפליקציות רגילות."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"‏גישה אל אישורי DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"‏מאפשרת לאפליקציה לנהל תצורה של אישורי DRM ולהשתמש בהם. לעולם לא אמורה להיות נחוצה עבור אפליקציה רגילה."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"הגדר כללי סיסמה"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"שלוט באורך ובתווים המותרים בסיסמאות לביטול נעילת מסך."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"עקוב אחר ניסיונות לביטול נעילת מסך"</string>
@@ -1135,7 +1109,7 @@
     <string name="cut" msgid="3092569408438626261">"חתוך"</string>
     <string name="copy" msgid="2681946229533511987">"העתק"</string>
     <string name="paste" msgid="5629880836805036433">"הדבק"</string>
-    <string name="replace" msgid="5781686059063148930">"החלף..."</string>
+    <string name="replace" msgid="5781686059063148930">"להחליף..."</string>
     <string name="delete" msgid="6098684844021697789">"מחק"</string>
     <string name="copyUrl" msgid="2538211579596067402">"העתק כתובת אתר"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"בחר טקסט"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"מאפשר לאפליקציה לגשת לאחסון המוגן באמצעות מפתח."</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>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"איגוד אל שירות סוכן אמון"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"מאפשר לאפליקציה לאגוד אל שירות סוכן אמון."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"אינטראקציה עם מערכת שחזור ועדכונים"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"מאפשרת לאפליקציה ליצור אינטראקציה עם מערכת השחזור ועדכוני מערכת."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"גע פעמיים לבקרת מרחק מתצוגה"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"טפט"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"שנה טפט"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"מאזין להתראות"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"‏VPN מופעל"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"‏VPN מופעל על ידי <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"גע כדי לנהל את הרשת."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 8905af6..58495e8 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"同期"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"<xliff:g id="CONTENT_TYPE">%s</xliff:g>での削除が多すぎます。"</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"タブレットのストレージに空き領域がありません。ファイルを削除して空き領域を確保してください。"</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"ウォッチのストレージに空き領域がありません。ファイルを削除して空き領域を確保してください。"</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"端末のストレージに空き領域がありません。ファイルを削除して空き領域を確保してください。"</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ネットワークが監視される場合があります"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"不明な第三者"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"着信音オン"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"シャットダウン中..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"タブレットの電源をOFFにします。"</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"ウォッチの電源をOFFにします。"</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"携帯電話の電源を切ります。"</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"シャットダウンしますか?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"再起動してセーフモードに変更"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"機内モード"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"セーフモード"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Androidシステム"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"ショートカットのアンインストール"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"ユーザー操作なしでホーム画面のショートカットを削除することをアプリに許可します。"</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"発信先の変更"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"発信を別の番号に転送するか完全に中止するオプションで、発信中にダイヤルされた番号にアクセスすることをアプリに許可します。"</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"通話の発信とダイヤルする番号の変更をアプリに許可します。これにより、アプリが発信を監視、転送、阻止できるようになります。"</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"テキストメッセージ(SMS)の受信"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"SMSメッセージの受信と処理をアプリに許可します。これにより、アプリが端末に届いたメッセージを表示することなく監視または削除できるようになります。"</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"テキストメッセージ(MMS)の受信"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"作業中のウィンドウの内容を取得することをアプリに許可します。この許可を悪意のあるアプリに利用されると、ウィンドウの内容全体が取得されてパスワード以外のテキストがすべてチェックされる恐れがあります。"</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"ユーザー補助を一時的に有効にする"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"この端末のユーザー補助を一時的に有効にすることをアプリに許可します。悪意のあるアプリはユーザーの同意を得ずにユーザー補助を有効にする場合があります。"</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"ウィンドウトークンの取得"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"ウィンドウトークンの取得をアプリに許可します。この許可を悪意のあるアプリに利用されると、システムを装ったアプリケーションウィンドウで不正な操作が実行される恐れがあります。"</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"フレーム統計情報の取得"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"フレーム統計情報の収集をアプリに許可します。この許可を悪意のあるアプリに利用されると、他のアプリからウィンドウのフレーム統計情報を監視される恐れがあります。"</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"ウィンドウ情報の取得"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"ウィンドウマネージャからウィンドウに関する情報を取得することをアプリに許可します。悪意のあるアプリが内部システムの利用を目的に情報を取得する恐れがあります。"</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"イベントのフィルタリング"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"すべてのユーザーイベントが送られる前にストリームをフィルタリングする入力フィルタを登録することをアプリに許可します。悪意のあるアプリがユーザーの操作なしでシステムUIを制御する恐れがあります。"</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"表示の拡大"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"表示内容を拡大することをアプリに許可します。悪意のあるアプリが、端末を使用できなくなるように表示内容を変換する恐れがあります。"</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"部分的にシャットダウンする"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"アクティビティマネージャをシャットダウン状態にします。完全なシャットダウンは実行しません。"</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"アプリケーションの切り替えを禁止する"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"SMSメッセージの受信通知の配信をアプリに許可します。この許可を悪意のあるアプリケーションに利用されると、受信SMSメッセージが偽造される恐れがあります。"</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH受信ブロードキャストの送信"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"WAP PUSHメッセージの受信通知を配信することをアプリに許可します。この許可を悪意のあるアプリに利用されると、MMSメッセージの受信確認が偽造されたりウェブページのコンテンツが悪意のあるコンテンツに密かに置き換えられたりする恐れがあります。"</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ネットワークスコアのブロードキャスト送信"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"ネットワークのスコアリングが必要であるという通知をブロードキャスト送信することをアプリに許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"実行中のプロセスの数を制限"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"実行するプロセスの上限数を制御することをアプリに許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"バックグラウンドのアプリの強制終了"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"VPNサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"壁紙にバインド"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"壁紙のトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"リモートディスプレイへのバインド"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"テレビの入力のトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"端末の管理者の追加または削除"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"有効な端末の管理者を追加または削除することを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"画面の向きの変更"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"インストール済みのメディアデコーダーを使用して再生用にデコードすることをアプリに許可します。"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"信頼できる認証情報の管理"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"CA証明書を信頼できる認証情報としてインストールしたりアンインストールしたりすることをアプリに許可します。"</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"アイドル状態でのアプリの実行"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"この権限により、端末が使用中でない場合でもAndroidシステムがバックグラウンドでアプリを実行できるようになります。"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"アイドルサービスへのバインディング"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"この許可により、Androidシステムはアプリのアイドルサービスにバインディングできるようになります。"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"diagが所有するリソースの読み書き"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"diagグループが所有するリソース(/dev内のファイルなど)の読み書きをアプリに許可します。許可すると、システムの安定性とセキュリティに影響が生じる可能性があります。メーカー/通信事業者によるハードウェア固有の診断以外には使用しないでください。"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"アプリのコンポーネントの有効/無効化"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"端末に保存されている個人のプロフィール情報(名前、連絡先情報など)の読み取りをアプリに許可します。これにより、アプリがユーザーの身元を特定できるようになり、プロフィール情報を第三者に転送する可能性があります。"</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"自分の連絡先カードの変更"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"端末に保存されている個人のプロフィール情報(名前、連絡先情報など)の変更と追加をアプリに許可します。これにより、アプリがユーザーの身元を特定できるようになり、プロフィール情報を第三者に転送する可能性があります。"</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"ボディーセンサー(心拍数モニターなど)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"心拍数など、体内の変化の測定に使用するセンサーからのデータにアクセスすることをアプリに許可します。"</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"ソーシャルストリームを読む"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"あなたや友だちのソーシャル更新情報へのアクセスと同期をアプリに許可します。情報の共有は慎重に行ってください。これを許可すると、あなたと友だちがソーシャルネットワークで行ったやり取りを、機密性に関係なくアプリから読み取ることができるようになります。注: この許可は、一部のソーシャルネットワークでは適用されない場合があります。"</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"ソーシャルストリームに書く"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"端末の電話機能の制御をアプリに許可します。許可すると、アプリではユーザーに通知なくネットワークの切り替え、無線通信のON/OFFなどを行えるようになります。"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"端末のステータスとIDの読み取り"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"端末の電話機能へのアクセスをアプリに許可します。これにより、電話番号、端末ID、通話中かどうか、通話相手の電話番号をアプリから特定できるようになります。"</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"正確な電話ステータスの読み取り"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"正確な電話ステータスにアクセスすることをアプリに許可します。これにより、実際の発信ステータス(発信がアクティブか、バックグラウンドか)、発信エラー、正確なデータ接続ステータス、データ接続エラーをアプリから特定できるようになります。"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"タブレットのスリープを無効化"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"端末のスリープを無効にする"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"タブレットのスリープを無効にすることをアプリに許可します。"</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX状態の変更"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"タブレットのWiMAXネットワークへの接続と切断をアプリに許可します。"</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"携帯端末のWiMAXネットワークへの接続と切断をアプリに許可します。"</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ネットワークスコア"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"ネットワークを順位付けし、タブレットでのネットワークの優先順位に反映することをアプリに許可します。"</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"ネットワークを順位付けし、携帯電話でのネットワークの優先順位に反映することをアプリに許可します。"</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"Bluetoothデバイスのペアの設定"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"タブレットのBluetooth設定を表示すること、ペアの端末に接続すること/ペアの端末からの接続を受け入れることをアプリに許可します。"</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"携帯端末のBluetooth設定を表示すること、ペアの端末に接続すること/ペアの端末からの接続を受け入れることをアプリに許可します。"</string>
@@ -703,18 +683,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"通知(他のアプリから投稿されたものも含む)を取得、調査、クリアすることをアプリに許可します。"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"通知リスナーサービスにバインド"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"通知リスナーサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"携帯通信会社が提供する設定アプリの呼び出し"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"携帯通信会社が提供する設定アプリを呼び出すことを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ネットワーク状況監視のためのリッスン"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"ネットワーク状況を監視するためリッスンすることをアプリに許可します。通常のアプリで必要になることはありません。"</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"入力デバイスの調整を変更"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"タッチスクリーンの調整パラメータの変更をアプリに許可します。通常のアプリでは必要ありません。"</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM証明書へのアクセス権"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"DRM証明書のプロビジョニングと使用をアプリに許可します。通常のアプリでは不要です。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"パスワードルールの設定"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"画面ロック解除パスワードの長さと使用できる文字を制御します。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"画面ロック解除試行の監視"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"キーガードセキュアストレージへのアクセスをアプリに許可する"</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>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"信頼できるエージェントサービスへのバインド"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"信頼できるエージェントサービスにバインドすることをアプリに許可します。"</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"アップデートと回復システムへのアクセス"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"回復システムとシステムアップデートへのアクセスをアプリに許可します。"</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"ダブルタップでズームコントロール"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"壁紙"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"壁紙を変更"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"通知リスナー"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPNが有効になりました"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPNが<xliff:g id="APP">%s</xliff:g>により有効化されました"</string>
     <string name="vpn_text" msgid="3011306607126450322">"タップしてネットワークを管理します。"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index a500b8e..c82b606 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"სინქრონიზაცია"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"<xliff:g id="CONTENT_TYPE">%s</xliff:g>-ის ძალიან ბევრი წაშლილები."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"ტაბლეტის მეხსიერება გავსებულია. ადგილის გასათავისუფლებლად წაშალეთ ფაილების ნაწილი."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"საათის მეხსიერება გავსებულია. ადგილის გასათავისუფლებლად წაშალეთ ფაილების ნაწილი."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"ტელეფონის მეხსიერება გავსებულია. ადგილის გასათავისუფლებლად წაშალეთ ფაილების ნაწილი."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"შესაძლოა ქსელი მონიტორინგის ქვეშ იმყოფება"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"უცნობი მესამე მხარის მიერ"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"ზარი ჩართულია"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"გამორთვა…"</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"თქვენი ტაბლეტი გაითიშება."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"თქვენი საათი გაითიშება."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"თქვენი ტელეფონი გაითიშება."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"გსურთ გამორთვა?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"უსაფრთხო რეჟიმის ჩატვირთვა"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"თვითმფრინავის რეჟიმი"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"უსაფრთხო რეჟიმი"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-ის სისტემა"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"მალსახმობების წაშლა"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"მთავარ ეკრანზე აპლიკაციისთვის მალსახმობების დამოუკიდებლად წაშლის უფლების მიცემა."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"გამავალი ზარების გადამისამართება"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"საშუალებას აძლევს აპს გამავალი ზარის დროს დაინახონ ზარის მიმღების ნომერი, ზარის სხვა მისამართზე გადამისამართებით ან ზარის საერთოდ შეწყვეტის საშუალებით."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"აპს შეეძლება გამავალი ზარების დამუშავება და ასაკრეფი ნომრის შეცვლა. ეს უფლება აპს აძლევს შესაძლებლობას აკონტროლოს, გადაამისამართოს ან აღკვეთოს გამავალი ზარები."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"ტექსტური შეტყობინებების (SMS) მიღება"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"აპს შეეძლება SMS შეტყობინებების მიღება და დამუშავება. ეს ნიშნავს, რომ აპს შეეძლება თქვენ მოწყობილობაზე გამოგზავნილი შეტყობინებების მონიტორინგი და მათი წაშლა თქვენთვის ჩვენების გარეშე."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"ტექსტური შეტყობინებების (MMS) მიღება"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"აპს შეეძლება აქტიური ფანჯრიდან კონტენტის მოძიება. მავნე აპებს შეუძლიათ ფანჯრის სრული კონტენტის მოძიება და ყველა ტექსტის წაკითხვა პაროლების გარდა."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"მარტივი წვდომის დროებით გააქტიურება"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"აპს შეეძლება მოწყობილობაზე გამარტივებული რეჟიმის ჩართვა. მავნე აპებს შეეძლებათ ამ რეჟიმის ჩართვა მომხმარებლის გაფრთხილების გარეშე."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"ფანჯრის ჟეტონის მოძიება"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"ნებას რთავს აპლიკაციას მოიძიოს ფანჯრის ჟეტონი. მავნე აპებს შეუძლია აპლიკაციის ფანჯარასთან არაავტორიზებული ინტერაქცია განახორციელოს და თავი სისტემად წარმოაჩინოს."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"ჩარჩოს სტატისტიკის მოძიება"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"ნებას რთავს აპლიკაციას შეაგროვოს ჩარჩოს სტატისტიკა. მავნე აპებმა შესაძლოა ფანჯრების ჩარჩოს სტატისტიკის მონიტორინგი განახორციელოს სხვა აპებიდან."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"ფანჯრის ინფორმაციის მოძიება"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"აპს შეეძლება ფანჯრების მენეჯერის მეშვეობით ფანჯრების შესახებ ინფორმაციის მოპოვება. მავნე აპლიკაციებს შეეძლებათ ისეთი ინფორმაციის მოპოვება, რომელიც შიდა სისტემური მოხმარებისთვის არის განკუთვნილი."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"ღონისძიებების გაფილტვრა"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"აპლიკაციას შეეძლება რეგისტრაცია შეტანის ფილტრებისა, რომლებიც ასუფთავებენ მომხმარებლის ღონისძიების ყველა დინებას. მავნე აპმა შესაძლოა ეს ფუნქცია სისტემის UI კონტროლისთვის გამოიყენოს, მომხმარებლის ინტერვენციის გარეშე."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"ეკრანის გადიდება"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"აპლიკაციას შეეძლება, შეცვალოს დისპლეის კონტენტი. მავნე აპებმა შეიძლება იმგვარად გარდაქმნან დისპლეის კონტენტი, რომ  მოწყობილობა გამოუსადეგარი გახდეს."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"ნაწილობრივი გამორთვა"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"აქტივობების მენეჯერს გათიშვის რეჟიმში აყენებს. სრულ გათიშვას არ ახორციელებს."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"აპის გადართვებისგან დაცვა"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"აპს საშუალებას აძლევს გააგზავნოს შეტყობინება SMS შეტყობინების მიღების თაობაზე. მავნე აპლიკაციებში ეს ფუნქცია შეიძლება გამოყენებული იქნას SMS შეტყობინებების მიღების იმიტაციიისათვის."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH-ით მიღებული სამაუწყებლო შეტყობინების გაგზავნა"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"აპს შეეძლება, გაგზავნოს შეტყობინება WAP PUSH შეტყობინების მიღების თაობაზე. მავნე აპებმა ეს შეიძლება გამოიყენონ MMS შეტყობინების მიღების გასაყალბებლად ან ნებისმიერი ვებგვერდის კონტენტის სახიფათო ვარიანტებით ჩუმად ჩასანაცვლებლად."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ქსელის შეფასებების მაუწყებლობის გაგზავნა"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"აპს ნებას რთავს გადასცეს შეტყობინება, რომ ქსელები შეფასებას საჭიროებს. ჩვეულებრივ აპებს ეს არასოდეს ჭირდება."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"მიმდინარე პროცესების რაოდენობის ლიმიტი"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"აპს შეეძლება, გააკონტროლოს მიმდინარე პროცესების მაქსიმალური რაოდენობა. ჩვეულებრივ აპებში არასდროს არის საჭირო."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"უკანა ფონის აპის იძულებით დახურვა"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"აპს შეეძლება Vpn სერვისის ზედა დონის ინტერფეისთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"ფონზე მიჭედება"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"მფლობელს შეეძლება ფონის ზედა დონის ინტერფეისთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"დისტანციურ მონიტორზე მიბმა"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"აპს შეეძლება TV შეყვანის ზედა დონის ინტერფეისთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"მოწყობილობის ადმინისტრატორს დამატება ან ამოშლა"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"საშუალებას აძლევს მფლობელს დაამატოს ან ამოშალოს მოწყობილობის აქტიური ადმინისტრატორები. ჩვეულებრივ აპებს, ალბათ, არასოდეს დაჭირდება"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"ეკრანის ორიენტაციის შეცვლა"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"აპს დასაკრავად შეეძლება გამოიყენოს ნებისმიერი დაყენებული მედია დეკოდერი."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"სანდო მტკიცებულებების მართვა"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"აპისთვის ნების დართვა, მოახდინოს CA სერტიფიკატების სანდო მტკიცებულებებად ინსტალაცია და დეინსტალაცია."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"უქმე მდგომარეობისას აპლიკაციის გაშვება"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"ეს უფლება Android-ის სისტემას უფლებას ანიჭებს ფონურად გაუშვას აპლიკაცია, როდესაც მოწყობილობა არ გამოიყენება."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"უქმე სერვისებზე მიბმა"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"ეს უფლება საშუალებას აძლევს Android-ის სისტემას, განახორციელოს აპლიკაციის უქმე სერვისების მიბმა."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"სისტემის დიაგნოსტიკის რესურსებში წაკითხვა/ჩაწერის უფლება"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"აპს შეეძლება, წაიკითხოს ან ჩაწეროს ნებისმიერ რესურსში, რომელიც დიაგნოსტიკის ჯგუფს ეკუთვნის, მაგალითად, ფაილები /dev-ში. ამან შესაძლოა იმოქმედოს სისტემის სტაბილურობასა და უსაფრთხოებაზე. მისი გამოყენება მხოლოდ მწარმოებლის ან ოპერატორის მიერ ტექნიკის სპეციფიკური დიაგნოსტიკისთვის უნდა მოხდეს."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"აპის კომპონენტების ჩართვა ან გამორთვა"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"აპს შეეძლება მოწყობილობაზე შენახული პირადი პროფილის ინფორმაციის წაკითხვა, მაგალითად, თქვენი სახელისა და საკონტაქტო ინფორმაციის. ეს ნიშნავს, რომ აპს შეუძლია თქვენი იდენტიფიცირება და თქვენი პირადი ინფორმაციის სხვებისთვის გაგზავნა."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"თქვენი საკონტაქტო ინფორმაციის შეცვლა"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"აპს შეეძლება მოწყობილობაზე შენახული პირადი პროფილის ინფორმაციის შეცვლა ან დამატება, მაგალითად, თქვენი სახელისა და საკონტაქტო ინფორმაციის. ეს ნიშნავს, რომ აპს შეუძლია თქვენი იდენტიფიცირება და თქვენი პირადი ინფორმაციის სხვებისთვის გაგზავნა."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"სხეულის სენსორები (მაგ. გულისცემის მონიტორები)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"საშუალებას აძლევს აპს იქონიოს წვდომა თქვენ მიერ გამოყენებული სენსორებიდან, რათა გაზომოთ, რა ხდება თქვენ სხეულში, მაგ. გულის ცემის რითმი."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"სოციალური ნაკადის წაკითხვა"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"აპს შეეძლება თქვენი და თქვენი მეგობრების სოციალური განახლებებთან წვდომა და სინქრონიზაცია. ინფორმაციის გაზიარებისას იყავით ფრთხიად - აპს ექნება შესაძლებლობა, რომ წაიკითხოს სოციალურ ქსელებში კომუნიკაცია თქვენსა და თქვენს მეგობრებს შორის კონფიდენციალურობის მიუხედავად. შენიშვნა: ეს უფლება შესაძლოა ვერ იყოს გამოყენებული ყველა სოციალურ ქსელში."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"თქვენს სოციალურ მაუწყებლობაზე დაწერა"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"აპს შეეძლება აკონტროლოს მოწყობილობაზე ტელეფონის ფუნქციები. ამ უფლების მქონე აპს შეუძლია ქსელების გადართვა, ტელეფონის რადიოს ჩართვა და გამორთვა, მომხმარებლისათვის შეტყობინების გარეშე."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"ტელეფონის სტატუსისა და იდენტობის წაკითხვა"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"აპს შეეძლება ჰქონდეს წვდომა მოწყობილობის სატელეფონო ფუნქციებზე. აპმა მსგავსი უფლებით შეძლებს დაადგინოს ტელეფონის ნომერი, მისი სერიული გამოცემა, აქტიური ზარი, დაკავშირებული ნომერი და მსგავსი."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"ტელეფონის ზუსტი მდგომარეობების დადგენა"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"ანიჭებს აპს ტელეფონის ზუსტ მდგომარეობაზე წვდომას. ეს უფლება საშუალებას აძლევს აპს შეიტყოს ინფორმაცია ზარის რეალურ სტატუსზე, აქტიურია ზარი თუ უკანა ფონზეა, ვერ განხორციელებული ზარები, მონაცემთა გადაცემის ზუსტი სტატუსი და ვერ განხორციელებული მონაცემთა კავშირები."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"დაიცავით ტაბლეტი დაძინებისგან"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ტელეფონის ძილის რეჟიმში გადასვლის აღკვეთა"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"აპს შეეძლება ხელი შეუშალოს ტაბლეტის დაძინებას."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX მდგომარეობის შეცვლა"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"აპს შეეძლება, დაუკავშიროს და გამოაერთოს ტაბლეტი WiMAX ქსელებიდან."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"აპს შეეძლება, დაუკავშიროს და გამოაერთოს ტელეფონი WiMAX ქსელებიდან."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ქსელების შეფასება"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"აპს ნებას რთავს შეაფასოს ქსელები და იქონიოს ზეგავლენა, თუ რომელი ქსელი ამჯობინოს ტაბლეტმა."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"აპს ნებას რთავს შეაფასოს ქსელები და იქონიოს ზეგავლენა, თუ რომელი ქსელი ამჯობინოს ტელეფონმა."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"Bluetooth მოწყობილობებთან დაწყვილება"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"აპს შეეძლება, ნახოს Bluetooth-ის კონფიგურაცია ტაბლეტზე, შექმნას და მიიღოს კავშირები დაწყვილებულ მოწყობილობებთან."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"აპს შეეძლება, ნახოს Bluetooth-ის კონფიგურაცია ტელეფონზე და შექმნას და მიიღოს კავშირები დაწყვილებულ მოწყობილობებთან."</string>
@@ -703,18 +683,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"აპს შეეძლება მოიძიოს, გამოიკვლიოს და წაშალოს შეტყობინებები, მათ შორის სხვა აპების მიერ გამოქვეყნებული."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"შეტყობინებების მოსმენის სერვისთან დაკავშირება"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"მფლობელს შეეძლება შეტყობინებების მსმენლის სერვისის ზედა დონის ინტერფეისთან დაკავშირება. არ უნდა მოხდეს მისი გამოყენება ჩვეუელებრივი აპებისთვის.ფ"</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ოპერატორის მიერ მოწოდებული კოფიგურაციის აპის გამოხმობა"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"საშუალებას აძლევს მფლობელს გამოიწვიოს ოპერატორის მიერ მოწოდებული კონფიგურაციის აპი. ჩვეულებრივ აპს ეს წესით არასოდეს არ უნდა დაჭირდეს."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"განხორციელდეს ქსელის მდგომარეობის მონიტორინგი"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"საშუალებას აძლევს აპლიკაციებს განახორციელოს ქსელის მდგომარეობის მონიტორინგი. ეს ფუნქცია ჩვეულებრივ აპებს არ ჭირდება."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"შეყვანის მოწყობილობის კალიბრაციის ცვლილება"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"საშუალებას აძლევს აპს შეცვალოს სენსორული ეკრანის კალიბრაციის პარამეტრები. ჩვეულებრივ აპებს წესით არ უნდა დაჭირდეს."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM სერთიფიკატებზე წვდომა"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"საშუალებას აძლევს აპლიკაციას დანერგოს და გამოიყენოს DRM სერთიფიკატები. ეს უფლება ჩვეულებრივ აპებს არ ჭირდება."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"პაროლის წესების დაყენება"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"გააკონტროლეთ ეკრანის განბლოკვის პაროლში დაშვებული სიმბოლოები და მისი სიგრძე."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"ეკრანის განბლოკვის მცდელობების გაკონტროლება"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"აპლიკაციას ღილაკების დამცავის უსაფრთხო საცავზე წვდომის უფლება ექნება."</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>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"სანდო აგენტის სერვისზე მიმაგრება."</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"საშუალებას აძლევს აპლიკაციას მიემაგროს სანდო აგენტის სერვისს."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"განახლებასთან და აღდგენის სისტემასთან ინტერაქცია"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"საშუალებას აძლევს აპლიკაციას მოახდინოს აღდგენის სისტემასთან და სისტემის განახლებასთან ინტერაქცია."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"მასშტაბის მართვისთვის შეეხეთ ორჯერ."</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"ფონი"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"ფონის შეცვლა"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"შეტყობინებების მსმენელი"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN გააქტიურებულია"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN გააქტიურებულია <xliff:g id="APP">%s</xliff:g>-ის მიერ"</string>
     <string name="vpn_text" msgid="3011306607126450322">"შეეხეთ ქსელის სამართავად."</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 43199fa..bee6c21 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -27,6 +27,17 @@
     <string name="terabyteShort" msgid="231613018159186962">"តេរ៉ាបៃ"</string>
     <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
     <string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
+    <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> ថ្ងៃ"</string>
+    <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> ថ្ងៃ <xliff:g id="HOURS">%2$d</xliff:g> ម៉ោង"</string>
+    <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> ថ្ងៃ <xliff:g id="HOURS">%2$d</xliff:g> ម៉ោង"</string>
+    <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> ម៉ោង"</string>
+    <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> ម៉ោង <xliff:g id="MINUTES">%2$d</xliff:g> នាទី"</string>
+    <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> ម៉ោង <xliff:g id="MINUTES">%2$d</xliff:g> នាទី"</string>
+    <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> នាទី"</string>
+    <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g>នាទី <xliff:g id="SECONDS">%2$d</xliff:g>វិនាទី"</string>
+    <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g>នាទី <xliff:g id="SECONDS">%2$d</xliff:g>វិនាទី"</string>
+    <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> វិនាទី"</string>
+    <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> វិនាទី"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;គ្មាន​ចំណង​ជើង&gt;"</string>
     <string name="ellipsis" msgid="7899829516048813237">"…"</string>
     <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -57,7 +68,7 @@
   </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
-    <string name="ClipMmi" msgid="6952821216480289285">"លេខ​សម្គាល់​អ្នក​ហៅ​​ចូល"</string>
+    <string name="ClipMmi" msgid="6952821216480289285">"លេខ​សម្គាល់​អ្នក​ហៅ​​ចូល​"</string>
     <string name="ClirMmi" msgid="7784673673446833091">"លេខ​សម្គាល់​អ្នក​ហៅ​ចេញ"</string>
     <string name="CfMmi" msgid="5123218989141573515">"បញ្ជូន​ការ​ហៅ​បន្ត"</string>
     <string name="CwMmi" msgid="9129678056795016867">"រង់ចាំ​ការ​ហៅ"</string>
@@ -114,7 +125,7 @@
     <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> ៖ មិន​បាន​បញ្ជូន​បន្ត"</string>
     <string name="fcComplete" msgid="3118848230966886575">"កូដ​លក្ខណៈ​ពេញលេញ។"</string>
     <string name="fcError" msgid="3327560126588500777">"បញ្ហា​ការ​តភ្ជាប់​ ឬ​កូដ​លក្ខណៈ​​​មិន​ត្រឹមត្រូវ​។"</string>
-    <string name="httpErrorOk" msgid="1191919378083472204">"យល់​ព្រម"</string>
+    <string name="httpErrorOk" msgid="1191919378083472204">"យល់​ព្រម​"</string>
     <string name="httpError" msgid="7956392511146698522">"មាន​កំហុស​បណ្ដាញ។"</string>
     <string name="httpErrorLookup" msgid="4711687456111963163">"រក​មិន​ឃើញ URL ។"</string>
     <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"គ្រោងការណ៍​ផ្ទៀងផ្ទាត់​តំបន់បណ្ដាញ​មិន​ត្រូវ​បាន​គាំទ្រ។"</string>
@@ -172,17 +183,19 @@
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"បើក​សំឡេង"</string>
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"ពេល​ជិះ​យន្តហោះ"</string>
     <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_actions_airplane_mode_off_status" msgid="5075070442854490296">"បាន​បិទ​របៀបពេលជិះ​យន្តហោះ​"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"ការ​កំណត់"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"របៀប​​​សុវត្ថិភាព"</string>
     <string name="android_system_label" msgid="6577375335728551336">"ប្រព័ន្ធ​​ Android"</string>
+    <string name="user_owner_label" msgid="2804351898001038951">"ផ្ទាល់ខ្លួន"</string>
+    <string name="managed_profile_label" msgid="6260850669674791528">"កន្លែង​ធ្វើ​ការ"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"សេវាកម្ម​ដែល​កាត់​លុយ​របស់​អ្នក"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ធ្វើ​អ្វី​ដែល​អាច​កាត់​លុយ​របស់​អ្នក។"</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"សារ​របស់​អ្នក"</string>
     <string name="permgroupdesc_messages" msgid="7821999071003699236">"អាន និង​សរសេរ​សារ SMS, អ៊ីមែល និង​សារ​ផ្សេងៗ​ទៀត​របស់​អ្នក។"</string>
     <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"ព័ត៌មាន​ផ្ទាល់ខ្លួន​របស់​អ្នក"</string>
-    <string name="permgroupdesc_personalInfo" msgid="8426453129788861338">"ចូល​ដំណើរការ​ព័ត៌មាន​ដោយ​ផ្ទាល់​អំពី​អ្នក​ ដែល​បា​ន​រក្សាទុក​ក្នុង​កាត​ទំនាក់ទំនង​របស់​អ្នក។"</string>
+    <string name="permgroupdesc_personalInfo" msgid="8426453129788861338">"ចូល​ដំណើរការ​ព័ត៌មាន​ដោយ​ផ្ទាល់​អំពី​អ្នក​ ដែល​បា​ន​រក្សាទុក​ក្នុង​កាត​ទំនាក់ទំនង​របស់​អ្នក។​"</string>
     <string name="permgrouplab_socialInfo" msgid="5799096623412043791">"ព័ត៌មាន​សង្គម​របស់​អ្នក"</string>
     <string name="permgroupdesc_socialInfo" msgid="7129842457611643493">"ចូល​ដំណើរការ​ព័ត៌មាន​ដោយ​ផ្ទាល់​អំពី​ទំនាក់ទំនង និង​ការ​ភ្ជាប់​សង្គម​របស់​អ្នក។"</string>
     <string name="permgrouplab_location" msgid="635149742436692049">"ទីតាំង​របស់​អ្នក"</string>
@@ -373,7 +386,7 @@
     <string name="permdesc_readInputState" msgid="8387754901688728043">"ឲ្យ​កម្មវិធី​មើល​គ្រាប់​ចុច​ដែល​អ្នក​ចុច​ពេល​មាន​អន្តរកម្ម​ជា​មួយ​កម្មវិធី​ផ្សេង (ដូចជា បញ្ចូល​ពាក្យ​សម្ងាត់)។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"ចង​ទៅ​វិធីសាស្ត្រ​បញ្ចូល"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"ឲ្យ​ម្ចាស់​ចង​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​វិធី​សាស្ត្រ​បញ្ចូល។ មិន​គួរ​​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
-    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"ចង​សេវា​កម្ម​ភាព​មធ្យោបាយ​ងាយស្រួល"</string>
+    <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"ចង​សេវា​កម្ម​ភាព​មធ្យោបាយ​ងាយស្រួល​"</string>
     <string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"ឲ្យ​​ម្ចាស់​ចង​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​សេវាកម្ម​ភាព​ងាយស្រួល។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindPrintService" msgid="8462815179572748761">"ចង​សេវាកម្ម​​បោះពុម្ព"</string>
     <string name="permdesc_bindPrintService" msgid="7960067623209111135">"ឲ្យ​ម្ចាស់​ចង​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​សេវាកម្ម​ធាតុ​ក្រាហ្វិក។ មិន​គួរ​​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
@@ -387,13 +400,11 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"ឲ្យ​ម្ចាស់​ចង​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​សេវាកម្ម Vpn ។​ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"ចង​ទៅ​ផ្ទាំង​រូបភាព"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ឲ្យ​ម្ចាស់​ចង​ចំណុចប្រទាក់​កម្រិត​កំពូល​នៃ​ផ្ទាំង​រូបភាព។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
+    <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"ភ្ជាប់​ទៅ​​អ្នក​សហការ​សំឡេង"</string>
+    <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​ភ្ជាប់​ទៅ​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​​របស់​សេវាកម្ម​អន្តរកម្ម​សំឡេង។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ភ្ជាប់​ទៅ​ការ​បង្ហាញ​ពី​ចម្ងាយ"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​ភ្ជាប់​​ទៅ​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​ការ​បង្ហាញ​ពី​ចម្ងាយ។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
-    <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ចង​សេវា​កម្ម​ធាតុ​ក្រាហ្វិក"</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>
@@ -401,7 +412,7 @@
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ឲ្យ​ម្ចាស់​ផ្ញើ​គោលបំណង​​ទៅ​អ្នក​គ្រប់គ្រង​ឧបករណ៍។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"ភ្ជាប់​ទៅ​ការ​បញ្ចូល​ទូរទស្សន៍"</string>
     <string name="permdesc_bindTvInput" msgid="2371008331852001924">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​ភ្ជាប់​ទៅ​ចំណុចប្រទាក់​កម្រិត​ខ្ពស់​នៃ​ការ​បញ្ចូល​ទូរទស្សន៍។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
-    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"បន្ថែម​ ឬ​លុប​កម្មវិធី​គ្រប់គ្រង​​​ឧបករណ៍"</string>
+    <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"បន្ថែម​ ឬ​លុប​កម្មវិធី​គ្រប់គ្រង​​​ឧបករណ៍​​"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"អនុញ្ញាត​​​ឲ្យ​ម្ចាស់​​​បន្ថែម​ ឬ​លុប​កម្មវិធី​គ្រប់គ្រង​ឧបករណ៍​សកម្ម​ចេញ​។ មិន​គួរ​ប្រើ​សម្រាប់​កម្មវិធី​​ធម្មតា​ទេ​។"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"ប្ដូរ​ទិស​អេក្រង់"</string>
     <string name="permdesc_setOrientation" msgid="3046126619316671476">"ឲ្យ​កម្មវិធី​ប្ដូរ​ការ​បង្វិល​អេក្រង់​នៅ​ពេល​ណា​មួយ។ មិន​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
@@ -413,9 +424,9 @@
     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"ឲ្យ​កម្មវិធី​ស្នើ​​សញ្ញា​ដែល​បាន​ផ្ដល់​ត្រូវ​ផ្ញើ​ទៅ​ដំណើរការ​ស្ថិតស្ថេរ​​ទាំង​អស់។"</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"ធ្វើ​ឲ្យ​កម្មវិធី​ដំណើរការ​ជា​និច្ច"</string>
     <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"ឲ្យ​កម្មវិធី​ធ្វើជា​ផ្នែក​​ស្ថិតស្ថេរ​ដោយ​ខ្លួន​ឯង​ក្នុង​អង្គ​ចងចាំ។ វា​អាច​កំណត់​អង្គ​ចងចាំ​ដែល​អាច​ប្រើ​បាន​ចំពោះ​កម្មវិធី​ផ្សេងៗ​ ដោយ​ធ្វើឲ្យ​កុំព្យូទ័រ​បន្ទះ​យឺត។"</string>
-    <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"ឲ្យ​កម្មវិធី ធ្វើជា​ផ្នែក​អចិន្ត្រៃយ៍​នៃ​ខ្លួន​ក្នុង​អង្គ​ចងចាំ។ វា​អាច​កម្រិត​អង្គ​ចងចាំ​អាច​ប្រើ​បាន​ ដើម្បី​ធ្វើ​ឲ្យ​កម្មវិធី​ផ្សេង​ធ្វើ​ឲ្យ​ទូរស័ព្ទ​របស់​អ្នក​យឺត។"</string>
+    <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"ឲ្យ​កម្មវិធី ធ្វើជា​ផ្នែក​អចិន្ត្រៃយ៍​នៃ​ខ្លួន​ក្នុង​អង្គ​ចងចាំ។ វា​អាច​កម្រិត​អង្គ​ចងចាំ​អាច​ប្រើ​បាន​ ដើម្បី​ធ្វើ​ឲ្យ​កម្មវិធី​ផ្សេង​ធ្វើ​ឲ្យ​ទូរស័ព្ទ​របស់​អ្នក​យឺត។​"</string>
     <string name="permlab_deletePackages" msgid="184385129537705938">"លុប​កម្មវិធី"</string>
-    <string name="permdesc_deletePackages" msgid="7411480275167205081">"ឲ្យ​កម្មវិធី​លុប​កញ្ចប់ Android ។ កម្មវិធី​ព្យាបាទ​អាច​ប្រើ​វា ដើម្បី​លុប​កម្មវិធី​សំខាន់​ៗ។"</string>
+    <string name="permdesc_deletePackages" msgid="7411480275167205081">"ឲ្យ​កម្មវិធី​លុប​កញ្ចប់ Android ។ កម្មវិធី​ព្យាបាទ​អាច​ប្រើ​វា ដើម្បី​លុប​កម្មវិធី​សំខាន់​ៗ។ ​"</string>
     <string name="permlab_clearAppUserData" msgid="274109191845842756">"លុប​ទិន្នន័យ​របស់​​កម្មវិធី​ផ្សេង"</string>
     <string name="permdesc_clearAppUserData" msgid="4625323684125459488">"ឲ្យ​កម្មវិធី​សម្អាត​ទិន្នន័យ​អ្នក​ប្រើ។"</string>
     <string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"លុប​ឃ្លាំង​សម្ងាត់​កម្មវិធី​ផ្សេងៗ"</string>
@@ -466,7 +477,7 @@
     <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"ឲ្យ​កម្មវិធី​កែ​ទិន្នន័យ​អំពី​ទំនាក់ទំនង​របស់​អ្នក​ដែល​បាន​រក្សាទុក​ក្នុង​កុំព្យូទ័រ​បន្ទះ រួមមាន​ប្រេកង់​​ដែល​អ្នក​បាន​ហៅ អ៊ីមែល ឬ​ទាក់ទង​តាម​វិធី​ផ្សេងៗ​ជា​មួយ​ទំនាក់ទំនង​ជាក់លាក់។ សិទ្ធិ​​នេះ​អនុញ្ញាត​ឲ្យ​​​កម្មវិធី​លុប​ទិន្នន័យ​ទំនាក់ទំនង​របស់​អ្នក។"</string>
     <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"ឲ្យ​កម្មវិធី​កែ​ទិន្នន័យ​អំពី​ទំនាក់ទំនង​របស់​អ្នក​ដែល​បាន​រក្សាទុក​ក្នុង​ទូរស័ព្ទ​របស់​អ្នក រួមមាន​ប្រេកង់​ដែល​អ្នក​បាន​ហៅ អ៊ីមែល ឬ​បាន​ទាក់ទង​​តាម​វិធី​ផ្សេងៗ​ជា​មួយ​ទំនាក់​ទំនាក់​ជាក់លាក់។ សិទ្ធិ​នេះ​ឲ្យ​កម្មវិធី​លុប​ទិន្នន័យ​ទំនាក់ទំនង។"</string>
     <string name="permlab_readCallLog" msgid="3478133184624102739">"អាន​​កំណត់​ហេតុ​​​ហៅ"</string>
-    <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"ឲ្យ​កម្មវិធី​អាន​បញ្ជី​ហៅ​កុំព្យូទ័រ​បន្ទះ​របស់​អ្នក រួមមាន​ទិន្នន័យ​អំពី​ការ​ហៅ​ចូល និង​ចេញ។ សិទ្ធិ​នេះ​អនុញ្ញាត​ឲ្យ​កម្មវិធី​រក្សាទុក​ទិន្នន័យ​បញ្ជី​ហៅ​របស់​អ្នក ហើយ​កម្មវិធី​ព្យាបាទ​អាច​ចែករំលែក​ទិន្នន័យ​បញ្ជី​ហៅ​ដោយ​មិន​ឲ្យ​អ្នក​ដឹង។"</string>
+    <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"ឲ្យ​កម្មវិធី​អាន​បញ្ជី​ហៅ​កុំព្យូទ័រ​បន្ទះ​របស់​អ្នក រួមមាន​ទិន្នន័យ​អំពី​ការ​ហៅ​ចូល និង​ចេញ។ សិទ្ធិ​នេះ​អនុញ្ញាត​ឲ្យ​កម្មវិធី​រក្សាទុក​ទិន្នន័យ​បញ្ជី​ហៅ​របស់​អ្នក ហើយ​កម្មវិធី​ព្យាបាទ​អាច​ចែករំលែក​ទិន្នន័យ​បញ្ជី​ហៅ​ដោយ​មិន​ឲ្យ​អ្នក​ដឹង។​"</string>
     <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"ឲ្យ​កម្មវិធី​អាន​​​បញ្ជី​ហៅ​ទូរស័ព្ទ​របស់​អ្នក រួមមាន​ទិន្នន័យ​អំពី​ការ​ហៅ​ចូល និង​ចេញ។ សិទ្ធិ​នេះ​អនុញ្ញាត​ឲ្យ​កម្មវិធី​រក្សាទុក​ទិន្នន័យ​បញ្ជី​ហៅ​របស់​អ្នក ហើយ​កម្មវិធី​ព្យាបាទ​អាច​ចែករំលែក​ទិន្នន័យ​បញ្ជី​ហៅ​ដោយ​មិន​ឲ្យ​អ្នកដឹង។"</string>
     <string name="permlab_writeCallLog" msgid="8552045664743499354">"សរសេរ​បញ្ជី​ហៅ"</string>
     <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"ឲ្យ​កម្មវិធី​កែ​បញ្ជី​ហៅ​កុំព្យូទ័រ​បន្ទះ​របស់​អ្នក​រួមមាន​ទិន្នន័យ​អំពី​ការ​ហៅ​ចូល និង​ចេញ។​កម្មវិធី​ព្យាបាទ​អាច​ប្រើ​វា ដើម្បី​លុប ឬ​កែ​បញ្ជី​ហៅ​របស់​អ្នក។"</string>
@@ -600,7 +611,7 @@
     <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"ឲ្យ​កម្មវិធី​កំណត់​ជំនួយ​ទំហំ​ផ្ទាំង​រូបភាព​ប្រព័ន្ធ។"</string>
     <string name="permlab_masterClear" msgid="2315750423139697397">"កំណត់​ប្រព័ន្ធ​ទៅ​លំនាំដើម​រោងចក្រ​ឡើងវិញ"</string>
     <string name="permdesc_masterClear" msgid="3665380492633910226">"ឲ្យ​កម្មវិធី​កំណត់​ប្រព័ន្ធ​​ដូច​ការ​កំណត់​ចេញ​ពី​រោងចក្រ​ឡើងវិញ​ពេញលេញ ដោយ​លុប​ទិន្នន័យ ការ​កំណត់​រចនាសម្ព័ន្ធ និង​កម្មវិធី​បាន​ដំឡើង។"</string>
-    <string name="permlab_setTime" msgid="2021614829591775646">"កំណត់​​ម៉ោង"</string>
+    <string name="permlab_setTime" msgid="2021614829591775646">"កំណត់​​ម៉ោង​"</string>
     <string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"ឲ្យ​កម្មវិធី​ប្ដូរ​ម៉ោង​កុំព្យូទ័រ​បន្ទះ។"</string>
     <string name="permdesc_setTime" product="default" msgid="1855702730738020">"ឲ្យ​កម្មវិធី​ប្ដូរ​ម៉ោង​ទូរស័ព្ទ។"</string>
     <string name="permlab_setTimeZone" msgid="2945079801013077340">"កំណត់​តំបន់​ពេលវេលា"</string>
@@ -703,10 +714,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"ឲ្យ​កម្មវិធី​ទៅ​យក ពិនិត្យ និង​សម្អាត​ការ​ជូន​ដំណឹង រួមមាន​​ប្រកាស​ដោយ​កម្មវិធី​ផ្សេងៗ។"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ចង​ទៅ​សេវាកម្ម​ស្ដាប់​ការ​ជូន​ដំណឹង"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ឲ្យ​ម្ចាស់​ចង​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​សេវាកម្ម​កម្មវិធី​ស្ដាប់​ការ​ជូន​ដំណឹង។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​​ទេ។"</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
+    <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ភ្ជាប់​ទៅ​សេវាកម្ម​ក្រុមហ៊ុន​ផ្ដល់​លក្ខខណ្ឌ"</string>
+    <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​ភ្ជាប់​ទៅ​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​​របស់​សេវាកម្ម​ក្រុមហ៊ុន​ផ្ដល់​លក្ខខណ្ឌ។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ដកហូត​កម្មវិធី​កំណត់​រចនាសម្ព័ន្ធ​ដែល​បាន​ផ្ដល់​ដោយ​ក្រុមហ៊ុន​បញ្ជូន"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​ដក​ហូត​កម្មវិធី​កំណត់​រចនាសម្ព័ន្ធ​ដែល​បាន​ផ្ដល់​ដោយ​ក្រុមហ៊ុន​បញ្ជូន។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"សង្កេត​មើល​លើ​លក្ខខណ្ឌ​បណ្ដាញ"</string>
@@ -768,7 +777,7 @@
   <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>
@@ -784,7 +793,7 @@
     <string name="phoneTypeHome" msgid="2570923463033985887">"ផ្ទះ"</string>
     <string name="phoneTypeMobile" msgid="6501463557754751037">"​ចល័ត"</string>
     <string name="phoneTypeWork" msgid="8863939667059911633">"កន្លែង​ធ្វើការ"</string>
-    <string name="phoneTypeFaxWork" msgid="3517792160008890912">"ទូរសារ​កន្លែង​ធ្វើការ"</string>
+    <string name="phoneTypeFaxWork" msgid="3517792160008890912">"ទូរសារ​កន្លែង​ធ្វើការ​"</string>
     <string name="phoneTypeFaxHome" msgid="2067265972322971467">"ទូរសារ​ផ្ទះ"</string>
     <string name="phoneTypePager" msgid="7582359955394921732">"ភេយ័រ"</string>
     <string name="phoneTypeOther" msgid="1544425847868765990">"ផ្សេងៗ"</string>
@@ -909,7 +918,7 @@
     <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"ព្យាយាម​លំនាំ​ច្រើន​ពេក"</string>
     <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"ដើម្បី​ដោះ​សោ ចូល​គណនី Google របស់​អ្នក។"</string>
     <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"ឈ្មោះ​អ្នក​ប្រើ (អ៊ីមែល​)"</string>
-    <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"ពាក្យសម្ងាត់"</string>
+    <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"ពាក្យសម្ងាត់​"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"ចូល"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"ឈ្មោះ​អ្នកប្រើ ឬ​ពាក្យ​សម្ងាត់​មិន​ត្រឹមត្រូវ។"</string>
     <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"ភ្លេច​ឈ្មោះ​អ្នក​ប្រើ ឬ​ពាក្យ​សម្ងាត់​របស់​អ្នក?\nមើល "<b>"google.com/accounts/recovery"</b>" ។"</string>
@@ -954,7 +963,7 @@
     <string name="factorytest_failed" msgid="5410270329114212041">"បាន​បរាជ័យ​ក្នុង​ការ​សាកល្បង​រោងចក្រ"</string>
     <string name="factorytest_not_system" msgid="4435201656767276723">"សកម្មភាព FACTORY_TEST ត្រូវ​បាន​គាំទ្រ​សម្រាប់​តែ​កញ្ចប់​បាន​ដំឡើង​ក្នុង /system/app."</string>
     <string name="factorytest_no_action" msgid="872991874799998561">"រក​មិន​ឃើញ​កញ្ចប់​ដែល​ផ្ដល់​សកម្មភាព FACTORY_TEST ។"</string>
-    <string name="factorytest_reboot" msgid="6320168203050791643">"ចាប់​ផ្ដើម​ឡើង​វិញ"</string>
+    <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>
@@ -1012,7 +1021,7 @@
     <string name="prepend_shortcut_label" msgid="2572214461676015642">"ម៉ឺនុយ +"</string>
     <string name="menu_space_shortcut_label" msgid="2410328639272162537">"ដកឃ្លា"</string>
     <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
-    <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"លុប"</string>
+    <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"លុប​"</string>
     <string name="search_go" msgid="8298016669822141719">"ស្វែងរក"</string>
     <string name="searchview_description_search" msgid="6749826639098512120">"ស្វែងរក"</string>
     <string name="searchview_description_query" msgid="5911778593125355124">"ស្វែងរក​សំណួរ"</string>
@@ -1096,18 +1105,18 @@
     <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>
-    <string name="day" msgid="8144195776058119424">"ថ្ងៃ"</string>
+    <string name="day" msgid="8144195776058119424">"ថ្ងៃ​"</string>
     <string name="days" msgid="4774547661021344602">"​ថ្ងៃ"</string>
     <string name="hour" msgid="2126771916426189481">"ម៉ោង"</string>
     <string name="hours" msgid="894424005266852993">"ម៉ោង"</string>
-    <string name="minute" msgid="9148878657703769868">"នាទី"</string>
+    <string name="minute" msgid="9148878657703769868">"នាទី​"</string>
     <string name="minutes" msgid="5646001005827034509">"នាទី"</string>
-    <string name="second" msgid="3184235808021478">"វិនាទី"</string>
+    <string name="second" msgid="3184235808021478">"វិនាទី​"</string>
     <string name="seconds" msgid="3161515347216589235">"វិនាទី"</string>
-    <string name="week" msgid="5617961537173061583">"សប្ដាហ៍"</string>
-    <string name="weeks" msgid="6509623834583944518">"សប្ដាហ៍"</string>
-    <string name="year" msgid="4001118221013892076">"ឆ្នាំ"</string>
-    <string name="years" msgid="6881577717993213522">"ឆ្នាំ"</string>
+    <string name="week" msgid="5617961537173061583">"សប្ដាហ៍​"</string>
+    <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>
@@ -1123,12 +1132,12 @@
     <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>
-    <string name="VideoView_error_button" msgid="2822238215100679592">"យល់​ព្រម"</string>
+    <string name="VideoView_error_button" msgid="2822238215100679592">"យល់​ព្រម​"</string>
     <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="noon" msgid="7245353528818587908">"រសៀល"</string>
     <string name="Noon" msgid="3342127745230013127">"រសៀល"</string>
     <string name="midnight" msgid="7166259508850457595">"កណ្ដាលអធ្រាត្រ"</string>
-    <string name="Midnight" msgid="5630806906897892201">"កណ្ដាល​អធ្រាត្រ"</string>
+    <string name="Midnight" msgid="5630806906897892201">"កណ្ដាល​អធ្រាត្រ​"</string>
     <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
     <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
     <string name="selectAll" msgid="6876518925844129331">"ជ្រើស​ទាំងអស់"</string>
@@ -1145,13 +1154,13 @@
     <string name="inputMethod" msgid="1653630062304567879">"វិធីសាស្ត្រ​បញ្ចូល"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"សកម្មភាព​អត្ថបទ"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"អស់​ទំហំ​ផ្ទុក"</string>
-    <string name="low_internal_storage_view_text" msgid="6640505817617414371">"មុខងារ​ប្រព័ន្ធ​មួយ​ចំនួន​អាច​មិន​ដំណើរការ"</string>
+    <string name="low_internal_storage_view_text" msgid="6640505817617414371">"មុខងារ​ប្រព័ន្ធ​មួយ​ចំនួន​អាច​មិន​ដំណើរការ​"</string>
     <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុង​ដំណើរការ"</string>
     <string name="app_running_notification_text" msgid="4653586947747330058">"ប៉ះ​ ដើម្បី​មើល​ព័ត៌មាន​បន្ថែម ឬ​បញ្ឈប់​កម្មវិធី។"</string>
-    <string name="ok" msgid="5970060430562524910">"យល់​ព្រម"</string>
-    <string name="cancel" msgid="6442560571259935130">"បោះ​បង់"</string>
-    <string name="yes" msgid="5362982303337969312">"យល់​ព្រម"</string>
-    <string name="no" msgid="5141531044935541497">"បោះ​បង់"</string>
+    <string name="ok" msgid="5970060430562524910">"យល់​ព្រម​"</string>
+    <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="loading" msgid="7933681260296021180">"កំពុង​ផ្ទុក..."</string>
     <string name="capital_on" msgid="1544682755514494298">"បើក"</string>
@@ -1160,7 +1169,7 @@
     <string name="whichHomeApplication" msgid="4616420172727326782">"ជ្រើស​កម្មវិធី​ដើម"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"ប្រើ​តាម​លំនាំដើម​សម្រាប់​សកម្មភាព​នេះ។"</string>
     <string name="clearDefaultHintMsg" msgid="3252584689512077257">"សម្អាត​លំនាំដើម​ក្នុង​ការកំណត់​ប្រព័ន្ធ &gt; កម្មវិធី &gt; ទាញ​យក។"</string>
-    <string name="chooseActivity" msgid="7486876147751803333">"ជ្រើស​សកម្មភាព"</string>
+    <string name="chooseActivity" msgid="7486876147751803333">"ជ្រើស​សកម្មភាព​​"</string>
     <string name="chooseUsbActivity" msgid="6894748416073583509">"ជ្រើស​កម្មវិធី​សម្រាប់​ឧបករណ៍​យូអេសប៊ី"</string>
     <string name="noApplications" msgid="2991814273936504689">"គ្មាន​កម្មវិធី​អាច​អនុវត្ត​សកម្មភាព​នេះ។"</string>
     <string name="aerr_title" msgid="1905800560317137752"></string>
@@ -1171,7 +1180,7 @@
     <string name="anr_activity_process" msgid="5776209883299089767">"សកម្មភាព <xliff:g id="ACTIVITY">%1$s</xliff:g> មិន​ឆ្លើយតប។\n\nតើ​អ្នក​ចង់​បិទ​វា?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> មិន​ឆ្លើយតប។ តើ​អ្នក​ចង់​បិទ​វា?"</string>
     <string name="anr_process" msgid="6513209874880517125">"ដំណើរការ <xliff:g id="PROCESS">%1$s</xliff:g> មិន​ឆ្លើយតប។ \n\nតើ​អ្នក​ចង់​បិទ​វា​ឬ?"</string>
-    <string name="force_close" msgid="8346072094521265605">"យល់​ព្រម"</string>
+    <string name="force_close" msgid="8346072094521265605">"យល់​ព្រម​"</string>
     <string name="report" msgid="4060218260984795706">"រាយការណ៍"</string>
     <string name="wait" msgid="7147118217226317732">"រង់ចាំ"</string>
     <string name="webpage_unresponsive" msgid="3272758351138122503">"ទំព័រ​ក្លាយ​ជា​មិន​ឆ្លើយតប។\n\nតើ​អ្នក​​ចង់​បិទ​វា?"</string>
@@ -1253,19 +1262,19 @@
     <string name="sms_short_code_details" msgid="3492025719868078457"><font fgcolor="#ffffb060">"នេះ​អាច​កាត់​លុយ"</font>" លើ​គណនី​ចល័ត​របស់​អ្នក។"</string>
     <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"វា​នឹង​គិត​ថ្លៃ​សេវាកម្ម​លើ​គណនី​ចល័ត​របស់​អ្នក។"</font></string>
     <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"ផ្ញើ"</string>
-    <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"បោះ​បង់"</string>
+    <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"បោះ​បង់​"</string>
     <string name="sms_short_code_remember_choice" msgid="5289538592272218136">"ចងចាំ​ជម្រើស​របស់​ខ្ញុំ"</string>
     <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">"បាន​ដក​ស៊ីម​កាត​ចេញ"</string>
-    <string name="sim_removed_message" msgid="2333164559970958645">"បណ្ដាញ​ចល័ត​នឹង​ប្រើ​លែង​បាន​រហូត​ដល់​អ្នក​ចាប់ផ្ដើម​ជា​មួយ​ស៊ីម​កាត​ដែល​បា​បញ្ចូល​ត្រឹមត្រូវ។"</string>
+    <string name="sim_removed_message" msgid="2333164559970958645">"បណ្ដាញ​ចល័ត​នឹង​ប្រើ​លែង​បាន​រហូត​ដល់​អ្នក​ចាប់ផ្ដើម​ជា​មួយ​ស៊ីម​កាត​ដែល​បា​បញ្ចូល​ត្រឹមត្រូវ។​"</string>
     <string name="sim_done_button" msgid="827949989369963775">"រួចរាល់"</string>
     <string name="sim_added_title" msgid="3719670512889674693">"បាន​បន្ថែម​ស៊ីម​កាត"</string>
     <string name="sim_added_message" msgid="6599945301141050216">"ចាប់ផ្ដើម​ឧបករណ៍​របស់​អ្នក​ឡើង​វិញ ដើម្បី​ចូល​ដំណើរការ​បណ្ដាញ​ចល័ត។"</string>
     <string name="sim_restart_button" msgid="4722407842815232347">"ចាប់ផ្ដើម​ឡើងវិញ"</string>
-    <string name="time_picker_dialog_title" msgid="8349362623068819295">"កំណត់​ម៉ោង"</string>
-    <string name="date_picker_dialog_title" msgid="5879450659453782278">"កំណត់​កាល​បរិច្ឆេទ"</string>
+    <string name="time_picker_dialog_title" msgid="8349362623068819295">"កំណត់​ម៉ោង​"</string>
+    <string name="date_picker_dialog_title" msgid="5879450659453782278">"កំណត់​កាល​បរិច្ឆេទ​"</string>
     <string name="date_time_set" msgid="5777075614321087758">"កំណត់"</string>
     <string name="date_time_done" msgid="2507683751759308828">"រួចរាល់"</string>
     <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"ថ្មី៖ "</font></string>
@@ -1343,7 +1352,7 @@
     <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">"ឲ្យ​កម្មវិធី​ចូល​​ការ​ផ្ទុក​មាន​សុវត្ថិភាព keguard ។"</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"ពិនិត្យ​ការ​បង្ហាញ និង​លាក់​ការ​ការពារ"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"ឲ្យ​កម្មវិធី​គ្រប់គ្រង keguard ។"</string>
@@ -1358,7 +1367,7 @@
     <string name="ime_action_go" msgid="8320845651737369027">"ទៅ"</string>
     <string name="ime_action_search" msgid="658110271822807811">"ស្វែងរក"</string>
     <string name="ime_action_send" msgid="2316166556349314424">"ផ្ញើ"</string>
-    <string name="ime_action_next" msgid="3138843904009813834">"បន្ទាប់"</string>
+    <string name="ime_action_next" msgid="3138843904009813834">"បន្ទាប់​"</string>
     <string name="ime_action_done" msgid="8971516117910934605">"រួចរាល់"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"មុន"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"អនុវត្ត"</string>
@@ -1367,7 +1376,7 @@
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"កម្មវិធី​មួយ ឬ​ច្រើន​ដូច​ខាង​ក្រោម​ស្នើ​សិទ្ធិ ដើម្បី​ចូល​គណនី​របស់​អ្នក​ឥឡូវ និង​ពេល​អនាគត។"</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"តើ​អ្នក​ចង់​អនុញ្ញាត​សំណើ​នេះ?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"ស្នើ​ចូល"</string>
-    <string name="allow" msgid="7225948811296386551">"អនុញ្ញាត"</string>
+    <string name="allow" msgid="7225948811296386551">"អនុញ្ញាត​"</string>
     <string name="deny" msgid="2081879885755434506">"បដិសេធ"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"បាន​ស្នើ​សិទ្ធិ"</string>
     <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"បាន​ស្នើ​សិទ្ធិ\nសម្រាប់​គណនី <xliff:g id="ACCOUNT">%s</xliff:g> ។"</string>
@@ -1377,8 +1386,7 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"ផ្ទាំង​រូបភាព"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"ប្ដូរ​ផ្ទាំង​រូបភាព"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"កម្មវិធី​ស្ដាប់​ការ​ជូន​ដំណឹង"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
+    <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ក្រុមហ៊ុន​ផ្ដល់​លក្ខខណ្ឌ"</string>
     <string name="vpn_title" msgid="19615213552042827">"បាន​ធ្វើ​ឲ្យ VPN សកម្ម"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"បាន​ធ្វើ​ឲ្យ VPN សកម្ម​ដោយ <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"ប៉ះ ដើម្បី​គ្រប់គ្រង​បណ្ដាញ។"</string>
@@ -1391,12 +1399,12 @@
     <string name="no_file_chosen" msgid="6363648562170759465">"គ្មាន​ឯកសារ​បាន​ជ្រើស"</string>
     <string name="reset" msgid="2448168080964209908">"កំណត់​ឡើងវិញ"</string>
     <string name="submit" msgid="1602335572089911941">"ដាក់​ស្នើ"</string>
-    <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"បាន​បើក​របៀប​រថយន្ត"</string>
+    <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"បាន​បើក​របៀប​រថយន្ត​"</string>
     <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"ប៉ះ​ ដើម្បី​ចេញ​ពី​របៀប​រថយន្ត​។"</string>
     <string name="tethered_notification_title" msgid="3146694234398202601">"ភ្ជាប់ ឬ​ហតស្ពត​សកម្ម"</string>
     <string name="tethered_notification_message" msgid="6857031760103062982">"ប៉ះ​ ដើម្បី​រៀបចំ។"</string>
     <string name="back_button_label" msgid="2300470004503343439">"ថយក្រោយ"</string>
-    <string name="next_button_label" msgid="1080555104677992408">"បន្ទាប់"</string>
+    <string name="next_button_label" msgid="1080555104677992408">"បន្ទាប់​"</string>
     <string name="skip_button_label" msgid="1275362299471631819">"រំលង"</string>
     <string name="throttle_warning_notification_title" msgid="4890894267454867276">"ការ​ប្រើ​ទិន្នន័យ​ចល័ត​ខ្ពស់"</string>
     <string name="throttle_warning_notification_message" msgid="3340822228599337743">"ប៉ះ​ ដើម្បី​​ស្វែងយល់​បន្ថែម​អំពី​ការ​ប្រើ​​​ទិន្នន័យ​ចល័ត​។"</string>
@@ -1422,7 +1430,7 @@
     <string name="media_shared" product="nosdcard" msgid="5830814349250834225">"ឧបករណ៍​ផ្ទុក​យូអេសប៊ី​បច្ចុប្បន្ន​កំពុង​ប្រើ​ដោយ​កុំព្យូទ័រ។"</string>
     <string name="media_shared" product="default" msgid="5706130568133540435">"បច្ចុប្បន្ន​កាត​អេសឌី​កំពុង​ប្រើ​ដោយ​កុំព្យូទ័រ"</string>
     <string name="media_unknown_state" msgid="729192782197290385">"មិន​ស្គាល់​ស្ថានភាព​មេឌៀ​ខាង​ក្រៅ។"</string>
-    <string name="share" msgid="1778686618230011964">"ចែក​រំលែក"</string>
+    <string name="share" msgid="1778686618230011964">"ចែក​រំលែក​"</string>
     <string name="find" msgid="4808270900322985960">"រក"</string>
     <string name="websearch" msgid="4337157977400211589">"ស្វែងរក​តាម​បណ្ដាញ"</string>
     <string name="find_next" msgid="5742124618942193978">"រក​បន្ទាប់"</string>
@@ -1438,7 +1446,7 @@
     <string name="sync_undo_deletes" msgid="2941317360600338602">"មិន​ធ្វើ​ការ​លុប​វិញ"</string>
     <string name="sync_do_nothing" msgid="3743764740430821845">"មិន​ធ្វើអ្វី​ទេ​ឥឡូវ"</string>
     <string name="choose_account_label" msgid="5655203089746423927">"ជ្រើស​គណនី"</string>
-    <string name="add_account_label" msgid="2935267344849993553">"បន្ថែម​គណនី​ថ្មី"</string>
+    <string name="add_account_label" msgid="2935267344849993553">"បន្ថែម​គណនី​ថ្មី​​"</string>
     <string name="add_account_button_label" msgid="3611982894853435874">"បន្ថែម​គណនី"</string>
     <string name="number_picker_increment_button" msgid="2412072272832284313">"បង្កើន"</string>
     <string name="number_picker_decrement_button" msgid="476050778386779067">"បន្ថយ"</string>
@@ -1457,15 +1465,15 @@
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"បង្កើន​​ឆ្នាំ"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"បន្ថយ​ឆ្នាំ"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"បោះ​បង់"</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="activitychooserview_choose_application" msgid="2125168057199941199">"ជ្រើស​កម្មវិធី"</string>
+    <string name="activitychooserview_choose_application" msgid="2125168057199941199">"ជ្រើស​កម្មវិធី​​"</string>
     <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"មិន​អាច​ចាប់ផ្ដើម <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
-    <string name="shareactionprovider_share_with" msgid="806688056141131819">"ចែករំលែក​ជា​មួយ"</string>
+    <string name="shareactionprovider_share_with" msgid="806688056141131819">"ចែករំលែក​ជា​មួយ​"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"ចែក​រំលែក​ជា​មួយ <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"គ្រប់គ្រង​ការ​រុញ។ ប៉ះ &amp; សង្កត់។"</string>
     <string name="description_target_unlock_tablet" msgid="3833195335629795055">"អូស​ ដើម្បី​ដោះ​សោ។"</string>
@@ -1479,7 +1487,7 @@
     <string name="storage_internal" msgid="4891916833657929263">"ឧបករណ៍​ផ្ទុក​ខាង​ក្នុង"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"កាត​អេសឌី"</string>
     <string name="storage_usb" msgid="3017954059538517278">"ឧបករណ៍​ផ្ទុក​យូអេសប៊ី"</string>
-    <string name="extract_edit_menu_button" msgid="8940478730496610137">"កែសម្រួល"</string>
+    <string name="extract_edit_menu_button" msgid="8940478730496610137">"កែសម្រួល​"</string>
     <string name="data_usage_warning_title" msgid="1955638862122232342">"ការព្រមាន​ប្រើ​ទិន្នន័យ"</string>
     <string name="data_usage_warning_body" msgid="2814673551471969954">"ប៉ះ ដើម្បី​មើល​ការ​ប្រើ និង​ការ​កំណត់។"</string>
     <string name="data_usage_3g_limit_title" msgid="7093334419518706686">"បាន​បិទ​ទិន្នន័យ 2G​-3G"</string>
@@ -1536,7 +1544,7 @@
     <string name="media_route_status_available" msgid="6983258067194649391">"ទំនេរ"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"មិន​ទំនេរ"</string>
     <string name="media_route_status_in_use" msgid="4533786031090198063">"កំពុង​ប្រើ"</string>
-    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"អេក្រង់​ជាប់"</string>
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"អេក្រង់​ជាប់​"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"អេក្រង់ HDMI"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"#<xliff:g id="ID">%1$d</xliff:g> ត្រួត​គ្នា"</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>
@@ -1568,7 +1576,7 @@
     <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_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>
@@ -1677,7 +1685,7 @@
     <string name="mediasize_japanese_you4" msgid="2091777168747058008">"You4"</string>
     <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"​មិន​ស្គាល់​បញ្ឈរ"</string>
     <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"មិន​ស្គាល់​ទេសភាព"</string>
-    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"បាន​បោះ​បង់"</string>
+    <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"បាន​បោះ​បង់​"</string>
     <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"កំហុស​ក្នុង​ការ​សរសេរ​មាតិកា"</string>
     <string name="reason_unknown" msgid="6048913880184628119">"មិន​ស្គាល់"</string>
     <string name="reason_service_unavailable" msgid="7824008732243903268">"មិន​បា​ន​បើក​សេវាកម្ម​បោះពុម្ព"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index c01ddd8..5a7f9b8 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"동기화"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"<xliff:g id="CONTENT_TYPE">%s</xliff:g> 삭제가 너무 많습니다."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"태블릿 저장공간이 꽉 찼습니다. 일부 파일을 삭제하여 저장 여유 공간을 늘리세요."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"시계 저장공간이 가득 찼습니다. 일부 파일을 삭제하여 저장 여유 공간을 늘리세요."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"휴대전화 저장공간이 꽉 찼습니다. 일부 파일을 삭제하여 저장공간을 늘리세요."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"네트워크가 모니터링될 수 있음"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"알 수 없는 제3자의 모니터링"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"벨소리가 켜져 있습니다."</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"종료 중..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"태블릿이 종료됩니다."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"시계가 종료됩니다."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"휴대전화가 종료됩니다."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"종료하시겠습니까?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"안전 모드로 다시 부팅"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"비행기 모드"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"안전 모드"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 시스템"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"바로가기 제거"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"애플리케이션이 사용자의 작업 없이 홈 화면 바로가기를 삭제할 수 있도록 허용합니다."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"발신전화 경로 전환"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"통화를 다른 번호로 리디렉션하거나 통화를 완전히 중단하는 옵션을 사용하여, 앱에서 발신 통화 중에 전화를 거는 번호를 볼 수 있게 허용합니다."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"앱이 발신 전화를 처리하고 전화를 걸 번호를 변경할 수 있도록 허용합니다. 이 권한을 사용하면 앱이 발신 전화를 모니터링, 리디렉션 또는 차단할 수도 있습니다."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"문자 메시지 받기(SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"앱이 SMS 메시지를 수신하고 처리할 수 있도록 허용합니다. 이는 앱이 사용자에게 표시하지 않고 기기로 전송된 메시지를 모니터링 또는 삭제할 수도 있다는 것을 의미합니다."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"문자 메시지 받기(MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"앱이 활성 창의 콘텐츠를 검색할 수 있도록 허용합니다. 이 경우 악성 앱이 전체 창의 콘텐츠를 검색하여 비밀번호를 제외한 모든 텍스트를 살펴볼 수 있습니다."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"일시적인 접근성 사용"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"애플리케이션이 기기에서 일시적으로 접근성을 사용하도록 허용합니다. 이 경우 악성 앱이 사용자의 동의 없이 접근성을 사용할 수 있습니다."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"창 토큰 검색"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"애플리케이션이 창 토큰을 검색하도록 허용합니다. 악성 앱이 시스템을 가장하여 애플리케이션 창과 무단으로 상호작용할 수 있습니다."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"프레임 통계 검색"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"애플리케이션이 프레임 통계를 수집하도록 허용합니다. 악성 앱이 다른 앱에서 창의 프레임 통계를 볼 수 있습니다."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"창 관련 정보 가져오기"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"애플리케이션이 Window Manager에서 창 관련 정보를 가져오도록 허용합니다. 이 경우 악성 앱이 내부 시스템에서만 사용하도록 되어 있는 정보를 가져올 수 있습니다."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"일정 필터링"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"애플리케이션에 입력 필터를 등록할 수 있도록 하여 모든 사용자 일정 스트림을 전달하기 전에 필터링합니다. 이 경우 사용자의 개입 없이 악성 앱이 시스템 UI를 제어할 수 있습니다."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"디스플레이 확대"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"앱이 표시된 콘텐츠를 확대하도록 허용합니다. 악성 앱은 표시된 콘텐츠를 변형시켜 기기를 사용할 수 없게 만들 수 있습니다."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"부분 종료"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"작업 관리자를 종료 상태로 설정합니다. 전체 종료를 수행하지는 않습니다."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"애플리케이션 전환 방지"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"앱이 SMS 메시지를 받았다는 알림을 브로드캐스트할 수 있도록 허용합니다. 이 경우 악성 앱이 수신된 SMS 메시지를 위조할 수 있습니다."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH-수신 브로드캐스트 보내기"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"앱이 WAP PUSH 메시지를 받았다는 알림을 브로드캐스트할 수 있도록 허용합니다. 이 경우 악성 앱이 MMS 메시지를 받은 것처럼 위장하거나 웹페이지의 콘텐츠를 악성 콘텐츠로 몰래 바꿀 수 있습니다."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"네트워크 점수화 브로드캐스트 전송"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"네트워크를 점수화할 필요가 있다는 알림을 앱이 브로드캐스트할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"실행 중인 프로세스 수 제한"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"앱이 실행할 최대 프로세스 수를 제어할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"백그라운드 앱 강제 종료"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"권한을 가진 프로그램이 VPN 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"배경화면 연결"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"권한을 가진 프로그램이 배경화면에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"원격 디스플레이에 연결"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"권한을 가진 프로그램이 TV 입력에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"기기 관리자 추가 또는 삭제"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"권한을 가진 프로그램이 활성화된 기기의 관리자를 추가 또는 삭제하도록 합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"화면 방향 변경"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"애플리케이션에서 설치된 모든 미디어 디코더를 사용하여 재생하는 데 디코딩할 수 있도록 허용합니다."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"신뢰할 수 있는 자격증명 관리"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"앱에서 CA 인증서를 신뢰할 수 있는 자격증명으로 설치 및 제거하도록 허용합니다."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"유휴 시간 동안 애플리케이션 실행"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"이 권한을 부여하면 기기를 사용하지 않는 동안 Android 시스템이 백그라운드에서 애플리케이션을 실행할 수 있게 됩니다."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"유휴 서비스에 연결"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"이 권한을 부여하면 Android 시스템이 애플리케이션의 유휴 서비스에 연결할 수 있습니다."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"진단 그룹 소유의 리소스 읽기/쓰기"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"앱이 진단 그룹 소유의 리소스(예: /dev에 있는 파일)를 읽고 쓸 수 있도록 허용합니다. 이 기능은 시스템 안정성 및 보안에 영향을 미칠 수 있으므로 제조업체 또는 사업자가 하드웨어 관련 진단을 수행하는 경우에만 사용해야 합니다."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"앱 구성요소 사용 또는 사용 안함"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"앱이 기기에 저장된 개인 프로필 정보(예: 사용자 이름, 연락처 정보 등)를 읽을 수 있도록 허용합니다. 이는 앱이 사용자를 확인할 수 있으며 다른 사용자에게 해당 프로필 정보를 전송할 수도 있다는 것을 의미합니다."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"나만의 연락처 카드 수정"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"앱이 기기에 저장된 개인 프로필 정보(예: 사용자 이름, 연락처 정보 등)를 변경 또는 추가할 수 있도록 허용합니다. 이는 앱이 사용자를 확인하고 다른 사용자에게 해당 프로필 정보를 전송할 수 있다는 것을 의미합니다."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"신체 센서(예: 심박수 모니터)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"앱이 신체 변화(예: 심박수) 측정을 위해 사용하는 센서의 데이터에 액세스하도록 허용합니다."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"소셜 스트림 읽기"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"앱이 사용자와 친구의 최신 소셜 소식에 액세스하고 동기화할 수 있도록 허용합니다. 이 경우 앱이 비밀유지와 관계 없이 소셜 네트워크에서 사용자와 친구가 주고받는 내용을 읽을 수 있으므로, 정보를 공유할 때 주의해야 합니다. 참고: 이 권한이 적용되지 않는 소셜 네트워크도 있습니다."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"소셜 스트림에 쓰기"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"앱이 기기의 휴대전화 기능을 관리할 수 있도록 허용합니다. 이 권한을 갖는 앱은 사용자에게 알리지 않고 네트워크를 전환하거나 무선 기능을 켜고 끄는 등의 작업을 수행할 수 있습니다."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"휴대전화 상태 및 ID 읽기"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"앱이 기기의 휴대전화 기능에 액세스할 수 있도록 허용합니다. 이 권한을 사용하면 앱이 전화번호 및 기기의 ID, 활성 통화인지 여부, 통화가 연결된 원격 번호 등을 확인할 수 있습니다."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"정확한 전화 상태 읽기"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"앱이 정확한 전화 상태에 액세스할 수 있도록 허용합니다. 이 권한을 부여하면 앱이 실제 통화 상태, 활성 통화 또는 백그라운드 상태인지 여부, 통화 실패, 정확한 데이터 연결 상태 및 데이터 연결 실패 등을 판단합니다."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"태블릿이 절전 모드로 전환되지 않도록 설정"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"휴대전화가 절전 모드로 전환되지 않도록 설정"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"앱이 태블릿의 절전 모드 전환을 막도록 허용합니다."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX 상태 변경"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"앱이 태블릿을 WiMAX 네트워크에 연결하거나 연결을 끊을 수 있도록 허용합니다."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"앱이 휴대전화를 WiMAX 네트워크에 연결하거나 연결을 끊을 수 있도록 허용합니다."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"네트워크 점수화"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"앱이 네트워크 순위를 정하고 태블릿에서 어떤 네트워크를 선호할지 영향을 주도록 허용합니다."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"앱이 네트워크 순위를 정하고 휴대전화에서 어떤 네트워크를 선호할지 영향을 주도록 허용합니다."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"블루투스 기기와 페어링"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"앱이 태블릿의 블루투스 설정을 확인하고 페어링된 기기에 연결하며 연결을 수락할 수 있도록 허용합니다."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"앱이 휴대전화의 블루투스 설정을 확인하고 페어링된 기기에 연결하며 연결을 수락할 수 있도록 허용합니다."</string>
@@ -703,18 +683,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"앱이 다른 앱에서 게시한 알림을 비롯하여 알림을 검색하고 살펴보며 삭제할 수 있도록 허용합니다."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"알림 수신기 서비스 사용"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"권한을 가진 프로그램이 알림 수신기 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"이동통신사에서 제공한 구성 앱 호출"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"권한을 가진 프로그램이 이동통신사에서 제공한 구성 앱을 호출하도록 합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"네트워크 상태에 대한 관측 보고 수신"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"애플리케이션이 네트워크 상태에 대한 관측 보고를 수신하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"입력 기기 보정 변경"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"앱이 터치 스크린의 보정 매개변수를 수정할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM 인증서에 액세스"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"애플리케이션이 DRM 인증서를 프로비저닝하고 사용하도록 허용합니다. 일반 앱에서는 필요하지 않습니다."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"비밀번호 규칙 설정"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"화면 잠금해제 비밀번호에 허용되는 길이 및 문자 수를 제어합니다."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"화면 잠금해제 시도 모니터링"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"애플리케이션에서 키가드 보안 저장소에 액세스하도록 허용합니다."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"키가드 표시 및 숨기기 설정"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"애플리케이션에서 키가드를 제어하도록 허용합니다."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Trust 상태 변경사항 수신"</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"애플리케이션이 Trust 상태에서의 변경사항을 수신할 수 있도록 허용합니다."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Trust Agent 서비스에 연결"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"애플리케이션이 Trust Agent 서비스에 바인딩할 수 있도록 허용합니다."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"업데이트 및 복구 시스템과 상호작용"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"애플리케이션이 복구 시스템 및 시스템 업데이트와 상호작용할 수 있도록 허용합니다."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"확대/축소하려면 두 번 터치하세요."</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"배경화면"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"배경화면 변경"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"알림 수신기"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN이 활성화됨"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN이 <xliff:g id="APP">%s</xliff:g>에 의해 활성화됨"</string>
     <string name="vpn_text" msgid="3011306607126450322">"네트워크를 관리하려면 터치하세요."</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 548d2c0..80a7e1f 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"ຊິ້ງຂໍ້ມູນ"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"ມີການລຶບ <xliff:g id="CONTENT_TYPE">%s</xliff:g> ຫຼາຍເກີນໄປ."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"ພື້ນທີ່ຈັດເກັບຂໍ້ມູນໃນແທັບເລັດເຕັມ. ລຶບບາງໄຟລ໌ອອກເພື່ອເພີ່ມພື້ນທີ່ຫວ່າງ."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"ບ່ອນ​ຈັດ​ເກັບ​ຂໍ້​ມູນ​ໃນ​ໂມງ​ເຕັມ​ແລ້ວ. ໃຫ້​ລຶບ​ໄຟ​ລ໌​ບາງ​ອັນ​ທີ່ບໍ່​ໄດ້​ໃຊ້​ອອກ​ເພື່ອ​ເພີ່ມ​ເນື້ອ​ທີ່​ຫວ່າງ."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"ພື້ນທີ່ໃນໂທລະສັບເຕັມແລ້ວ. ກະລຸນາລຶບບາງໄຟລ໌ອອກເພື່ອເພີ່ມພື້ນທີ່ຫວ່າງ."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ການນຳໃຊ້ເຄືອຂ່າຍອາດມີການກວດສອບຕິດຕາມ"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"ໂດຍບຸກຄົນທີສາມທີ່ບໍ່ຮູ້ຈັກ"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"ເປີດສຽງໂທເຂົ້າແລ້ວ"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"ກຳລັງປິດລະບົບລົງ..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"ແທັບເລັດຂອງທ່ານຈະຖືກປິດ."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"ໂມງ​ຂອງ​ທ່ານ​ຈະ​ຖືກ​ປິດ​ໄວ້."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"ໂທລະສັບຂອງທ່ານຈະຖືກປິດ."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"ທ່ານຕ້ອງການທີ່ຈະປິດບໍ່?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"ຣີບູດເຂົ້າ safe mode"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"ໂໝດໃນຍົນ"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"ລະບົບ Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"ຖອນທາງລັດ"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນລຶບທາງລັດໃນໜ້າຫຼັກໄດ້ ໂດຍບໍ່ຕ້ອງຮັບການຢືນຢັນຈາກຜູ່ໃຊ້."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"ປ່ຽນເສັ້ນທາງການໂທອອກ"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບຯ​ເບິ່ງ​​ໝາຍ​ເລກເບີ​ໂທ ໃນ​ລະ​ຫວ່າງ​ການ​ໂທ​ອອກ ພ້ອມ​ທັງ​ໂຕ​ເລືອກ​ໃນ​ການ​ປ່ຽນ​ເສັ້ນ​ທາງ​ການ​ໂທ​ໄປ​ຫາ​ເບີ​ອື່ນ ຫຼື ລາຍ​ລະ​ອຽດກ່ຽວ​ກັບ​ເບີ​ໂທ​ລະ​ສັບ."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"ອະນຸຍາດໃຫ້ແອັບຯປະມວນຜົນສາຍທີ່ໂທອອກ ແລະປ່ຽນໝາຍເລກທີ່ຈະໂທອອກ. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດກວດສອບ, ໂອນສາຍ ຫຼືຂັດຂວາງບໍ່ໃຫ້ໂທອອກໄດ້."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"ຮັບຂໍ້ຄວາມສັ້ນ (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"ອະນຸຍາດໃຫ້ແອັບຯຮັບ ແລະປະມວນຜົນຂໍ້ຄວາມ SMS. ນີ້ໝາຍຄວາມວ່າແອັບຯສາມາດຕິດຕາມ ຫຼືລຶບຂໍ້ຄວາມທີ່ສົ່ງເຂົ້າອຸປະກອນຂອງທ່ານ ໂດຍທີ່ບໍ່ສະແດງພວກມັນໃຫ້ທ່ານເຫັນ."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"ຮັບຂໍ້ຄວາມ (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"ອະນຸຍາດໃຫ້ແອັບຯດຶງຂໍ້ມູນເນື້ອຫາຂອງໜ້າຈໍທີ່ໃຊ້ຢູ່ໄດ້. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດດຶງຂໍ້ມູນທັງໝົດໃນໜ້າຈໍ ແລະກວດສອບຂໍ້ຄວາມທັງໝົດໃນນັ້ນໄດ້ ຍົກເວັ້ນລະຫັດຜ່ານ."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"ປິດການຊ່ວຍການເຂົ້າເຖິງຊົ່ວຄາວ"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນ ເປີດໃຊ້ການຊ່ວຍເຂົ້າເຖິງແບບຊົ່ວຄາວໃນອຸປະກອນ. ແອັບຯທີ່ເປັນອັນຕະລາຍ ອາດເປີດໃຊ້ການຊ່ວຍເຂົ້າເຖິງ ໂດຍບໍ່ໄດ້ຮັບການຍິນຍອມຈາກຜູ່ໃຊ້."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"​ດຶງ​ຂໍ້​ມູນ​ໂທ​ເຄນ​ໜ້າ​ຈໍ"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ດຶງ​ຂໍ້​ມູນ​ໂທ​ເຄນ​ຂອງ​ໜ້າ​ຈໍ​ໄດ້. ແອັບຯ​ທີ່​ເປັນ​ອັນ​ຕະ​ລາຍ​ອາດ​ດຳ​ເນີນ​ການ​ຕິດ​ຕໍ່​ທີ່ບໍ່​ໄດ້​ຮັບ​ອະ​ນຸ​ຍາດ​ກັບ​ໜ້າ​ຈໍ​ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ເພື່ອ​ຮຽນ​ແບບ​ລະ​ບົບ."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"ດຶງ​ຂໍ້​ມູນ​ສະ​ຖິ​ຕິ​ເຟ​ຣມ"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"​ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ສາ​ມາດ​ສະ​ສົມ​ສະ​ຖິ​ຕິ​ເຟ​ຣມ​ໄດ້. ແອັບຯ​ທີ່​ເປັນ​ອັນ​ຕະ​ລາຍ​ອາດ​ສັງ​ເກດ​ສະ​ຖິ​ຕິ​ເຟ​ຣມ​ຂອງ​ໜ້າ​ຈໍ​ຕ່າງໆ​ຈາກ​ແອັບຯ​ອື່ນ​ໄດ້."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"ດຶງເອົາຂໍ້ມູນໜ້າຈໍ"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນ ດຶງເອົາຂໍ້ມູນກ່ຽວກັບໜ້າຈໍຈາກໂຕຈັດການໜ້າຈໍ. ແອັບຯທີ່ບໍ່ປອດໄພອາດດຶງເອົາຂໍ້ມູນທີ່ໃຊ້ສຳລັບພາຍໃນລະບົບໄດ້."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"ກັ່ນຕອງເຫດການ"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນ ລົງທະບຽນການກັ່ນຕອງຂາເຂົ້າ ທີ່ກັ່ນຕອງການສົ່ງຂໍ້ມູນເຫດການຜູ່ໃຊ້ທັງໝົດ ກ່ອນທີ່ພວກມັນຈະຖືກເຜີຍແຜ່. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດຄວບຄຸມ UI ຂອງລະບົບໂດຍບໍ່ຕ້ອງໃຫ້ຜູ່ໃຊ້ຈັດການໄດ້."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"ຂະຫຍາຍການສະແດງຜົນ"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນ ສາມາດຂະຫຍາຍເນື້ອຫາທີ່ສະແດງຜົນໄດ້. ແອັບພລິເຄຊັນທີ່ເປັນອັນຕະລາຍ ອາດປ່ຽນເນື້ອຫາທີ່ສະແດງໃນລັກສະນະ ທີ່ເຮັດໃຫ້ບໍ່ສາມາດນຳໃຊ້ອຸປະກອນໄດ້."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"ປິດລົງບາງສ່ວນ"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"ກຳນົດໃຫ້ໂຕຈັດການກິດຈະກຳຢູ່ໃນສະຖານະປິດລະບົບ ໂດຍບໍ່ໄດ້ປິດລະບົບຢ່າງສົມບູນ."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"ຂັດຂວາງການສະລັບແອັບຯ"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"ອະນຸຍາດໃຫ້ແອັບຯ ກະຈາຍສັນຍານການແຈ້ງເຕືອນວ່າຂໍ້ຄວາມ SMS ໄດ້ຮັບແລ້ວ. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດຈະໃຊ້ສິ່ງນີ້ໃນການປອມແປງຂໍ້ຄວາມ SMS ຂາເຂົ້າ."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"ສົ່ງການກະຈາຍ WAP-PUSH ທີ່ໄດ້ຮັບ"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"ອະນຸຍາດໃຫ້ແອັບຯສົ່ງການແຈ້ງເຕືອນໃນເວລາທີ່ໄດ້ຮັບຂໍ້ມຄວາມ WAP PUSH. ແອັບຯທີ່ເປັນອັນຕະລາຍ ອາດໃຊ້ການກະທຳນີ້ເພື່ອປອມການໄດ້ຮັບຂໍ້ຄວາມ MMS ຫຼືລັກປ່ຽນເນື້ອຫາຂອງໜ້າເວັບຕ່າງໆ ດ້ວຍສິ່ງອັນຕະລາຍທັງຫຼາຍຢ່າງງຽບໆ."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"​ສົ່ງ​ການ​ກະ​ຈາຍ​ຄະແນນ​ເຄືອ​ຂ່າຍ"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"​ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບຯ​ກະ​ຈາຍ​ການ​ແຈ້ງ​ເຕືອນທີ່​ເຄືອ​ຂ່າຍຕ່າງໆ​ຈຳ​ເປັນ​ຖືກໃຊ້​ນັບ​​ຄະ​ແນນ. ບໍ່​ມີຄວາມ​ຈຳ​ເປັນ​ໃນ​ແອັບຯ​ທົ່ວ​ໄປ."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"ຈຳກັດຈຳນວນຂອງໂປຣເຊສທີ່ເຮັດວຽກຢູ່"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"ອະນຸຍາດໃຫ້ແອັບຯຄວບຄຸມຈຳນວນສູງສຸດ ຂອງໂປຣເຊສທີ່ຈະເຮັດວຽກ. ບໍ່ຄວນຖືກໃຊ້ກັບແອັບພລິເຄຊັນທົ່ວໄປ."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"ບັງຄັບໃຫ້ແອັບຯທີ່ເຮັດວຽກຢູ່ພື້ນຫຼັງປິດໂຕລົງ"</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງເຊື່ອມໂຍງກັບສ່ວນຕິດຕໍ່ລະດັບເທິງສຸດ ຂອງບໍລິການ VPN. ແອັບຯທົ່ວໄປບໍ່ຄວນຈຳເປັນຕ້ອງໃຊ້."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"ເຊື່ອມໂຍງກັບພາບພື້ນຫຼັງ"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ອະນຸຍາດໃຫ້ຜູ່ໃຊ້ເຊື່ອມໂຍງກັບສ່ວນຕິດຕໍ່ລະດັບສູງສຸດ ຂອງພາບພື້ນຫຼັງໃດນຶ່ງ. ແອັບຯທຳມະດາບໍ່ຄວນຈຳເປັນຕ້ອງໃຊ້."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ຜູກກັນເພື່ອສະແດງຜົນທາງໄກ."</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ອະນຸຍາດໃຫ້ແອັບຯໃຊ້ທຸກຕົວຖອດລະຫັດສື່ທີ່ຕິດຕັ້ງໄວ້ແລ້ວ ເພື່ອການຖອດລະຫັດການຫຼິ້ນໄຟລ໌ຕ່າງໆ."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"ຈັດການໜັງສືຮັບຮອງທີ່ເຊື່ອຖືໄດ້."</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"ອະ​ນຸ​ຍາດ​ໃຫ້ແອັບຯ ຕິດຕັ້ງ ແລະ ຖອນການຕິດຕັ້ງໃບຢັ້ງຢືນ CA ທີ່ເປັນໃບຮັບຮອງທີ່ເຊື່ອຖືໄດ້."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"ເປີດ​ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ໃນ​ເວ​ລາ​ທີ່​ບໍ່​ເຮັດ​ວຽກ"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"ນີ້​ຈະ​ເປັນ​ການອ​ະ​ນຸ​ຍາດ​​ໃຫ້​ລະ​ບົບ Android ສາ​ມາດ​ເປີດ​ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ໃນ​ພື້ນຫຼັງໄດ້​ໃນ​ຂະ​ນະ​ທີ່​ອຸ​ປະ​ກອນບໍ່​​ຖືກ​ນຳ​ໃຊ້."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"ເຊື່ອມຫາບໍລິການທີ່ບໍ່ໄດ້ນໍາໃຊ້"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"ສິດນີ້ຈະອະນຸຍາດໃຫ້ລະບົບ Android ສາມາດຜູກກັບການບໍລິການຂອງແອັບພລິເຄຊັນທີ່ບໍ່ໄດ້ເຮັດວຽກຢູ່ໄດ້."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"ອ່ານ/ຂຽນ ໃສ່ຊັບພະຍາກອນທີ່ເປັນຂອງກຸ່ມວິໄຈ"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນອ່ານ ແລະຂຽນ ໃສ່ທຸກຊັບພະຍາກອນທີ່ເປັນຂອງກຸ່ມວິນິໄສ; ຕົວຢ່າງ: ໄຟລ໌ໃນ /dev. ສິ່ງນີ້ອາດສົ່ງຜົນກະທົບຕໍ່ຄວາມສະຖຽນ ແລະຄວາມປອດໄພຂອງລະບົບ. ສິ່ງນີ້ຄວນໃຊ້ສຳຫຼັບການວິເຄາະບັນຫາຈຳເພາະ ຂອງບາງຮາດແວໂດຍຜູ່ຜະລິດ ຫຼືຜູ່ປະຕິບັດການເທົ່ານັ້ນ."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"ເປີດ ຫຼືປິດນຳໃຊ້ອົງປະກອບຂອງແອັບຯ"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"ອະນຸຍາດໃຫ້ແອັບຯ ອ່ານຂໍ້ມູນໂປໄຟລ໌ສ່ວນໂຕໃນອຸປະກອນຂອງທ່ານເຊັ່ນ: ຊື່ຂອງທ່ານ ແລະຂໍ້ມູນການຕິດຕໍ່ຂອງທ່ານ. ນີ້ໝາຍຄວາມວ່າແອັບຯຈະສາມາດລະບຸໂຕຕົນຂອງທ່ານ ແລະສົ່ງຂໍ້ມູນໂປຣໄຟລ໌ຂອງທ່ານໃຫ້ຜູ່ອື່ນໄດ້."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"ແກ້ໄຂບັດລາຍຊື່ຜູ່ຕິດຕໍ່ຂອງທ່ານເອງ"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"ອະນຸຍາດໃຫ້ແອັບຯ ປ່ຽນແປງ ຫຼືເພີ່ມຂໍ້ມູນໃສ່ໂປຣໄຟລ໌ສ່ວນບຸກຄົນທີ່ເກັບໄວ້ໃນອຸປະກອນຂອງທ່ານ, ເຊັ່ນ: ຊື່ ແລະຂໍ້ມູນຕິດຕໍ່ທ່ານ. ນີ້ໝາຍຄວາມວ່າແອັບຯສາມາດບົ່ງບອກໂຕທ່ານ ແລະອາດສົ່ງຂໍ້ມູນໂປຣໄຟລ໌ຂອງທ່ານໃຫ້ຜູ່ອື່ນໄດ້."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"ເຊັນ​ເຊີ​​ຮ່າງ​ກາຍ (ເຊັ່ນ: ​ຕິດ​ຕາມ​ອັດ​ຕາ​ການ​ເຕັ້ນ​ຂອງ​ຫົວ​ໃຈ)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບຯ​ເຂົ້າ​ເຖິງ​ຂໍ້​ມູນ​ຈາກ​ເຊັນ​ເຊີ​ທີ່​ທ່ານ​ໃຊ້​ເພື່ອ​ວັດ​ແທກ​ສິ່ງ​ທີ່​ເກີດ​ຂຶ້ນ​ໃນ​ຮ່າງ​ກາຍ​ຂອງ​ທ່ານ ເຊັ່ນ: ອັດ​ຕາ​ການ​ເຕັ້ນ​ຂອງ​ຫົວ​ໃຈ."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"ອ່ານການອັບເດດສັງຄົມອອນລາຍຂອງທ່ານ"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"ອະນຸຍາດໃຫ້ແອັບຯ ເຂົ້າເຖິງ ແລະຊິ້ງຂໍ້ມູນຂ່າວສານສັງຄົມຈາກທ່ານ ແລະໝູ່ຂອງທ່ານ. ຄວນລະມັດລະວັງໃນເວລາທີ່ແລກປ່ຽນຂໍ້ມູນ -- ນີ້ຈະເປັນການອະນຸຍາດໃຫ້ແອັບຯ ອ່ານການສື່ສານລະຫວ່າງທ່ານ ກັບໝູ່ຂອງທ່ານເທິງເຄືອຂ່າຍສັງຄົມ ໂດຍບໍ່ຄຳນຶງເຖິງຄວາມລັບ. ໝາຍເຫດ: ການກຳນົດສິດນີ້ອາດບໍ່ໄດ້ບັງຄັບໃຊ້ໃນທຸກເຄືອຂ່າຍສັງຄົມ."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"ຂຽນໃສ່ເຄືອຂ່າຍສັງຄົມຂອງທ່ານ"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"ອະນຸຍາດໃຫ້ແອັບຯຄວບຄຸມຄວາມສາມາດຂອງໂທລະສັບໃນອຸປະກອນ. ແອັບຯທີ່ມີການອະນຸຍາດນີ້ຈະສາມາດສະລັບເຄືອຂ່າຍ, ເປີດ ຫຼືປິດສັນຍານວິທະຍຸ ແລະຄວາມສາມາດອື່ນທີ່ຄ້າຍກັນ ໂດຍບໍ່ມີການແຈ້ງເຕືອນທ່ານ."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"ອ່ານສະຖານະ ແລະຂໍ້ມູນລະບຸໂຕຕົນຂອງໂທລະສັບ"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"ອະນຸຍາດໃຫ້ແອັບຯ ເຂົ້າເຖິງຄວາມສາມາດການໂທລະສັບຂອງອຸປະກອນ. ການກຳນົດສິດນີ້ເຮັດໃຫ້ແອັບຯສາມາດກວດສອບເບີໂທລະສັບ ແລະ ID ຂອງອຸປະກອນ, ບໍ່ວ່າການໂທຈະຍັງດຳເນີນຢູ່ ແລະເບີປາຍທາງເຊື່ອມຕໍ່ຢູ່ຫຼືບໍ່ກໍຕາມ."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"ອ່ານ​ຄ່າ​ສະ​ຖາ​ນະ​ລະ​ອຽດ​ຂອງ​ໂທ​ລະ​ສັບ"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບຯ​ເຂົ້າ​ເຖິງ​ສະ​ຖາ​ນະ​ໂດຍ​ລະ​ອຽດ​ຂອງ​ໂທ​ລະ​ສັບ. ການ​ອະ​ນຸ​ຍາດ​ນີ້​ຈະ​ຍິນຍອມ​ໃຫ້​ແອັບຯ​ກວດ​ສອບ​ສະ​ຖານ​ະ​ການ​ໂທ​ແທ້ໆ ວ່າ​ກຳ​ລັງ​ດຳ​ເນີນ​ຢູ່ ຫຼື​ຢູ່​ໃນ​ແບັກ​ກ​ຣາວ, ຄວາມລົ້ມ​ເຫລວ​ຂອງ​ການ​ໂທ, ສະ​ຖາ​ນະ​ການ​ເຊື່ອມ​ຕໍ່​ຂໍ້​ມູນ​ແບບ​ລະ​ອຽດ ແລະ​ຄວາມ​ລົ້ມ​ເຫລວ​ຂອງ​ການ​ເຊື່ອມ​ຕໍ່​ຂໍ້​ມູນ."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ຂັດຂວາງບໍ່ໃຫ້ປິດໜ້າຈໍແທັບເລັດ"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ຂັດຂວາງບໍ່ໃຫ້ໂທລະສັບປິດໜ້າຈໍ"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"ອະນຸຍາດໃຫ້ແອັບຯ ປ້ອງກັນບໍ່ໃຫ້ປິດໜ້າຈໍແທັບເລັດ."</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"ປ່ຽນສະຖານະ WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"ອະນຸຍາດໃຫ້ແອັບຯເຊື່ອມຕໍ່ ແລະຕັດການເຊື່ອມຕໍ່ແທັບເລັດຈາກເຄືອຂ່າຍ WiMAX."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"ອະນຸຍາດໃຫ້ແອັບຯເຊື່ອມຕໍ່ ແລະຕັດການເຊື່ອມຕໍ່ຂອງໂທລະສັບຈາກເຄືອຂ່າຍ WiMax ໄດ້."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ຄະແນນ​ເຄືອ​ຂ່າຍ"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບຯ​ຈັດ​ລຳ​ດັບ​ເຄືອ​ຂ່າຍ ແລະ ຊ່ວຍ​ຕັດ​ສິນ​ໃຈ​ວ່າ​ເຄືອ​ຂ່າຍ​ໃດ​ທີ່​​ແທັບ​ເລັດ​ຄວນ​ນຳ​ໃຊ້."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບຯ​ຈັດ​ລຳ​ດັບ​ເຄືອ​ຂ່າຍ ແລະ ຊ່ວຍ​ຕັດ​ສິນ​ໃຈ​ວ່າ​ເຄືອ​ຂ່າຍ​ໃດ​ທີ່​ໂທ​ລະ​ສັບ​ຄວນ​ນຳ​ໃຊ້."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"ຈັບຄູ່ກັບອຸປະກອນ Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"ອະນຸຍາດໃຫ້ແອັບຯເບິ່ງການຕັ້ງຄ່າຂອງ Bluetooth ໃນແທັບເລັດ ຕະຫຼອດຈົນເຊື່ອມຕໍ່ ແລະຍອມຮັບການເຊື່ອມຕໍ່ກັບອຸປະກອນທີ່ຈັບຄູ່ກັນແລ້ວ."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"ອະນຸຍາດໃຫ້ແອັບຯເບິ່ງການຕັ້ງຄ່າຂອງ Bluetooth ໃນໂທລະສັບ, ຮວມທັງໃຫ້ສ້າງ ແລະຮັບການເຊື່ອມຕໍ່ຈາກອຸປະກອນທີ່ຈັບຄູ່ກັນ."</string>
@@ -703,18 +685,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"ອະນຸຍາດໃຫ້ແອັບຯດຶງຂໍ້ມູນ, ກວດສອບ ແລະລຶບລ້າງການແຈ້ງເຕືອນ ຮວມທັງພວກທີ່ໂພສໂດຍແອັບຯອື່ນໆນຳ."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ເຊື່ອມໂຍງກັບບໍລິການໂຕຟັງການແຈ້ງເຕືອນ"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງເຊື່ອມໂຍງສ່ວນຕິດຕໍ່ລະດັບເທິງສຸດ ຂອງຜູ່ຟັງບໍລິການການແຈ້ງເຕືອນ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ຮ້ອງຂໍແອັບຯປັບຄ່າທີ່ສະໜອງໂດຍຜູ່ໃຫ້ບໍລິການ"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ອະ​ນຸ​ຍາດ​ໃຫ້​ເຈົ້າຂອງຮ້ອງຂໍແອັບຯປັບຄ່າທີ່ສະໜອງໂດຍຜູ່ໃຫ້ບໍລິການ. ບໍ່ໜ້າຈະຕ້ອງການສຳລັບແອັບຯທົ່ວໄປ."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ຕິດຕາມເພື່ອສັງເກດສະພາບຂອງເຄືອຂ່າຍ"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັ່ນຕິດຕາມເພື່ອສັງເກດສະພາບຂອງເຄືອຂ່າຍ. ປົກກະຕິແລ້ວແອັບຯທຳມະດາຈະບໍ່ຕ້ອງການໃຊ້."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"ປ່ຽນ​ການ​ວັດ​ແທ້​ອຸ​ປະ​ກອນ​ປ້ອນ​ຂໍ້​ມູນ"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບຯ​ແກ້​ໄຂ​ຄ່າ​ການວັດ​ແທ້​ໜ້າ​ຈ​ໍ​ສຳ​ຜັດ. ​ແອັບຯ​ທຳ​ມະ​ດາບໍ່​ຄວນ​ໃຊ້."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"ເຂົ້າ​ເຖິງ​ໃບຮັບຮອງ DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"ອະນຸຍາດ​ໃຫ້​ແອັບພລິເຄຊັນ​ຈັດຫາ ແລະ​ນຳໃຊ້​ໃບຮັບຮອງ DRM. ແອັບຯ​ທຳມະດາ​ບໍ່​ຄວນ​ຕ້ອງ​ການ​ໃຊ້."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"ຕັ້ງຄ່າກົດຂອງລະຫັດຜ່ານ"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"ຄວບຄຸມຄວາມຍາວຂອງໂຕອັກສອນທີ່ສາມາດໃຊ້ກັບລະຫັດປົດລັອກໜ້າຈໍ"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"ຕິດຕາມການພະຍາຍາມປົດລັອກໜ້າຈໍ"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນ ເຂົ້າເຖິງບ່ອນຈັດເກັບຂໍ້ມູນຄວາມປອດໄພດ້ວຍຄີກາດ."</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>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"​ເຊື່ອມ​ໂຍງ​ຫາ​ບໍ​ລິ​ການ​ຕົວ​ແທນ​ການ​ເຊື່ອ​ຖື"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"​ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ພ​ລິ​ເຄ​ຊັນເຊື່ອມ​ໂຍງ​ກັບ​ບໍ​ລິ​ການ​ຕົວ​ແທນ​ທີ່​ເຊື່ອ​ຖື​ໄດ້."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"ຕິດຕໍ່ກັບລະບົບອັບເດດ ແລະລະບົບກູ້ຂໍ້ມູນ."</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນຕິດຕໍ່ກັບລະບົບກູ້ຂໍ້ມູນ ແລະການອັບເດດລະບົບ."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"ແຕະສອງເທື່ອສຳລັບການຄວບຄຸມການຊູມ"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"ພາບພື້ນຫຼັງ"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"ປ່ຽນພາບພື້ນຫຼັງ"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"ໂຕຟັງການແຈ້ງເຕືອນ"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"ເປີດນຳໃຊ້ VPN ແລ້ວ"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"ເປີດໃຊ້ VPN ໂດຍ <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"ແຕະເພື່ອຈັດການເຄືອຂ່າຍ."</string>
@@ -1689,7 +1657,7 @@
     <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"PIN ປະ​ຈຸ​ບັນ"</string>
     <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"ລະຫັດ PIN ໃໝ່"</string>
     <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"ຢືນຢັນລະຫັດ PIN ໃໝ່"</string>
-    <string name="restr_pin_create_pin" msgid="8017600000263450337">"ສ້າງ PIN ສໍາ​ລັບ​ການ​ປັບ​ປຸງ​ຂໍ້ຈໍາ​ກັດ"</string>
+    <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">
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 0b25703..c61b4e6 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinchronizuoti"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Per daug <xliff:g id="CONTENT_TYPE">%s</xliff:g> trynimo."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Planšetinio kompiuterio atmintis pilna. Kad atlaisvintumėte vietos, ištrinkite kelis failus."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Laikrodžio saugykla pilna. Ištrinkite kelis failus, kad atlaisvintumėte vietos."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Telefono atmintis pilna. Ištrinkite kai kuriuos failus, kad atlaisvintumėte vietos."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Tinklas gali būti stebimas"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Nežinoma trečioji šalis"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Skambutis įjungtas"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Išsijungia..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Planšetinio kompiuterio veikimas bus sustabdytas."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Laikrodis išsijungs."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefonas bus išjungtas."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Ar norite išjungti?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Iš naujo įkelti operacinę sistemą saugos režimu"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Lėktuvo režimas"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Saugos režimas"</string>
     <string name="android_system_label" msgid="6577375335728551336">"„Android“ sistema"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"pašalinti sparčiuosius klavišus"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Programai leidžiama pašalinti sparčiuosius klavišus iš pagrindinio ekrano be naudotojo įsikišimo."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"peradresuoti išsiunčiamuosius skambučius"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Leidžiama programai peržiūrėti renkamą numerį išsiunčiamojo skambučio metu suteikiant galimybę peradresuoti skambutį kitu numeriu arba visiškai nutraukti skambutį."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Leidžiama programai atlikti išsiunčiamuosius skambučius ir keisti renkamą numerį. Šis leidimas suteikia teisę programai stebėti, peradresuoti ar neleisti išsiunčiamųjų skambučių."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"gauti teksto pranešimus (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Leidžiama programai gauti ir apdoroti SMS pranešimus. Tai reiškia, kad programa gali stebėti ir ištrinti į jūsų įrenginį siunčiamus pranešimus jums jų neparodžiusi."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"gauti teksto pranešimus (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Leidžiama programai nuskaityti aktyvaus lango turinį. Kenkėjiškos programos gali bandyti išgauti viso lango turinį ir tirti visą jo tekstą, išskyrus slaptažodžius."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"laikinai įgalinti pritaikymą neįgaliesiems"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Leidžiama programai laikinai įgalinti pritaikymą neįgaliesiems įrenginyje. Kenkėjiškos programos pritaikymą neįgaliesiems gali įgalinti be naudotojo sutikimo."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"gauti lango prieigos raktą"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Programai leidžiama gauti lango prieigos raktą. Kenkėjiškos programos gali vykdyti neteisėtą sąveiką su programos langu mėgdžiodamos sistemą."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"gauti kadrų statistinius duomenis"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Programai leidžiama rinkti kadrų statistinius duomenis. Kenkėjiškos programos gali stebėti kadrų statistinius duomenis iš kitų programų langų."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"gauti lango informaciją"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Leidžiama programai iš langų tvarkytuvės gauti informaciją apie langus. Kenkėjiškos programos gali gauti informaciją, kuri skirta naudoti sistemos viduje."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filtrų įvykiai"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Leidžiama programai registruoti įvesties filtrą, kuriuo filtruojamas visų naudotojo įvykių srautas prieš juos išsiunčiant. Kenkėjiška programa gali kontroliuoti sistemos naudotojo sąsają be naudotojo įsikišimo."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"didinti pateiktį"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Leidžiama programai didinti pateikties turinį. Kenkėjiškos programos gali pakeisti pateikties turinį taip, kad nebūtų galima naudoti įrenginio."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"dalinis išjungimas"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Veiklos tvarkyklę perjungia į išsijungimo būseną. Neišjungia visiškai."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"neleisti perjungti programų"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Leidžiama programai pateikti pranešimą, kad buvo gautas SMS pranešimas. Kenkėjiškos programos gali tai naudoti, kad klastotų gaunamuosius SMS pranešimus."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"siųsti „WAP-PUSH-received“ perdavimą"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Leidžiama programai pateikti pranešimą, kai gaunamas WAP PUSH pranešimas. Kenkėjiškos programos gali tai naudoti, kad klastotų MMS pranešimo gavimą ar kad nepastebimai pakeistų bet kurio tinklalapio turinį kenkėjiškais variantais."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"siųsti tinklų transliavimo įvertinimą"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Programai leidžiama transliuoti pranešimą, kad reikia įvertinti tinklus. Niekada nereikia įprastoms programoms."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"riboti vykdomų procesų skaičių"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Leidžiama programai valdyti didžiausią vykdomų procesų skaičių. Nereikalinga įprastoms programoms."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"priverstinai uždaryti fonines programas"</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Leidžiama savininkui susisaistyti su aukščiausio lygio VPN paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"susaistyti su darbalaukio fonu"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Leidžiama savininką susaistyti su aukščiausio lygio darbalaukio fono sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"susisaistyti su nuotoliniu ekranu"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Leidžiama savininkui susisaistyti su aukščiausiojo lygio nuotolinio ekrano sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"susaistyti su valdiklio paslauga"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Leidžiama programai naudoti bet kurį įdiegtą medijos dekoderį norint iššifruoti atkūrimą."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"tvarkyti patikimus prisijungimo duomenis"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Programoje galima įdiegti ir iš jos pašalinti CA sertifikatus kaip patikimus prisijungimo duomenis."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"paleisti programą, kai įrenginys yra neaktyvus"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Šiuo leidimu sistemai „Android“ leidžiama fone paleisti programą, kai įrenginys yra nenaudojamas."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"susaistyti su neaktyviomis paslaugomis"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Šiuo leidimu „Android“ sistemai leidžiama susaistyti su programos neaktyviomis paslaugomis."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"skaityti / rašyti ištekliuose, priklausančiuose diagnostikai"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Leidžiama programai skaityti ir rašyti visuose diagnostikos grupei priklausančiuose ištekliuose, pvz., failuose, esančiuose /dev. Tai gali paveikti sistemos stabilumą ir saugą. Tai turėtų būti naudojama TIK gamintojui ar operatoriui atliekant aparatinės įrangos diagnostiką."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"įgalinti programos komponentus arba jų neleisti"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Programai leidžiama skaityti įrenginyje saugomą asmeninę profilio informaciją, pvz., vardą, pavardę ir kontaktinę informaciją. Tai reiškia, kad programa gali nustatyti tapatybę ir siųsti profilio informaciją kitiems."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"keisti jūsų kontaktinę kortelę"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Leidžiama programai keisti įrenginyje saugomą asmeninę profilio informaciją, pvz., vardą, pavardę ir kontaktinę informaciją, arba jos pridėti. Tai reiškia, kad programa gali nustatyti tapatybę ir siųsti profilio informaciją kitiems."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"kūno jut. (pvz., pulso d. t.)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Programai leidžiama pasiekti naudojamų jutiklių duomenis, siekiant įvertinti, kas vyksta jūsų kūne, pvz., pulso dažnį."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"skaityti socialinį srautą"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Leidžiama programai pasiekti ir sinchronizuoti viešas naujienas iš jūsų ir jūsų draugų. Būkite atidūs bendrindami informaciją – programai leidžiama skaityti korespondenciją tarp jūsų ir draugų viešuosiuose tinkluose, neatsižvelgiant į konfidencialumą. Pastaba: šis leidimas negali būti taikomas visuose viešuosiuose tinkluose."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"rašyti į socialinį srautą"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Leidžiama programai valdyti įrenginio telefono funkcijas. Šį leidimą turinti programa gali perjungti tinklus, įjungti ir išjungti telefono radiją ir atlikti panašius veiksmus jūsų neįspėdama."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"skaityti telefono būseną ir tapatybę"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Leidžiama programai pasiekti telefono funkcijas įrenginyje. Šis leidimas suteikia teisę programai nustatyti telefono numerį ir įrenginio ID, tai, ar skambutis aktyvus, ir skambučiu prijungtą nuotolinį numerį."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"skaityti tikslias telefono būsenas"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Programai leidžiama pasiekti tikslias telefono būsenas. Šiuo leidimu programai leidžiama nustatyti tikrą skambučio būseną, ar skambutis yra aktyvus, ar vyksta fone, ar paskambinti nepavyksta, tikslią duomenų ryšio būseną ir ar nepavyksta užmegzti duomenų ryšio."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"neleisti planšetiniam kompiuteriui užmigti"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"neleisti telefonui snausti"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Leidžiama programai neleisti planšetiniam kompiuteriui užmigti."</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Keisti „WiMAX“ būseną"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Leidžia programai prijungti planšetinį kompiuterį prie „WiMAX“ ryšio tinklų ir nuo jų atjungti."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Leidžia programai prijungti telefoną prie „WiMAX“ ryšio tinklų ir nuo jų atjungti."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"įvertinti tinklus"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Programai leidžiama įvertinti tinklus ir nustatyti, kuriems tinklams planšetiniame kompiuteryje turėtų būti taikoma pirmenybė."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Programai leidžiama įvertinti tinklus ir nustatyti, kuriems tinklams telefone turėtų būti taikoma pirmenybė."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"susieti su „Bluetooth“ įrenginiais"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Leidžiama programai peržiūrėti „Bluetooth“ konfigūraciją planšetiniame kompiuteryje ir užmegzti bei priimti ryšius iš susietų įrenginių."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Leidžiama programai peržiūrėti „Bluetooth“ konfigūraciją telefone ir užmegzti bei priimti ryšius iš susietų įrenginių."</string>
@@ -703,18 +685,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"iškviesti operatoriaus pateiktą konfigūravimo programą"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Turėtojui leidžiama iškviesti operatoriaus pateiktą konfigūravimo programą. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"vykdyti tinklo sąlygų stebėjimą"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Leidžiama programai vykdyti tinklo sąlygų stebėjimą. To niekada neturėtų prireikti naudojant įprastas programas."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"keisti įvesties įrenginio kalibravimą"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Leidžiama programai keisti jutiklinio ekrano kalibravimo parametrus. Neturėtų prireikti naudojant įprastas programas."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"gali pasiekti DRM sertifikatus"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Programai leidžiama pasiekti ir naudoti DRM sertifikatus. Neturėtų prireikti naudojant įprastas programas."</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="policylab_watchLogin" msgid="914130646942199503">"Stebėti bandymus atrakinti ekraną"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Programai leidžiama pasiekti „KeyGuard“ saugyklą."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Valdyti „KeyGuard“ rodymą ir slėpimą"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Programai leidžiama valdyti „KeyGuard“."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Atsižvelgti į patikimos būsenos pakeitimus."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Programai leidžiama atsižvelgti į patikimos būsenos pakeitimus."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Susisaistyti su „trust agent“ paslauga"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Programai leidžiama susisaistyti su „trust agent“ paslauga."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Sąveikauti su naujiniu ir atkūrimo sistema"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Programai leidžiama sąveikauti su atkūrimo sistema ir sistemos naujiniais."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Dukart palieskite, kad valdytumėte mastelio keitimą"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Darbalaukio fonas"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Keisti darbalaukio foną"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Pranešimų skaitymo priemonė"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN suaktyvintas"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN suaktyvino „<xliff:g id="APP">%s</xliff:g>“"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Palieskite, kad valdytumėte tinklą."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index f2415d5..130b27e 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinhronizācija"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Pārāk daudz <xliff:g id="CONTENT_TYPE">%s</xliff:g> dzēsto vienumu."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Planšetdatora atmiņa ir pilna. Dzēsiet dažus failus, lai atbrīvotu vietu."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Pulksteņa atmiņa ir pilna. Dzēsiet dažus failus, lai atbrīvotu vietu."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Tālruņa atmiņa ir pilna! Dzēsiet dažus failus, lai atbrīvotu vietu."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Iespējams, tīklā veiktās darbības tiek pārraudzītas."</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Nezināma trešā puse"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Zvanītājs ieslēgts"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Notiek izslēgšana..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Planšetdators tiks beidzēts."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Pulkstenis tiks izslēgts."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Tālrunis tiks izslēgts."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Vai vēlaties izslēgt?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Atsāknēšana drošajā režīmā"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Lidojuma režīms"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"Pārsniedz"</string>
     <string name="safeMode" msgid="2788228061547930246">"Drošais režīms"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android sistēma"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"atinstalēt saīsnes"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Ļauj lietojumprogrammai noņemt saīsnes no sākuma ekrāna, nejautājot lietotājam."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"pārmaršrutēt izejošos zvanus"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Ļauj lietotnei skatīt ievadīto tālruņa numuru izejošā zvana laikā un piedāvā iespēju šo zvanu pāradresēt uz citu numuru vai vispār pārtraukt zvanu."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Ļauj lietotnei apstrādāt izejošos zvanus un mainīt numuru, uz kuru tiks zvanīts. Ar šo atļauju lietotne var pārraudzīt, novirzīt vai neatļaut izejošos zvanus."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"saņemt īsziņas (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Ļauj lietotnei saņemt un apstrādāt īsziņas. Tas nozīmē, ka lietotne var pārraudzīt vai dzēst uz jūsu ierīci nosūtītos ziņojumus, neparādot tos jums."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"saņemt ziņojumus (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Ļauj lietotnei izgūt aktīva loga saturu. Ļaunprātīgas lietotnes var izgūt visu loga saturu un pārbaudīt visu tā tekstu, izņemot paroles."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"Īslaicīga pieejamības režīma iespējošana"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Ļauj lietojumprogrammai īslaicīgi ierīcē iespējot pieejamības režīmu. Ļaunprātīgas lietotnes var iespējot pieejamības režīmu bez lietotāja atļaujas."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"Loga marķiera izgūšana"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Ļauj lietojumprogrammai izgūt loga marķieri. Ļaunprātīgas lietotnes var veikt neautorizētas darbības ar lietojumprogrammas logu, izliekoties par attiecīgo sistēmu."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"Ietvaru statistikas izgūšana"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Ļauj lietojumprogrammai apkopot ietvaru statistiku. Ļaunprātīgas lietotnes var iegūt logu ietvaru statistiku no citām lietotnēm."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"Izgūt informāciju par logiem"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Ļauj lietojumprogrammai no logu pārvaldnieka izgūt informāciju par logiem. Ļaunprātīgas lietotnes var izgūt informāciju, kas ir paredzēta iekšējai izmantošanai sistēmā."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"Filtrēt notikumus"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Ļauj lietojumprogrammai reģistrēt ieejas filtru, kas filtrē visu lietotāja notikumu straumi, pirms notikumi tiek nosūtīti. Ļaunprātīga lietotne var kontrolēt sistēmas lietotāja saskarni, nejautājot lietotājam."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"displeja palielināšana"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Ļauj lietojumprogrammai palielināt displeja saturu. Ļaunprātīgas lietotnes var pārveidot displeja saturu tā, ka ierīce kļūst nelietojama."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"daļēja izslēgšana"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Liek darbību pārvaldniekam pāriet izslēgšanas stāvoklī. Neveic pilnīgu izslēgšanu."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"novērst lietojumprogrammu pārslēgšanu"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Ļauj lietotnei pārraidīt paziņojumu par saņemtu īsziņu. Ļaunprātīgas lietotnes to var izmantot, lai viltotu ienākošas īsziņas."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"sūtīt WAP-PUSH-saņemto apraidi"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Ļauj lietotnei pārraidīt paziņojumu par to, ka ir saņemts WAP PUSH ziņojums. Ļaunprātīgas lietotnes to var izmantot, lai viltotu multiziņas saņemšanu vai jebkuras tīmekļa lapas saturu nemanāmi nomainītu ar ļaunprātīgiem variantiem."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"apraidīt ziņojumu par tīklu vērtēšanu"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Ļauj lietotnei apraidīt paziņojumu, ka tīkli ir jānovērtē. Parastām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"ierobežot aktīvo procesu skaitu"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Ļauj lietotnei kontrolēt izpildāmo procesu maksimālo skaitu. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"veikt fonā darbojošos lietotņu piespiedu aizvēršanu"</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Ļauj īpašniekam izveidot saiti ar VPN pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"saistīt ar tapeti"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Ļauj īpašniekam piesaistīt tapetes augstākā līmeņa lietotāja saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"Saites izveide ar attālu displeju"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ļauj īpašniekam izveidot saiti ar attāla displeja augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"saistīt ar logrīka pakalpojumu"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ļauj lietotnei izmantot jebkuru instalētu multivides failu dekodētāju, lai dekodētu failus atskaņošanai."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Uzticamo akreditācijas datu pārvaldība"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ļauj lietotnei instalēt un atinstalēt CA sertifikātus kā uzticamus akreditācijas datus."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"Lietojumprogrammas darbība dīkstāves laikā"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Ar šo atļauju Android sistēmā lietojumprogramma darbojas fonā, kad ierīce netiek lietota."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"saistīšana ar neaktīviem pakalpojumiem"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Pamatojoties uz šo atļauju, Android sistēma var izveidot saiti ar lietojumprogrammas neaktīvajiem pakalpojumiem."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lasīt grupas “diag” resursus un rakstīt tajos"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Ļauj lietotnei lasīt un rakstīt jebkurā resursā, kas pieder diagnostikas grupai, piemēram, failiem mapē /dev. Tas var ietekmēt sistēmas stabilitāti un drošību. Var izmantot ražotājs vai operators TIKAI konkrētas aparatūras diagnostikai."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"iespējot vai atspējot lietotnes komponentus"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Ļauj lietotnei lasīt ierīcē saglabāto personīgā profila informāciju, piemēram, jūsu vārdu un kontaktinformāciju. Tas nozīmē, ka lietotne var jūs identificēt un var nosūtīt jūsu profila informāciju citām personām."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"mainīt manu vizītkarti"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Ļauj lietotnei mainīt ierīcē saglabāto personīgā profila informāciju, piemēram, jūsu vārdu un kontaktinformāciju, vai pievienot tai citu informāciju. Tas nozīmē, ka lietotne var jūs identificēt un var nosūtīt jūsu profila informāciju citām personām."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"ķermeņa sensori (piemēram, sirdsdarbības monitori)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Ļauj lietotnei piekļūt to sensoru datiem, kurus izmantojat, lai novērtētu ķermeņa procesus, piemēram, sirdsdarbību."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"lasīt jūsu soc. tīklu straumi"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Ļauj lietotnei piekļūt sociālajiem atjauninājumiem no jums un jūsu draugiem un sinhronizēt tos. Esiet piesardzīgs, kad kopīgojat informāciju, — šādi lietotne var lasīt sociālajos tīklos ar draugiem veikto saziņu, neraugoties uz konfidencialitāti. Piezīme: šo atļauju nedrīkst piemērot visiem sociālajiem tīkliem."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"rakstīt sociālo tīklu straumē"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Ļauj lietotnei kontrolēt ierīces tālruņa funkcijas. Lietotne, kurai ir šī atļauja, var pārslēgt tīklus, ieslēgt un izslēgt tālruņa radio un veikt tamlīdzīgas darbības, nebrīdinot jūs."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"lasīt tālruņa statusu un identitāti"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Ļauj lietotnei piekļūt ierīces tālruņa funkcijām. Ar šo atļauju lietotne var noteikt tālruņa numuru un ierīču ID, zvana statusu un attālo numuru, ar ko ir izveidots savienojums, veicot zvanu."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"precīzu tālruņa statusa datu lasīšana"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Ļauj lietotnei piekļūt precīziem datiem par tālruņa statusu. Izmantojot šo atļauju, lietotne var noteikt zvana faktisko statusu, vai zvans ir aktīvs vai notiek fonā, vai zvans nav izdevies, kā arī precīzu datu savienojuma statusu un neizdevušos datu savienojumus."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"novērst planšetdatora pāriešanu miega režīmā"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"novērst tālruņa pāriešanu miega režīmā"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Ļauj lietotnei novērst planšetdatora pāriešanu miega režīmā."</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX statusa mainīšana"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Ļauj lietotnei izveidot un pārtraukt planšetdatora savienojumu ar WiMAX tīkliem."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Ļauj lietotnei izveidot un pārtraukt tālruņa savienojumu ar WiMAX tīkliem."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"vērtēt tīklus"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Ļauj lietotnei ranžēt tīklus un ietekmēt to, kuriem tīkliem planšetdators dos priekšroku."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Ļauj lietotnei ranžēt tīklus un ietekmēt to, kuriem tīkliem tālrunis dos priekšroku."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"savienot pārī ar Bluetooth ierīcēm"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Ļauj lietotnei skatīt Bluetooth konfigurāciju planšetdatorā, kā arī veidot un pieņemt savienojumus ar pārī savienotām ierīcēm."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Ļauj lietotnei skatīt Bluetooth konfigurāciju tālrunī, kā arī veidot un pieņemt savienojumus ar pārī savienotām ierīcēm."</string>
@@ -703,18 +685,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"Operatora nodrošinātas konfigurācijas lietotnes izsaukšana"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ļauj īpašniekam izsaukt operatora nodrošināto konfigurācijas lietotni. Parastām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"iegūt informāciju par tīkla stāvokļa novērojumiem"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Ļauj lietojumprogrammai iegūt informāciju par tīkla stāvokļa novērojumiem. Parastām lietotnēm šī atļauja nekad nav nepieciešama."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"mainīt ievadierīces kalibrēšanu"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Ļauj lietotnei pārveidot skārienekrāna kalibrēšanas parametrus. Parastām lietotnēm šī atļauja nekad nav nepieciešama."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"Piekļuve digitālā satura tiesību pārvaldības sertifikātiem"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Ļauj lietojumprogrammai nodrošināt un izmantot digitālā satura tiesību pārvaldības sertifikātus. Parastām lietotnēm šī atļauja nekad nav nepieciešama."</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="policylab_watchLogin" msgid="914130646942199503">"Ekrāna atbloķēšanas mēģinājumu pārraudzīšana"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Ļauj lietojumprogrammai piekļūt krātuvei, kas aizsargāta ar atslēgu."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Pārvaldīt krātuves rādīšanu un paslēpšanu."</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Ļauj lietojumprogrammai pārvaldīt krātuvi."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Klausīties uzticamības statusa izmaiņas"</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Ļauj lietojumprogrammai klausīties uzticamības statusa izmaiņas."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Izveidot savienojumu ar uzticamības pārbaudes pakalpojumu"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ļauj lietojumprogrammai izveidot savienojumu ar uzticamības pārbaudes pakalpojumu."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Mijiedarbošanās ar atjauninājumu un atkopšanas sistēmu"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Ļauj lietojumprogrammai mijiedarboties ar atkopšanas sistēmu un sistēmas atjauninājumiem."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Pieskarieties divreiz, lai kontrolētu tālummaiņu."</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Fona tapete"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Tapetes maiņa"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Paziņojumu uztvērējs"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN ir aktivizēts."</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Lietojumprogramma <xliff:g id="APP">%s</xliff:g> aktivizēja VPN."</string>
     <string name="vpn_text" msgid="3011306607126450322">"Pieskarieties, lai pārvaldītu tīklu."</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 8fd4fba..b35904b 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Синк"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Хэт олон <xliff:g id="CONTENT_TYPE">%s</xliff:g> устгах."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Таблетийн сан дүүрсэн. Зай чөлөөлөх бол зарим файлыг устгана уу."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Цагны сан дүүрсэн. Зай чөлөөлөх бол зарим файлыг устгана уу."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Утасны сан дүүрсэн. Зай чөлөөлөх бол зарим файлыг устгана уу."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Сүлжээ хянагдаж байж болзошгүй"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Тодорхойгүй гуравдагч талаас"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Хонх ассан"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Унтрааж байна…"</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Таны таблет унтрах болно."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Таны цаг унтрах болно."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Таны утас унтрах болно."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Та унтраах уу?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Аюулгүй горимоор дахин асаах"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Нислэгийн горим"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Аюулгүй горим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Андройд систем"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"товчлолыг устгах"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Аппликешн нь хэрэглэгчийн оролцоогүйгээр Нүүр дэлгэцний товчлолыг устгаж чадна."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"гарсан дуудлагыг чиглэлийг өөрчлөх"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Гадагш дуудлага хийх үед залгасан дугаарыг харах, дуудлагыг өөр дугаар руу шилжүүлэх, таслах боломжтой болгоно."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Апп нь дуудлага хийх болон залгаж байгаа дугаарыг өөрчлөх боломжтой. Энэ зөвшөөрөл нь апп-г залгасан дуудлагыг хаах, хянах болон дахин чиглүүлэх боломжтой болгодог."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"текст мессеж(SMS) хүлээж авах"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Апп нь SMS мессежийг хүлээн авах болон гүйцэтгэх боломжтой. Ингэснээр апп нь таны төхөөрөмжрүү илгээсэн мессежийг танд үзүүлэхгүйгээр хянах болон устгаж чадна."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"текст мессеж(МMS) хүлээж авах"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Апп нь идэвхтэй цонхны контентыг авах боломжтой. Хортой апп нь цонхны контентыг бүхэлд авах болон нууц үгнээс бусад бүх текстийг шалгаж болзошгүй"</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"Хялбар байдлыг түр идэвхтэй болгох"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Аппликешн нь төхөөрөмжийн хялбар байдлыг түр зуур идэвхжүүлэх боломжтой. Хортой апп нь хэрэглэгчийн зөвшөөрөлгүйгээр хялбар байдлыг идэвхжүүлж болзошгүй."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"цонхны токен авах"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Аппликешнд цонхны токен авах боломж олгоно. Хорлонтой апп-ууд системийн өмнөөс аппликешны цонхтой зөвшөөрөлгүйгээр харилцах боломжтой."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"фреймын статистик авах"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Аппликешнд фреймын статистикыг цуглуулах боломж олгоно. Хорлонтой апп-ууд виндовсын фреймын статистикыг өөр апп-с хянах боломжтой."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"цонхны мэдээллийг унших"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Аппликешн нь цонхны менежерээс цонхны талаар мэдээллийг дуудах боломжтой. Хортой апп нь дотоод системийн хэрэглээнд зориулагдсан мэдээллийг дуудаж болзошгүй."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"үйл явдлыг шүүх"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Аппликешн нь хэрэглэгчийн бүх үйл явдалын илгээгдэхээс өмнөх урсгалыг шүүж байгаа оролтын шүүлтйиг бүртгэх боломжтой. Хортой апп нь хэрэглэгчийн интервэшнгүйгээр системийн UI-г удирдах боломжтой."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"дэлгэц томруулах"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Аппликешн нь дэлгэцний контентийг өсгөх боломжтой. Хортой апп нь дэлгэцийн контентыг төхөөрөмжнөөс ашиглаж болохгүй болгон хувиргах боломжтой."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"хэсэгчилсэн унтраалт"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Активити менежерийг унтраана. Бүрэн унтраалтыг хийхгүй."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"апп шилжүүлэхийг хориглох"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Апп нь SMS мессеж хүлээн авсан талаарх мэдэгдлийг өргөн дамжуулах боломжтой. Хортой апп энийг ашиглан ирсэн SMS мессежийг хуурамчаар хийх боломжтой."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH-хүлээн авав өргөн дамжууллыг илгээх"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Аппликешн нь WAP PUSH мессеж хүлээж авсан мэдэгдлийг өргөн дамжуулах боломжтой. Хортой апп нь энийг ашиглан MMS мессеж хүлээн авсан гэж хуурамчаар мэдэгдэх эсвэл хортой хувьсагч агуулсан веб хуудасны контентыг чимээгүй орлуулах боломжтой."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"бүртгэгдсэн сүлжээнүүд рүү түгээх"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Апп-д сүлжээнүүдэд бүртгэгдсэн байх шаардлагатай мэдэгдлийг түгээх боломжийг олгоно. Энгийн апп-д хэзээ ч шаардагдахгүй."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"ажиллаж байгаа процессийн тоог хязгаарлах"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Апп нь нэг зэрэг ажиллах процессийн тооны дээд утгыг удирдах боломжтой. Энгийн апп-д хэзээ ч ашиглагдахгүй."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"арын апп-г хүчээр хаах"</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Эзэмшигч нь VPN үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"ханын зурагтай холбох"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Эзэмшигч нь ханын зурагны дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-уудад шаардлагагүй."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"алсын дэлгэцтэй холбогдох"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Апп нь тоглуулах үедээ код тайлахдаа суулгагдсан ямарч медиа код тайлагчийг ашиглах боломжтой."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"итгэмжлэгдсэн жуухуудыг удирдах"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Апп-д CA сертификатуудыг итгэмжлэгдсэн жуух байдлаар суулгах болон устгахыг зөвшөөрнө."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"Сул зогсолтын хугацаанд аппликешнийг ажиллуулна"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Энэ зөвшөөрөл нь Андройд системд төхөөрөмжийг ашиглахгүй байгаа үед аппликешныг далд ажиллуулах боломж олгоно."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"идэвхгүй үйлчилгээнүүдтэй холбогдох"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Энэ зөвшөөрөл Андройд системд аппликешний идэвхгүй үйлчилгээтэй холбогдох боломж олгоно."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"оношлох грүпийн эзэмшдэг нөөцрүү унших/бичих"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Апп нь оношлох грүпийн эзэмшдэг, жишээ нь /dev доторх файлууд, дурын  нөөцийг унших бичих боломжтой.Энэ нь системийн тогвортой байдал болон аюулгүй байдалд бодитоор нөлөөлнө. Энэ нь үйлдвэрлэгч болон операторын хардверт-зориулсан оношлогоонд ашиглагдана."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"апп компонентыг идэвхжүүлэх эсвэл идэвхгүй болгох"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Апп нь таны нэр болон холбоо барих мэдээлэл зэрэг таны утсан дээр хадгалагдсан хувийн профайл мэдээллийг унших боломжтой. Ингэснээр апп нь танийг таньж чадах ба таны профайл мэдээллийг бусдад илгээх боломжтой."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"та өөрийн харилцагчийн картыг өөрчлөх"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Апп нь таны нэр болон холбоо барих мэдээлэл зэрэг таны төхөөрөмж дээр хадгалагдсан хувийн профайл мэдээллийг солих эсвэл нэмэх боломжтой. Ингэснээр апп нь танийг таньж чадах ба таны профайл мэдээллийг бусдад илгээх боломжтой."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"биеийн сенсор (зүрхний цохилт хянагч гэх мэт)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Зүрхний цохилт гэх мэт биеийн үзүүлэлт хэмждэг сенсоруудын дата-д хандалт хийх боломжийг апп-д олгоно."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"таны нийтийн урсгалаас унших"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Апп нь та болон таны найзуудын нийтийн шинэчлэлтэд хандах болон синк хийх боломжтой. Мэдээлэл хуваалцахдаа болгоомжтой байна уу - энэ нь апп-д нийтийн сүлжээндэх та болон таны найзууд хоорондын холбоог нууц эсэхээс үл хамааран унших боломжтой. Анхаар: энэ зөвшөөрөл нь бүх нийтийн сүлжээнд ашиглаж боломжгүй."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"Таны нийтийн урсгалруу бичих"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Апп-н төхөөрөмжийн утасны функцийг удирдах боломжтой. Энэ зөвшөөрөлтэй апп  нь танд анхааруулахгүйгээр сүлжээг сэлгэх, утасны радиог асаах, унтраах боломжтой."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"утасны статус ба таниулбарыг унших"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Апп нь төхөөрөмжийн утасны функцд хандах боломжтой. Энэ зөвшөөрөл нь апп-д утасны дугаар болон төхөөрөмжийн ID-г, дуудлага идэвхтэй эсэх, холын дугаар дуудлагаар холбогдсон байгаа эсэхийг тогтоох боломжийг олгоно,"</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"утасны байдлыг нарийн унших"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Апп-д утасны тодорхой байдалд хандах боломжийг олгодог. Энэ зөвшөөрөл апп-д дуудлагын бодит статус, дуудлага идэвхтэй эсхүл ар талд тавигдсан эсэх, амжилтгүй дуудлага болон дата холболтын нарийн статус болон дата холболтын алдааг тодорхойлох боломж олгоно."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"таблетыг унтуулахгүй байлгах"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"утсыг унтуулахгүй байлгах"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Апп нь таблетыг унтахаас сэргийлэх боломжтой"</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX статусыг өөрчлөх"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Апп нь WiMAX сүлжээнд таблетыг холбох болон салгах боломжтой."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Апп нь WiMAX сүлжээнд утсыг холбох болон салгах боломжтой."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"бүртгэгдсэн сүлжээ"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Апп-д сүлжээнүүдийг эрэмбэлж, аль сүлжээнд таблетыг холбоход нөлөөлөх боломж олгоно."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Апп-д сүлжээнүүдийг эрэмбэлж, аль сүлжээнд утсыг холбоход нөлөөлөх боломж олгоно."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"Блютүүт төхөөрөмжтэй хос үүсгэх"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Апп нь таблет дээрх блютүүт тохиргоог харах боломжтой ба хос болох төхөөрөмжтэй холболтыг зөвшөөрөх болон хийх боломжтой."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Апп нь утсан дээрх Блютүүт тохиргоог харах боломжтой ба хос болох төхөөрөмжтэй холболтыг зөвшөөрөх болон хийх боломжтой."</string>
@@ -703,18 +685,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Апп нь бусад апп-уудын илгээсэн мэдэгдлүүдийг дуудах, шалгах, болон цэвэрлэх боломжтой."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"мэдэгдэл сонсогч үйлчилгээтэй холбох"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Эзэмшигч нь мэдэгдэл сонсох үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"үүрэн компанийн нийлүүлсэн тохируулгын апп-г өдөөх"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Эзэмшигчид үүрэн компанийн нийлүүлсэн тохируулах апп-г өдөөх боломж олгоно. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Сүлжээний байдлын талаар ажиглалтуудыг хүлээн авах"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Аппликешнд сүлжээний байдлын талаар ажиглалтуудыг хүлээн авахыг зөвшөөрнө. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"оролтын төхөөрөмжийн калибрешныг өөрчлөх"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Мэдрэгчтэй дэлгэцний калибрешн параметрийг өөрчлөхийг апп-д зөвшөөрнө. Энгийн апп-д шаардлагагүй."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"хандалтын DRM сертификат"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Аппликешнд DRM сертификатыг ашиглах болон нийлүүлэхийг зөвшөөрнө. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Нууц үгний дүрмийг тохируулах"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Дэлгэц түгжих нууц үгэнд зөвшөөрөгдсөн тэмдэгт болон уртыг удирдах"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Дэлгэц тайлах оролдлогыг хянах"</string>
@@ -989,7 +963,7 @@
     <string name="permlab_setAlarm" msgid="1379294556362091814">"сэрүүлэг тохируулах"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Апп нь суулгагдсан сэрүүлэгний апп дээр сэрүүлэг тохируулах боломжтой. Зарим сэрүүлэгний апп нь энэ функцийг дэмжихгүй байж болзошгүй."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"дуут шуудан нэмэх"</string>
-    <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Таны дуут шуудангийн ирсэн мэйлд зурвас нэмэхийг апп-д зөвшөөрөх."</string>
+    <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Апп нь таны дуут шуудангийн ирсэн мэйлд мессеж нэмэх боломжтой."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Хөтчийн геобайршлын зөвшөөрлийг өөрчлөх"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Апп нь Хөтчийн гео байршлын зөвшөөрлийг өөрчлөх боломжтой. Хортой апп нь энийг ашиглан дурын веб хуудасруу байршлын мэдээллийг илгээх боломжтой."</string>
     <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"багцийг тулгах"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Аппликешн нь хамгаалалттай аюулгүй санд хандах боломжтой."</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>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Итгэмжлэгдсэн төлөөлөгчийн үйлчилгээтэй холбогдох"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Аппликешнд итгэмжлэгдсэн төлөөлөгчтэй холбогдох боломж олгоно."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Шинэчлэлт болон сэргээх системтэй харилцах"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Аппликешнд сэргээх систем болон системийн шинэчлэлтэй харилцах боломж олгоно."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Өсгөх контрол дээр хоёр удаа товшино уу"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Ханын зураг"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Ханын зураг солих"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Мэдэгдэл сонсогч"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN идэвхтэй болов"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN-г <xliff:g id="APP">%s</xliff:g> идэвхтэй болгов"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Сүлжээг удирдах бол хүрнэ үү."</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index d0d4223..6ebdfe1 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Penyegerakan"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Terlalu banyak pemadaman <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Storan tablet penuh. Padamkan beberapa fail untuk mengosongkan ruang."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Storan tontonan penuh. Padamkan beberapa fail untuk mengosongkan ruang."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Storan telefon penuh. Padamkan beberapa fail untuk mengosongkan ruang."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Rangkaian mungkin dipantau"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Oleh pihak ketiga yang tidak diketahui"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Pendering dihidupkan"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Mematikan..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tablet anda akan dimatikan."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Tontonan anda akan dimatikan."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefon anda akan dimatikan."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Adakah anda mahu menutup?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"But semula ke mod selamat"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mod pesawat"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mod selamat"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"nyahpasang pintasan"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Membenarkan aplikasi mengalih keluar pintasan Skrin Laman Utama tanpa campur tangan pengguna."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"tukar laluan panggilan keluar"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Membenarkan apl melihat nombor yang didail semasa panggilan keluar dengan pilihan untuk mengubah hala panggilan ke nombor lain atau membatalkan terus panggilan."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Membenarkan apl memproses panggilan keluar dan menukar nombor yang perlu didail. Kebenaran ini membolehkan apl memantau, mengalih atau menghalang panggilan keluar."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"terima mesej teks (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Membenarkan apl menerima dan memproses mesej SMS. Ini bermakna apl boleh memantau atau memadam mesej yang dihantar ke peranti anda tanpa menunjukkannya kepada anda."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"terima mesej teks (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Membenarkan apl untuk mendapatkan kandungan tetingkap aktif. Apl hasad boleh mengambil keseluruhan kandungan tetingkap dan memeriksa semua teks kecuali kata laluan."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"dayakan kebolehcapaian untuk sementara"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Membenarkan aplikasi untuk mendayakan kebolehcapaian untuk sementara pada peranti. Apl hasad mungkin mendayakan kebolehcapaian tanpa izin pengguna."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"dapatkan kembali token tetingkap"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Membenarkan apl mendapatkan kembali token tetingkap. Apl hasad mungkin meniru sistem dan menjalankan interaksi yang tidak dibenarkan dengan tetingkap aplikasi."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"dapatkan kembali statistik bingkai"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Membenarkan aplikasi mengumpul statistik bingkai. Apl hasad mungkin memerhatikan statistik bingkai tetingkap dari apl lain."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"dapatkan maklumat tetingkap"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Membolehkan aplikasi mendapatkan maklumat tentang tetingkap dari pengurus tetingkap. Apl hasad boleh mendapatkan maklumat yang bertujuan untuk penggunaan sistem dalaman."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"tapis acara"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Membenarkan aplikasi mendaftarkan penapis input yang menapis strim semua acara pengguna sebelum dihantar. Apl hasad mungkin mengawal UI sistem tanpa campur tangan pengguna."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"besarkan paparan"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Membenarkan aplikasi membesarkan kandungan paparan. Apl hasad mungkin mengubah kandungan paparan yang akan membuatkan peranti tidak boleh digunakan."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"penutupan separa"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Meletakkan pengurus aktiviti dalam keadaan tutup. Tidak melaksanakan penutupan lengkap."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"halang pertukaran apl"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Membenarkan apl untuk menyiarkan pemberitahuan bahawa mesej SMS telah diterima. Apl hasad boleh menggunakannya untuk memalsukan mesej SMS masuk."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"hantar siaran WAP-TOLAK-diterima"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Membenarkan apl untuk menyiarkan pemberitahuan bahawa mesej WAP PUSH telah diterima. Apl hasad boleh menggunakannya untuk memalsukan penerimaan mesej MMS atau secara diam-diam menggantikan kandungan mana-mana laman web dengan varian hasad."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"hantar siaran markah rangkaian"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Membenarkan apl menyiarkan pemberitahuan bahawa rangkaian perlu diberi markah. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"hadkan bilangan proses yang dijalankan"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Membenarkan apl untuk mengawal bilangan maksimum proses yang akan berlangsung. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"memaksa apl latar belakang untuk menutup"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan Vpn. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"terikat pada kertas dinding"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi kertas dinding. Tidak sekali-kali diperlukan untuk apl biasa."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"terikat kepada paparan jauh"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi paparan jauh. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"terikat kepada perkhidmatan widget"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi input TV. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"tambah atau alih keluar pentadbir peranti"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Membenarkan pemegang menambah atau mengalih keluar pentadbir peranti aktif. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"tukar orientasi skrin"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Membenarkan apl untuk menggunakan sebarang penyahkod media yang dipasangkan untuk menyahkod main semula."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"urus bukti kelayakan yang dipercayai"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Membenarkan apl memasang dan menyahpasang sijil CA sebagai bukti kelayakan yang dipercayai."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"jalankan aplikasi pada masa melahu"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Kebenaran ini membolehkan sistem Android menjalankan aplikasi di latar belakang semasa peranti tidak digunakan."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"diikat ke perkhidmatan melahu"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Kebenaran ini membolehkan sistem Android mengikat kepada perkhidmatan melahu aplikasi."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"baca/tulis ke sumber yang dimiliki oleh diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Membenarkan apl membaca dan menulis ke sebarang sumber yang dimiliki oleh kumpulan diag; contohnya, fail dalam /dev. Hal ini berpotensi menjejaskan kestabilan dan keselamatan sistem. Perkara ini seharusnya HANYA digunakan untuk diagnosis khusus perkakasan oleh pengilang atau pengendali."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"dayakan atau lumpuhkan komponen apl"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Membenarkan apl membaca maklumat profil peribadi yang disimpan dalam peranti anda, seperti nama dan maklumat kenalan anda. Ini bermakna apl lain boleh mengenal pasti anda dan menghantar maklumat profil anda kepada orang lain."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"ubah suai kad kenalan sendiri"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Membenarkan apl menukar atau menambah maklumat profil peribadi yang disimpan pada peranti anda, seperti nama dan maklumat kenalan anda. Ini bermakna apl boleh mengenal pasti anda dan menghantar maklumat profil anda kepada orang lain."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"penderia (spt. denyut jantung)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Membenarkan apl mengakses data dari penderia yang anda gunakan untuk mengukur perkara yang berlaku dalam tubuh anda, seperti kadar denyutan jantung."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"baca aliran sosial anda"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Membenarkan apl mengakses dan menyegerakkan kemas kini sosial daripada anda dan rakan anda. Berhati-hati semasa berkongsi maklumat - ini membenarkan apl untuk membaca komunikasi di antara anda dan rakan anda pada rangkaian sosial tanpa mengira kerahsiaan. Nota: kebenaran ini tidak boleh dikuatkuasakan pada semua rangkaian sosial."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"tulis ke aliran sosial anda"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Membenarkan apl untuk mengawal ciri-ciri telefon peranti. Apl dengan kebenaran ini boleh menukar rangkaian, menghidupkan dan mematikan radio telefon dan sebagainya tanpa memberitahu anda."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"baca status dan identiti telefon"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Membenarkan apl mengakses ciri telefon pada peranti. Kebenaran ini membolehkan apl menentukan nombor telefon dan ID peranti, sama ada panggilan aktif dan nombor jauh yang dihubungkan dengan panggilan."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"baca keadaan telefon yang tepat"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Membenarkan apl mengakses keadaan telefon yang tepat. Kebenaran ini membolehkan apl menentukan status panggilan sebenar, sama ada panggilan aktif atau di latar belakang, kegagalan panggilan, status sambungan data yang tepat dan kegagalan sambungan data."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"menghalang tablet daripada tidur"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"halang telefon daripada tidur"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Membenarkan apl menghalang tablet daripada tidur."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Tukar keadaan WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Membenarkan apl untuk menyambungkan tablet ke dan menyahsambungkan tablet dari rangkaian WiMaX."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Membenarkan apl untuk menyambungkan telefon ke dan menyahsambung telefon dari rangkaian WiMaX."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"beri markah kepada rangkaian"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Membenarkan apl menilai rangkaian dan mempengaruhi rangkaian yang harus dipilih oleh tablet."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Membenarkan apl menilai rangkaian dan mempengaruhi rangkaian yang harus dipilih oleh telefon."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"berpasangan dengan peranti Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Membenarkan apl melihat konfigurasi Bluetooth pada tablet dan untuk membuat serta menerima sambungan dengan peranti yang dipasangkan."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Membenarkan apl melihat konfigurasi Bluetooth pada telefon dan membuat serta menerima sambungan dengan peranti yang dipasangkan."</string>
@@ -703,18 +683,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"gunakan apl konfigurasi yang disediakan oleh pembawa"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Membenarkan pemegang menggunakan apl konfigurasi yang diberikan oleh pembawa. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"dengar pemerhatian mengenai keadaan rangkaian"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Membenarkan aplikasi mendengar pemerhatian tentang keadaan rangkaian. Tidak sekali-kali diperlukan untuk apl biasa."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"tukar penentukuran peranti input"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Membenarkan apl mengubah suai parameter penentukuran skrin sentuh. Ini tidak sekali-kali diperlukan untuk apl biasa."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"akses sijil DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Membenarkan aplikasi memperuntuk dan menggunakan sijil DRM. 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="policylab_watchLogin" msgid="914130646942199503">"Memantau percubaan buka kunci skrin"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Membenarkan aplikasi mengakses storan selamat pengawal kekunci."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Kawal paparkan dan sembunyikan pengawal kekunci"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Membenarkan aplikasi untuk mengawal pengawal kekunci."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Dengar perubahan keadaan amanah."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Membenarkan aplikasi mendengar perubahan dalam keadaan amanah."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Mengikat kepada perkhidmatan ejen amanah"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Membenarkan aplikasi terikat kepada perkhidmatan ejen amanah."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Berinteraksi dengan kemas kini dan sistem pemulihan"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Membenarkan aplikasi berinteraksi dengan sistem pemulihan dan kemas kini sistem."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Sentuh dua kali untuk mendapatkan kawalan zum"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Kertas dinding"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Tukar kertas dinding"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Pendengar pemberitahuan"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN diaktifkan"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN diaktifkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Sentuh untuk mengurus rangkaian."</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 2c90ba3..26b27fb 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synkronisering"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"For mange slettinger av <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Nettbrettlageret er fullt. Slett noen filer for å frigjøre lagringsplass."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Klokkens lagringsplass er full. Slett filer for å frigjøre plass."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Telefonlageret er fullt. Slett noen filer for å frigjøre lagringsplass."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Nettverket blir muligens overvåket"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Av en ukjent tredjepart"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Ringelyd på"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Avslutter…"</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Nettbrettet slås av."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Klokken slås av."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefonen kommer til å slås av."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Vil du slå av?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Start på nytt i sikker modus"</string>
@@ -166,14 +164,13 @@
     <string name="global_action_power_off" msgid="4471879440839879722">"Slå av"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Feilrapport"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Utfør feilrapport"</string>
-    <string name="bugreport_message" msgid="398447048750350456">"Informasjon om tilstanden til enheten din samles inn og sendes som en e-post. Det tar litt tid fra du starter feilrapporten til e-posten er klar, så vær tålmodig."</string>
+    <string name="bugreport_message" msgid="398447048750350456">"Informasjon om den nåværende tilstanden til enheten din samles inn og sendes som en e-post. Det tar litt tid fra du starter feilrapporten til e-posten er klar, så vær tålmodig."</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Stillemodus"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Lyden er av"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Lyden er på"</string>
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flymodus"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Sikkermodus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"avinstallere snarveier"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Lar appen fjerne snarveier på startsiden uten å involvere brukeren."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"omdirigere utgående anrop"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Lar appen se nummeret det ringes til under en utgående samtale, med mulighet for å omdirigere anropet til et annet nummer eller avbryte samtalen fullstendig."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Lar appen behandle utgående anrop og endre nummeret som skal ringes opp. Denne tillatelsen lar appen overvåke, viderekoble eller hindre utgående anrop."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"motta tekstmeldinger (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Lar appen motta og behandle tekstmeldinger. Dette betyr at appen kan overvåke eller slette meldinger som er sendt til enheten din uten at du har sett dem."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"motta tekstmeldinger (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Lar appen hente ut innholdet i det aktive vinduet. Ondsinnede apper kan hente ut hele vindusinnholdet og undersøke all teksten, med unntak av passord."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"aktivere tilgjengelighet midlertidig"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Lar en app midlertidig aktivere tilgjengelighet på enheten. Skadelige apper kan aktivere tilgjengelighet uten bekreftelse fra brukeren."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"hente vindustoken"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Gir appen tillatelse til å hente vindustokenet. Skadelige apper kan sette igang uautorisert samhandling med appvinduet ved å imitere systemet."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"hente bildestatistikk"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Gir appen tillatelse til å samle inn bildestatistikk. Skadelige apper kan observere bildestatistikken til vinduer i andre apper."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"hente vindusinformasjon"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Lar appen hente informasjon om vinduene fra vindusbehandleren. Skadelige apper kan hente informasjon som ikke er ment for intern systembruk."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filtrere hendelser"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Lar appen registrere et inndatafilter som filtrerer strømmen for alle brukerhendelser før de sendes ut. Skadelige apper kan kontrollere brukergrensesnittet for systemet uten at brukeren gjør noe."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"forstørre visningen"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Lar apper forstørre innholdet  på en skjerm. Skadelige apper kan endre skjerminnhold på en måte som gjør at enheten blir ubrukelig."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"delvis avslutning"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Lar appen sette aktivitetshåndtereren i avslutningstilstand. Slår ikke systemet helt av."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"forhindre bytte mellom apper"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Lar appen kringkaste et varsel om at en SMS-melding er mottatt. Ondsinnede apper kan bruke dette til å forfalske innkommende SMS-meldinger."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"kringkaste melding om mottatt WAP-PUSH"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Lar appen kringkaste et varsel om at en WAP-PUSH-melding er mottatt. Ondsinnede apper kan bruke dette til å forfalske MMS-meldingskvitteringer, eller ubemerket erstatte innholdet av alle slags nettsider med ondsinnede varianter."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"sende kringkasting om nettverksvurdering"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Gir appen tillatelse til å kringkaste et varsel om at nettverk må vurderes. Denne tillatelsen bør aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"begrense antallet kjørende prosesser"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Lar appen kontrollere det maksimale antallet prosesser som kjører. Aldri nødvendig for vanlige apper."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"tvinge bakgrunnsapper til å lukkes"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Lar innehaveren binde seg til det øverste nivået av grensesnittet for en VPN-tjeneste. Skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"binde til bakgrunnsbilde"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Lar innehaveren binde det øverste nivået av grensesnittet til en bakgrunn. Skal aldri være nødvendig for vanlige apper."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"binde til ekstern skjerm"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lar innehaveren binde seg til det øverste grensesnittnivået for ekstern skjerm. Skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"binde til modultjenste"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Lar innehaveren binde appen til det øverste grensesnittnivået for en TV-inngang. Dette skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"legge til eller fjerne en enhetsadministrator"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Tillater innehaveren å legge til eller fjerne aktive enhetsadministratorer. Dette skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"snu skjermen"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Lar appen bruke en hvilken som helst installert mediedekoder for å dekode for avspilling."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrer pålitelig legitimasjon"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lar appen installere og avinstallere CA-sertifikater som pålitelig legitimasjon."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"kjør appen når den ikke er i bruk"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Denne tillatelsen gjør at Android-systemet kan kjøre appen i bakgrunnen mens enheten ikke er i bruk."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"knytt til inaktive tjenester"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Denne tillatelsen gjør at Android-systemet kan binde seg til appers inaktive tjenester."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lese/skrive ressurser eid av diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Lar appen lese og skrive til alle ressurser som eies av gruppen «diag», som for eksempel filer i /dev. Dette kan potensielt påvirke systemets sikkerhet og stabilitet. Dette bør BARE brukes av produsenten eller operatøren til maskinvarespesifikk diagnostikk."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivere eller deaktivere appkomponenter"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Lar appen lese personlig profilinformasjon som er lagret på enheten, som for eksempel navn og kontaktinformasjon. Dette betyr at appen kan identifisere deg og sende profilinformasjonen din til andre."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"endre ditt eget kontaktkort"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Lar appen endre eller legge til personlig profilinformasjon som er lagret på enheten din, som for eksempel navn og kontaktinformasjon. Dette betyr at appen kan identifisere deg og sende profilinformasjonen din til andre."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"kroppssensorer (som pulsmålere)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Gir appen tillatelse til å bruke data fra sensorer du bruker til å måle det som skjer i kroppen din, som f.eks. pulsen."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"lese din sosiale strøm"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Lar appen lese og synkronisere sosiale oppdateringer fra deg selv og vennene dine. Vær forsiktig når du deler informasjon - med denne tillatelsen kan appen lese kommunikasjon mellom deg og vennene dine på sosiale nettverk, uavhengig av konfidensialitet. Vær oppmerksom på at denne tillatelsen kanskje ikke gjelder for alle sosiale nettverk."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"skrive i din sosiale strøm"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Lar appen kontrollere telefonfunksjonene til enheten. En app som har denne tillatelsen kan bytte nettverk, slå telefonens radio på og av og lignende, uten å varsle deg i det hele tatt."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"lese telefonstatus og -identitet"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Lar appen bruke enhetens telefonfunksjoner. Med denne tillatelsen kan appen finne telefonnummer og enhets-ID-er, registrere om en samtale pågår, og se det eksterne nummeret det opprettes en forbindelse med via oppringing."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"lese nøyaktige telefontilstander"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Gir appen tilgang til nøyaktige telefontilstander. Denne tillatelsen gjør at appen kan fastslå den faktiske anropstatusen, om et anrop er aktivt eller i bakgrunnen, anropsfeil, nøyaktig status for datatilkobling og datatilkoblingsfeil."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"hindre nettbrettet fra å gå over til sovemodus"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"forhindre telefonen fra å sove"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Lar appen hindre nettbrettet fra å gå over i sovemodus."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Endre WiMAX-status"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Lar appen koble nettbrettet til og fra WiMAX-nettverk."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Lar appen koble telefonen til og fra WiMAX-nettverk."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"vurdere nettverk"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Gir appen tillatelse til å rangere nettverk, og påvirke hvilket nettverk nettbrettet skal foretrekke."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Gir appen tillatelse til å rangere nettverk, og påvirke hvilket nettverk telefonen skal foretrekke."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"koble til Bluetooth-enheter"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Lar appen se Bluetooth-konfigurasjonen på nettbrettet, samt opprette og godta tilkoblinger med sammenkoblede enheter."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Lar appen se Bluetooth-konfigurasjonen på telefonen, samt opprette og godta tilkoblinger med sammenkoblede enheter."</string>
@@ -703,18 +683,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"starte konfigurasjonsappen som ble levert av operatøren"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Gir innehaveren tillatelse til å kalle opp den konfigurasjonsappen som ble levert av operatøren. Dette skal ikke være nødvendig for vanlige apper."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"lytte etter observasjoner om nettverksforhold"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Gir appen tillatelse til å lytte etter observasjoner om nettverksforhold. Dette skal ikke være nødvendig for vanlige apper."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"endre kalibreringen av inndataenheter"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Lar appen endre kalibrasjonsparametrene for berøringsskjermen. Denne tillatelsen bør aldri være nødvendig for vanlige apper."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"tilgang til DRM-sertifikater"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Tillater at en app klargjøre og bruke DRM-sertifikater. Denne tillatelsen bør 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="policylab_watchLogin" msgid="914130646942199503">"Overvåk forsøk på opplåsing av skjerm"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Lar en app bruke sikker lagring via keyguard."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Kontrollér om tastelåsen er skjult eller vist"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Tillater at en app kontrollerer tastelåsen."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Oppdag endringer i tillitsstatusen."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Gir appen tillatelse til å oppdage endringer i tillitsstatusen."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Tilknytt en tillitsagent-tjeneste."</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Gir appen tillatelse til å knyttes til en tillitsagent-tjeneste."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Samhandling med oppdateringer og gjenopprettingssystem"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Tillater en app å samhandle med gjenopprettingsssystemet og systemoppdateringer."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Trykk to ganger for zoomkontroll"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Bakgrunnsbilde"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Velg bakgrunnsbilde"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Varsellytteren"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN er aktivert"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN er aktivert av <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Trykk for å administrere nettverket."</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 7821648..b8a7122 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchroniseren"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Te veel verwijderen voor <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Tabletgeheugen is vol. Verwijder enkele bestanden om ruimte vrij te maken."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Horlogegeheugen is vol. Verwijder enkele bestanden om ruimte vrij te maken."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Telefoongeheugen is vol. Verwijder enkele bestanden om ruimte vrij te maken."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netwerk kan worden gecontroleerd"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Door een onbekende derde partij"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Belsoftware aan"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Uitschakelen..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Uw tablet wordt uitgeschakeld."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Uw horloge wordt uitgeschakeld."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Uw telefoon wordt uitgeschakeld."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Wilt u afsluiten?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Opnieuw opstarten in veilige modus"</string>
@@ -173,7 +171,6 @@
     <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_action_settings" msgid="1756531602592545966">"Instellingen"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
     <string name="safeMode" msgid="2788228061547930246">"Veilige modus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-systeem"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"snelkoppelingen verwijderen"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"De app toestaan snelkoppelingen van het startscherm te verwijderen zonder tussenkomst van de gebruiker."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"uitgaande oproepen doorschakelen"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"De app toestaan het nummer te bekijken dat wordt gekozen voor een uitgaande oproep, met de mogelijkheid de oproep om te leiden naar een ander nummer of de oproep helemaal af te breken."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Hiermee kan de app uitgaande oproepen verwerken en het nummer wijzigen dat wordt gebeld. De app kan uitgaande oproepen bijhouden, omleiden of blokkeren."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"tekstberichten (SMS) ontvangen"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Hiermee kan de app sms-berichten ontvangen en verwerken. Dit betekent dat de app berichten die naar uw apparaat zijn verzonden, kan bijhouden of verwijderen zonder deze aan u weer te geven."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"tekstberichten (MMS) ontvangen"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Hiermee kan de app de inhoud van het actieve venster ophalen. Schadelijke apps kunnen de volledige inhoud van het venster ophalen en alle tekst bekijken, behalve wachtwoorden."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"toegankelijkheid tijdelijk inschakelen"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Een app toestaan toegankelijkheid tijdelijk in te schakelen op het apparaat. Schadelijke apps kunnen toegankelijkheid inschakelen zonder toestemming van de gebruiker."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"venstertoken ophalen"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Hiermee kan een app de venstertoken ophalen. Schadelijke apps kunnen niet-geautoriseerde interactie met het appvenster uitvoeren en het systeem nabootsen."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"framestatistieken ophalen"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Hiermee kan een app framestatistieken verzamelen. Schadelijke apps kunnen de framestatistieken voor vensters van andere apps bekijken."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"venstergegevens ophalen"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Toestaan dat een app gegevens over vensters kan ophalen uit vensterbeheer. Schadelijke apps kunnen gegevens ophalen die zijn bedoeld voor interne systeemfunctionaliteit."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"evenementen filteren"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Toestaan dat een app een invoerfilter registreert waarmee de streams van alle gebruikersgebeurtenissen worden gefilterd voordat deze worden verzonden. Schadelijke apps kunnen de gebruikersinterface van het systeem beheren zonder tussenkomst van de gebruiker."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"display vergroten"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Een app toestaan de inhoud van een display te vergroten. Schadelijke apps kunnen de display-inhoud transformeren op een manier waardoor het apparaat onbruikbaar wordt."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"gedeeltelijke uitschakeling"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Hiermee wordt activiteitenbeheer uitgeschakeld. Er wordt geen volledige uitschakeling uitgevoerd."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"schakelen tussen apps voorkomen"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Hiermee kan de app een melding verzenden dat een sms\'je is ontvangen. Schadelijke apps kunnen dit gebruiken om inkomende sms\'jes te vervalsen."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"melding over ontvangen WAP-PUSH-bericht verzenden"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Hiermee kan de app een melding verzenden dat een WAP PUSH-bericht is ontvangen. Schadelijke apps kunnen dit gebruiken om de ontvangst van MMS-berichten te vervalsen of de inhoud van een webpagina ongemerkt te vervangen door schadelijke varianten."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"melding verzenden dat netwerken een score moeten krijgen"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Hiermee kan de app een melding uitzenden dat netwerken een score moeten krijgen. Nooit vereist voor normale apps."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"aantal actieve processen beperken"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Hiermee kan de app het maximale aantal processen beheren dat kan worden uitgevoerd. Nooit nodig voor normale apps."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"achtergrondapps gedwongen stoppen"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Staat de houder toe verbinding te maken met de hoofdinterface van een VPN-service. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"verbinden met een achtergrond"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Hiermee wordt de houder toegestaan zich te verbinden met de hoofdinterface van een achtergrond. Nooit vereist voor normale apps."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"verbinding maken met een extern display"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een extern display. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"verbinden met een widgetservice"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Hiermee wordt de houder toegestaan te binden aan de hoofdinterface van een tv-ingang. Nooit vereist voor normale apps."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"een apparaatbeheerder toevoegen of verwijderen"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Hiermee kan de rechtenhouder actieve apparaatbeheerders toevoegen of verwijderen. Nooit vereist voor normale apps."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"schermstand wijzigen"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Hiermee kan de app alle geïnstalleerde mediadecoders gebruiken om te decoderen voor het afspelen."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"vertrouwde inloggegevens beheren"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Hiermee kan de app CA-certificaten installeren en verwijderen als vertrouwde inloggegevens."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"app uitvoeren tijdens inactiviteit"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Met dit recht kan het Android-systeem de app op de achtergrond uitvoeren terwijl het apparaat niet wordt gebruikt."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"koppelen aan inactieve services"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Met deze toestemming kan het Android-systeem koppelen aan de inactieve services van een app."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"lezen/schrijven naar bronnen van diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Hiermee kan de app lezen en schrijven naar elke bron die hoort bij de diagnostische groep, zoals bestanden in /dev. Hierdoor kan de systeemstabiliteit en -veiligheid worden beïnvloed. Dit mag ALLEEN worden gebruikt voor hardwarespecifieke diagnostiek door de fabrikant of provider."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"componenten van apps in- of uitschakelen"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Hiermee kan de app persoonlijke profielgegevens lezen die op uw apparaat zijn opgeslagen, zoals uw naam en contactgegevens. Dit betekent dat de app u kan identificeren en uw profielgegevens naar anderen kan verzenden."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"uw eigen contactkaart aanpassen"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Hiermee kan de app persoonlijke profielgegevens wijzigen of toevoegen die op uw apparaat zijn opgeslagen, zoals uw naam en contactgegevens. Dit betekent dat de app u kan identificeren en uw profielgegevens naar anderen kan verzenden."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"lichaamssensoren (zoals hartslagmeters)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Toestaan dat de app toegang krijgt tot gegevens van sensoren die u gebruikt om te meten wat er gebeurt in uw lichaam, zoals de hartslag."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"uw sociale stream lezen"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Hiermee kan de app toegang krijgen tot sociale updates van u en uw vrienden en deze synchroniseren. Wees voorzichtig bij het delen van informatie: hiermee kan de app communicatie lezen tussen u en uw vrienden op sociale netwerken, ongeacht de vertrouwelijkheid. Opmerking: deze toestemming kan niet worden afgedwongen voor alle sociale netwerken."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"schrijven naar sociale streams"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Hiermee kan de app de telefoonfuncties van het apparaat beheren. Een app met deze toestemming kan schakelen tussen netwerken, kan de radio van de telefoon in- en uitschakelen en dergelijke acties uitvoeren zonder dat u hiervan op de hoogte wordt gesteld."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"telefoonstatus en -identiteit lezen"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Hiermee kan de app toegang krijgen tot de telefoonfuncties van het apparaat, Met deze toestemming kan de app het telefoonnummer en de apparaat-ID\'s bepalen, of een oproep actief is, en het andere telefoonnummer waarmee wordt gebeld."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"exacte telefoonstatus lezen"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Toestaan dat de app toegang krijgt tot de exacte telefoonstatus. Hiermee kan de app bepalen wat de echte oproepstatus is, of een oproep actief is of zich op de achtergrond bevindt, of er mislukte oproepen zijn, wat de exacte status van de gegevensverbinding is en of er mislukte gegevensverbindingen zijn."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"voorkomen dat tablet overschakelt naar slaapmodus"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"voorkomen dat telefoon overschakelt naar slaapmodus"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Hiermee kan de app voorkomen dat de tablet overschakelt naar de slaapmodus."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX-status wijzigen"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Hiermee kan de app de tablet verbinden met WiMAX-netwerken en de verbinding daarmee verbreken."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Hiermee kan de app de telefoon verbinden met WiMAX-netwerken en de verbinding daarmee verbreken."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"score toekennen aan netwerken"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Hiermee kan de app netwerken rangschikken en beïnvloeden aan welke netwerken de tablet de voorkeur moet geven."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Hiermee kan de app netwerken rangschikken en beïnvloeden aan welke netwerken de telefoon de voorkeur moet geven."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"koppelen met Bluetooth-apparaten"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Hiermee kan de app de Bluetooth-configuratie van de tablet bekijken en verbindingen met gekoppelde apparaten maken en accepteren."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Hiermee kan de app de Bluetooth-configuratie van de telefoon bekijken en verbindingen met gekoppelde apparaten maken en accepteren."</string>
@@ -703,18 +683,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"de door de provider geleverde configuratie-app aanroepen"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Hiermee kan de houder de door de provider geleverde configuratie-app aanroepen. Nooit vereist voor normale apps."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"controleren op waarnemingen met betrekking tot netwerkomstandigheden"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Hiermee kan een app controleren op waarnemingen met betrekking tot netwerkomstandigheden. Nooit vereist voor normale apps."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"kalibratie van invoerapparaat wijzigen"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Hiermee kan de app de kalibratieparameters van het aanraakscherm aanpassen. Nooit vereist voor normale apps."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"toegang tot DRM-certificaten"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Toestaan dat een app DRM-certificaten registreert en gebruikt. 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="policylab_watchLogin" msgid="914130646942199503">"Pogingen voor schermontgrendeling bijhouden"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Hiermee krijgt een app toegang tot opslag met toetsbeveiliging."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Weergeven en verbergen van toetsbeveiliging beheren"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Staat toe dat een app de toetsbeveiliging beheert."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Controleren op wijzigingen in de trust-status."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Toestaan dat een app controleert op wijzigingen in de trust-status."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Binden aan een trust-agentservice"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Toestaan dat een app wordt gebonden aan een trust-agentservice."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interactie met update- en herstelsysteem"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Hiermee kan een app interactie hebben met het herstelsysteem en systeemupdates."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Raak twee keer aan voor zoomregeling"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Achtergrond"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Achtergrond wijzigen"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Listener voor meldingen"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN is geactiveerd"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN wordt geactiveerd door <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Raak aan om het netwerk te beheren."</string>
@@ -1541,9 +1507,9 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay <xliff:g id="ID">%1$d</xliff:g>"</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>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", beveiligd"</string>
-    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Scherm casten"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Scherm sturen"</string>
     <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Verbinden met <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Scherm casten"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Scherm sturen"</string>
     <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Verbonden met <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Verbinding verbreken"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Noodoproep"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 3cbd980..8aa847f 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -135,10 +135,9 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronizuj"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Zbyt wiele usuwanych <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Pamięć tabletu jest pełna. Usuń niektóre pliki, aby zwolnić miejsce."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Pamięć w zegarku jest pełna. Usuń niektóre pliki, by zwolnić miejsce."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Pamięć telefonu jest pełna. Usuń niektóre pliki, aby zwolnić miejsce."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Sieć może być monitorowana"</string>
-    <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Przez nieznany podmiot zewnętrzny"</string>
+    <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Przez nieznaną firmę zewnętrzną"</string>
     <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Przez <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
     <string name="me" msgid="6545696007631404292">"Ja"</string>
     <string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opcje tabletu"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Dzwonek włączony"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Wyłączanie..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tablet zostanie wyłączony."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Zegarek zostanie wyłączony."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefon zostanie wyłączony"</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Czy chcesz wyłączyć?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Uruchom w trybie awaryjnym"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Tryb samolotowy"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Tryb awaryjny"</string>
     <string name="android_system_label" msgid="6577375335728551336">"System Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"odinstalowywanie skrótów"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Pozwala aplikacji usuwać skróty z ekranu głównego bez interwencji użytkownika."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"przekierowywanie połączeń wychodzących"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Pozwala aplikacji na sprawdzenie numeru wybieranego w trakcie połączenia wychodzącego, a także umożliwia przerwanie połączenia lub przekierowanie go pod inny numer."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Pozwala aplikacji na przetwarzanie połączeń wychodzących i zmianę wybieranego numeru. Aplikacje z tym uprawnieniem mogą monitorować, przekierowywać lub blokować połączenia wychodzące."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"odbieranie wiadomości tekstowych (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Pozwala aplikacji na odbieranie i przetwarzanie SMS-ów. To oznacza, że aplikacja będzie mogła bez Twojej wiedzy monitorować i usuwać wiadomości wysyłane do Twojego urządzenia."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"odbieranie wiadomości tekstowych (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Pozwala aplikacji na pobieranie zawartości aktywnego okna. Złośliwe aplikacje mogą pobrać całą zawartość okna i przeanalizować znajdujący się w nim tekst z wyjątkiem haseł."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"tymczasowo włącz ułatwienia dostępu"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Umożliwia aplikacji tymczasowe włączanie ułatwień dostępu na urządzeniu. Złośliwe aplikacje mogą je włączać bez zgody użytkownika."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"pobieranie tokenu okna"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Zezwala aplikacji na pobieranie tokenu okna. Złośliwe aplikacje mogą podszywać się pod system i bez autoryzacji wchodzić w interakcję z oknem aplikacji."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"pobieranie statystyk klatek"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Zezwala aplikacji na zbieranie statystyk klatek. Złośliwe aplikacje mogą śledzić statystyki klatek wyświetlanych w oknach innych aplikacji."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"pobieranie informacji o oknach"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Zezwala aplikacji na pobieranie informacji o oknach z menedżera okien. Złośliwe aplikacje mogą pobierać informacje przeznaczone do użytku wewnętrznego w systemie."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filtrowanie zdarzeń"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Zezwala aplikacji na zarejestrowanie filtra wejściowego, który filtruje strumień wszystkich zdarzeń z udziałem użytkownika przed ich rozesłaniem. Złośliwe aplikacje mogą kontrolować interfejs systemu niezależnie od działań użytkownika."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"powiększanie ekranu"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Zezwala aplikacji na powiększenie zawartości ekranu. Szkodliwe aplikacje mogą przekształcić zawartość ekranu tak, by urządzenie stało się bezużyteczne."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"częściowe wyłączenie"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Przełącza menedżera aktywności w stan wyłączenia. Nie wykonuje pełnego wyłączenia."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"zapobieganie przełączaniu aplikacji"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Pozwala aplikacji na wysyłanie powiadomienia, że została odebrana wiadomość SMS. Złośliwe aplikacje mogą to wykorzystać do fałszowania przychodzących wiadomości SMS."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"wysyłanie transmisji informującej o otrzymaniu wiadomości WAP-PUSH"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Pozwala aplikacji na nadanie powiadomienia o odebraniu wiadomości WAP PUSH. Złośliwe aplikacje mogą to wykorzystać do fałszowania potwierdzenia odbioru wiadomości MMS lub do niezauważalnego podmieniania zawartości dowolnej strony internetowej jej szkodliwymi wariantami."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"rozsyłanie informacji o ocenie sieci"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Pozwala aplikacji na wysłanie powiadomienia, że sieci wymagają oceny. Nieprzeznaczone dla zwykłych aplikacji."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"ograniczanie liczby uruchomionych procesów"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Pozwala aplikacji na kontrolowanie maksymalnej liczby uruchamianych procesów. Nigdy niewykorzystywane przez normalne aplikacje."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"wymuszanie zamknięcia aplikacji w tle"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Pozwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi VPN. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"powiązanie z tapetą"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Pozwala na tworzenie powiązania z interfejsem najwyższego poziomu tapety. Nieprzeznaczone dla zwykłych aplikacji."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"powiązanie z wyświetlaczem zdalnym"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu wyświetlacza zdalnego. Nieprzeznaczone dla zwykłych aplikacji."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"powiązanie z usługą widżetów"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Zezwala na utworzenie powiązania z głównym interfejsem wejścia TV. Nieprzeznaczone dla zwykłych aplikacji."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"dodaj lub usuń administratora urządzenia"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Umożliwia właścicielowi dodawanie i usuwanie aktywnych administratorów urządzenia. Ta opcja nie jest wykorzystywana w przypadku standardowych aplikacji."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"zmienianie orientacji ekranu"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Pozwala aplikacji na użycie dowolnego zainstalowanego dekodera multimediów do odtwarzania."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"zarządzanie zaufanymi danymi uwierzytelniającymi"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Zezwala aplikacji na instalowanie i odinstalowywanie certyfikatów CA jako zaufanych danych uwierzytelniających."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"uruchom aplikację w czasie bezczynności"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"To uprawnienie pozwala systemowi Android uruchomić aplikację w tle, gdy urządzenie nie jest używane."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"powiązanie z nieaktywnymi usługami"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"To uprawnienie umożliwia powiązanie systemu Android z nieaktywnymi usługami aplikacji."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"czytanie/zapisywanie w zasobach należących do diagnostyki"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Pozwala aplikacji na czytanie i zapisywanie wszystkich zasobów należących do grupy diagnostyki, na przykład plików w katalogu /dev. Może to potencjalnie wpłynąć na stabilność i bezpieczeństwo systemu. Powinno być wykorzystywane WYŁĄCZNIE do diagnozowania sprzętu przez producenta lub operatora."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"włączanie lub wyłączanie składników aplikacji"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Pozwala aplikacji na odczyt osobistych informacji przechowywanych w Twoim profilu na urządzeniu (np. imienia i nazwiska lub adresu). Oznacza to, że aplikacja może Cię zidentyfikować i wysłać informacje z Twojego profilu do innych osób."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"zmiana własnej karty kontaktu"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Pozwala aplikacji na zmianę lub dodanie osobistych informacji przechowywanych w Twoim profilu na urządzeniu (np. imienia i nazwiska lub adresu). Oznacza to, że aplikacja może Cię zidentyfikować i wysłać informacje z Twojego profilu do innych osób."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"czujniki ciała (np. monitorujące tętno)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Zezwala aplikacji na dostęp do danych z czujników mierzących procesy zachodzące w ciele, np. bicie serca (tętno)."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"odczyt sieci społecznościowych"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Pozwala aplikacji na odczyt i synchronizację informacji publikowanych przez Ciebie i Twoich znajomych w sieciach społecznościowych. Zachowaj ostrożność, udostępniając informacje. Aplikacja z tym uprawnieniem może odczytać całą komunikację, którą prowadzisz ze swoimi znajomymi w sieciach społecznościowych, niezależnie od jej poufności. Uwaga: to uprawnienie może nie być egzekwowane we wszystkich sieciach społecznościowych."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"zapis sieci społecznościowych"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Pozwala aplikacji na kontrolowanie funkcji telefonu w urządzeniu. Aplikacja z tymi uprawnieniami może zmieniać, włączać i wyłączać sieci bezprzewodowe itp. bez informowania użytkownika."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"odczytywanie stanu i informacji o telefonie"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Pozwala aplikacji na dostęp do funkcji telefonicznych urządzenia. Aplikacja z tym uprawnieniem może odczytać numer telefonu i identyfikator urządzenia, sprawdzić, czy połączenie jest aktywne, oraz poznać numer, z którym jest nawiązane połączenie."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"dokładne rozpoznawanie stanów telefonu"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Pozwala aplikacji dokładnie rozpoznawać stany telefonu. Aplikacja z tym uprawnieniem może określić rzeczywisty stan połączenia, ustalić, czy jest ono aktywne czy znajduje się w tle, odczytać informacje o nieudanych połączeniach, precyzyjnie określić stan połączenia transmisji danych oraz odczytać informacje o błędach transmisji danych."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"zapobieganie przechodzeniu tabletu do trybu uśpienia"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"zapobieganie przejściu telefonu w stan uśpienia"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Pozwala aplikacji na zapobieganie przechodzeniu tabletu do trybu uśpienia."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"zmienianie stanu WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Pozwala aplikacji na nawiązywanie i kończenie połączeń z sieciami WiMAX w tablecie."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Pozwala aplikacji na nawiązywanie i kończenie połączeń z sieciami WiMAX w telefonie."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ocenianie sieci"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Pozwala aplikacji na ocenę sieci i wybieranie sieci preferowanych przez tablet."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Pozwala aplikacji na ocenę sieci i wybieranie sieci preferowanych przez telefon."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"parowanie z urządzeniami Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Pozwala aplikacji na dostęp do konfiguracji Bluetooth na tablecie oraz na nawiązywanie i akceptowanie połączeń ze sparowanych urządzeń."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Pozwala aplikacji na dostęp do konfiguracji Bluetooth na telefonie oraz na nawiązywanie i akceptowanie połączeń ze sparowanych urządzeń."</string>
@@ -703,18 +683,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"wywoływanie aplikacji konfiguracyjnej udostępnionej przez operatora"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Zezwala na wywoływanie aplikacji konfiguracyjnej udostępnionej przez operatora. Nieprzeznaczone dla zwykłych aplikacji."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"śledź stan sieci"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Pozwala aplikacji śledzić stan sieci. Nieprzeznaczone dla zwykłych aplikacji."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"zmiana kalibracji urządzenia wejściwego"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Zezwala aplikacji na modyfikowanie parametrów kalibracji ekranu dotykowego. Nieprzeznaczone dla zwykłych aplikacji."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"dostęp do certyfikatów DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Zezwala aplikacji na dodanie i używanie certyfikatów DRM. Nieprzeznaczone 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="policylab_watchLogin" msgid="914130646942199503">"Monitoruj próby odblokowania ekranu"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Zezwala aplikacji na dostęp do bezpiecznego magazynu kluczy."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Kontroluj wyświetlanie i ukrywanie zabezpieczenia kluczami"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Umożliwia aplikacji kontrolowanie zabezpieczenia kluczami."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Monitoruj zmiany w stanie zaufania."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Zezwala aplikacji na monitorowanie zmian w stanie zaufania."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Powiąż z usługą agenta zaufania"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Zezwala aplikacji na powiązanie z usługą agenta zaufania."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interakcja z systemem odzyskiwania i aktualizacjami"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Zezwala aplikacji na interakcję z systemem odzyskiwania i aktualizacjami systemu."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Dotknij dwukrotnie, aby sterować powiększeniem."</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Zmień tapetę"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Odbiornik powiadomień"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN aktywny"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Obsługa sieci VPN została włączona przez aplikację <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Dotknij, aby zarządzać siecią."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 1ad8fad..f566881 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronização"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminações de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"O armazenamento do tablet está cheio. Elimine alguns ficheiros para libertar espaço."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"O armazenamento de visualizações está cheio. Elimine alguns ficheiros para libertar espaço."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"O armazenamento do telemóvel está cheio. Elimine alguns ficheiros para libertar espaço."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"A rede pode ser monitorizada"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Por um terceiro desconhecido"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Campainha ativada"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"A encerrar..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"O seu tablet irá encerrar."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"As suas visualizações vão ser encerradas."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"O seu telefone será encerrado."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Pretende encerrar?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Reiniciar no modo de segurança"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo de avião"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"desinstalar atalhos"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Permite que a aplicação remova atalhos do Ecrã principal sem a intervenção do utilizador."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"redirecionar as chamadas efetuadas"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Permite que a aplicação veja o número que é marcado durante uma chamada efetuada, com a opção de redirecionar a chamada para um número diferente ou terminar a chamada."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Permite que a aplicação processe chamadas efetuadas e mude o número a marcar. Esta autorização permite que a aplicação monitorize, redirecione ou impeça a realização de chamadas."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"receber mensagens de texto (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Permite que a aplicação receba e processe mensagens SMS. Isto significa que a aplicação poderá monitorizar ou eliminar mensagens enviadas para o seu dispositivo sem as apresentar."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"receber mensagens de texto (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Permite que a aplicação obtenha o conteúdo da janela ativa. As aplicações maliciosas podem obter todo o conteúdo da janela e examinar todo o texto, exceto as palavras-passe."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"acessibilidade ativada temporariamente"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Permite que uma aplicação ative temporariamente a acessibilidade no dispositivo. As aplicações maliciosas podem ativar a acessibilidade sem o consentimento do utilizador."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"obter token da janela"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Permite que uma aplicação obtenha o token da janela. As aplicações maliciosas podem interagir de forma não autorizada com a janela da aplicação, roubando a identidade do sistema."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"obter estatísticas de fotograma"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Permite que uma aplicação recolha estatísticas de fotograma. As aplicações maliciosas podem observar as estatísticas de fotograma de janelas de outras aplicações."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"obter informações da janela"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Permite que uma aplicação obtenha informações sobre as janelas a partir do gestor de janelas. Aplicações maliciosas podem obter informações que se destinam à utilização interna do sistema."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filtrar eventos"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Permite que uma aplicação registe um filtro de entrada que filtra a transmissão em fluxo contínuo para todos os eventos de utilizador antes de serem entregues. Uma aplicação maliciosa pode controlar a IU do sistema sem intervenção do utilizador."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"ampliar o visor"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Permite que uma aplicação amplie o conteúdo de um visor. As aplicações maliciosas poderão transformar o conteúdo do visor de um modo que torne o dispositivo inutilizável."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"encerramento parcial"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Coloca o gestor de actividade num estado de encerramento. Não executa um encerramento completo."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"impedir trocas de aplicações"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permite que a aplicação difunda uma notificação de que foi recebida uma mensagem SMS. As aplicações maliciosas podem utilizar este recurso para forjar mensagens SMS recebidas."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar difusão recebida através de PUSH WAP"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permite que a aplicação difunda uma notificação de que foi recebida uma mensagens PUSH WAP. As aplicações maliciosas podem utilizar isto para forjar um recibo de mensagem MMS ou substituir, de forma silenciosa, o conteúdo de qualquer página Web por variantes maliciosas."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"enviar transmissão de pontuação de redes"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Permite à aplicação transmitir uma notificação de que é necessário pontuar as redes. Nunca é necessário para aplicações normais."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"número limite de processos em execução"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permite a uma aplicação controlar o número máximo de processos que será executado. Nunca é necessário para aplicações normais."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forçar as aplicações em segundo plano a fechar"</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permite que o titular se vincule à interface de nível superior de um serviço de VPN. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"vincular a uma imagem de fundo"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite ao titular vincular-se à interface de nível superior de uma imagem de fundo. Nunca deverá ser necessário para aplicações normais."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"associar a um ecrã remoto"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite ao detentor associar a interface de nível superior a um ecrã remoto. Nunca deve ser necessário para aplicações normais."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincular a um serviço de widget"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que a aplicação utilize qualquer descodificador de multimédia instalado para descodificar a reprodução."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gerir credenciais fidedignas"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que a aplicação instale e desinstale certificados da AC (Autoridade de certificação) como credenciais fidedignas."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"executar aplicação durante o tempo de inatividade"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Esta autorização permite ao sistema Android executar a aplicação em segundo plano enquanto o dispositivo não estiver a ser utilizado."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"associar a serviços inativos"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Esta autorização permite que o sistema Android seja vinculado aos serviços inativos de uma aplicação."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"ler/escrever em recursos propriedade de diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite à aplicação ler e escrever em qualquer recurso que seja propriedade do grupo diag; por exemplo, ficheiros em /dev. Isto pode potencialmente afetar a estabilidade e a segurança do sistema e deve ser utilizado APENAS para diagnósticos específicos do hardware pelo fabricante ou pelo operador."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"ativar ou desativar componentes da aplicação"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Permite que a aplicação leia dados de perfil pessoais guardados no dispositivo, tais como o seu nome e informações de contacto. Isto significa que outras aplicações podem identificá-lo e enviar os seus dados de perfil a terceiros."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"modificar o próprio cartão de contacto"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Permite que a aplicação altere ou adicione dados de perfil pessoais guardados no dispositivo, tais como o seu nome e informações de contacto. Isto significa que outras aplicações podem identificá-lo e enviar os seus dados de perfil a terceiros."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"sensores corporais (como monitores do ritmo cardíaco)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Permite à aplicação aceder a dados de sensores que o utilizador usa para medir o que está a acontecer no seu corpo, por exemplo o ritmo cardíaco."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"ler o seu fluxo social"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Permite que a aplicação aceda e sincronize atualizações de redes sociais suas e dos seus amigos. Tenha cuidado ao partilhar informações, pois esta ação permite que a aplicação leia comunicações entre si e os seus amigos nas redes sociais, independentemente do grau de confidencialidade. Nota: esta autorização pode não ser aplicada a todas as redes sociais."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"escrever para o seu fluxo social"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permite que a aplicação controle as funcionalidades de telefone do aparelho. Uma aplicação com esta permissão pode alternar entre redes, ligar/desligar o rádio do telefone e outras coisas semelhantes sem sequer o notificar."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"ler o estado e a identidade do telemóvel"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que a aplicação aceda às funcionalidades de telefone do dispositivo. Esta autorização permite que a aplicação determine o número de telefone e IDs do dispositivo, se alguma chamada está ativa e qual o número remoto ligado por uma chamada."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"ler os estados precisos do telemóvel"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permite que a aplicação aceda ao estados precisos do telemóvel. Esta autorização permite que a aplicação determine o estado real da chamada, se uma chamada está ativa ou em segundo plano, falhas em chamadas, o estado preciso da ligação de dados e falhas de ligação de dados."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"impedir que o tablet entre em inactividade"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir modo de inactividade do telefone"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que a aplicação impeça o tablet de entrar no modo de suspensão."</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Alterar estado do WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite que a aplicação ligue e desligue o tablet de redes WiMAX."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permite que a aplicação ligue e desligue o telemóvel de redes WiMAX."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"pontuar redes"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Permite à aplicação classificar redes e influenciar as redes que o tablet deve preferir."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Permite à aplicação classificar redes e influenciar as redes que o telemóvel deve preferir."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"sincronizar com dispositivos Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permite que a aplicação visualize a configuração do Bluetooth no tablet e que estabeleça e aceite ligações com dispositivos emparelhados."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permite que a aplicação visualize a configuração do Bluetooth no telemóvel e que estabeleça e aceite ligações com dispositivos emparelhados."</string>
@@ -703,18 +685,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invocar a aplicação de configuração fornecida pela operadora"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite que o titular invoque a aplicação de configuração fornecida pela operadora. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ouvir observações sobre as condições da rede"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que uma aplicação ouça observações sobre as condições da rede. Nunca deverá ser necessário para aplicações normais."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"alterar a calibragem de entrada do dispositivo"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permite à aplicação modificar os parâmetros de calibragem do ecrã tátil. Esta funcionalidade nunca deverá ser necessária para aplicações normais."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"Aceder a certificados DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Permite que uma aplicação forneça e utilize certificados DRM. Nunca deverá 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="policylab_watchLogin" msgid="914130646942199503">"Monitorizar tentativas de desbloqueio do ecrã"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permite a uma aplicação aceder ao armazenamento seguro de proteção de teclado."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Controlar apresentação e ocultação de proteção de teclado"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permite que uma aplicação controle a proteção de teclado."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Registar alterações no estado trust."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite que uma aplicação registe alterações no trust state."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Vincular a um serviço de trust agent"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite que uma aplicação fique vinculada a um serviço de trust agent."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interagir com o sistema de recuperação e de atualização"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Permite que uma aplicação interaja com o sistema de recuperação e as atualizações do sistema."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Toque duas vezes para controlar o zoom"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Imagem de fundo"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Alterar imagem de fundo"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Serviço de escuta de notificações"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN ativada"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"A VPN foi ativada pelo <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Toque para gerir a rede."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 77e54a4..2cfad8f 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronizar"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Muitas exclusões de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"O armazenamento do tablet está cheio. Exclua alguns arquivos para liberar espaço."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Armazenamento do relógio cheio. Exclua alguns arquivos para liberar espaço."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"O armazenamento do telefone está cheio. Exclua alguns arquivos para liberar espaço."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"A rede pode ser monitorada"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Por terceiros desconhecidos"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Campainha ligada"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Encerrando…"</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Seu tablet será desligado."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Seu relógio será desligado."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"O seu telefone será desligado."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Deseja desligar?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Reiniciar no modo de segurança"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avião"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"desinstalar atalhos"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Permite que o aplicativo remova atalhos da tela inicial sem a intervenção do usuário."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"redirecionar as chamadas efetuadas"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Permite que o aplicativo veja o número discado ao realizar uma chamada, com a opção de redirecionar a chamada para outro número ou abortá-la."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Permite que o aplicativo processe as chamadas de saída e altere o número a ser discado. Esta permissão autoriza o aplicativo a monitorar, redirecionar ou evitar chamadas de saída."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"receber mensagens de texto (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Permite que o aplicativo receba e processe mensagens SMS. Isso significa que o aplicativo pode monitorar ou excluir mensagens enviadas para o dispositivo sem mostrá-las para você."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"receber mensagens de texto (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Permite que o aplicativo recupere o conteúdo da janela ativa. Aplicativos maliciosos podem recuperar o conteúdo da janela inteira e examinar todo o texto, exceto as senhas."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"ativar temporariamente a acessibilidade"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Permite que um aplicativo ative temporariamente a acessibilidade no dispositivo. Aplicativos maliciosos podem ativar a acessibilidade sem o consentimento do usuário."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"recuperar token da janela"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Permite que o aplicativo recupere o token da janela. Aplicativos maliciosos podem realizar interações não autorizadas com a janela do aplicativo em nome do sistema."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"recuperar estatísticas de quadros"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Permite que o aplicativo colete estatísticas de quadros. Aplicativos maliciosos podem observar as estatísticas de quadros de janelas de outros aplicativos."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"recuperar informações de janelas"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Permite que o aplicativo recupere informações sobre as janelas do gerenciador de janelas. Aplicativos mal-intencionados podem recuperar informações destinadas ao uso interno do sistema."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filtrar eventos"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Permite que o aplicativo registre um filtro de entrada que filtra o fluxo de todos os eventos do usuário antes que sejam enviados. Aplicativos mal-intencionados podem controlar a interface do sistema sem a intervenção do usuário."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"ampliar monitor"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Permite que o aplicativo amplie o conteúdo de um monitor. Aplicativos maliciosos podem manipular o conteúdo do monitor de modo a tornar o dispositivo inutilizável."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"desligamento parcial"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Coloca o gerenciador de atividades em um estado de desligamento. Não executa o desligamento completo."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"evitar trocas de aplicativo"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permite que o aplicativo transmita uma notificação quando uma mensagem SMS foi recebida. Aplicativos maliciosos podem usar esse recurso para forjar mensagens SMS recebidas."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar transmissão WAP-PUSH recebida"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permite que o aplicativo transmita uma notificação quando uma mensagem WAP PUSH for recebida. Aplicativos maliciosos podem usar esse recurso para forjar o recebimento de mensagens MMS ou substituir o conteúdo de qualquer página da web com variantes maliciosas."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"enviar transmissão de avaliação de redes"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Permite que o aplicativo transmita uma notificação informando que as redes devem ser avaliadas. Não deve ser necessário para aplicativos comuns."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar número de processos em execução"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permite que o aplicativo controle o máximo de processos que serão executados. Nunca é necessário para aplicativos normais."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forçar encerramento de aplicativos em segundo plano"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permite que seu proprietário sujeite a interface de alto nível de um serviço de VPN. Nunca deve ser necessário para aplicativos normais."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"sujeitar-se a um plano de fundo"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite que o proprietário utilize interface de nível superior de um plano de fundo. Nunca deve ser necessário para aplicativos normais."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"usar uma tela remota"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite que o proprietário use a interface de nível superior de uma tela remota. Não deve ser necessário para aplicativos comuns."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"sujeitar-se a um serviço de widget"</string>
     <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 aplicativos 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 aplicativos 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 aplicativos normais."</string>
-    <string name="permlab_bindTvInput" msgid="5601264742478168987">"associar a uma entrada de TV"</string>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Permite que o proprietário use a interface de nível superior de uma entrada de TV. Não deve ser necessário para aplicativos comuns."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"adicionar ou remover um administrador do dispositivo"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite que o proprietário adicione ou remova administradores do dispositivo ativos. Não deve ser necessário para aplicativos comuns."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"alterar orientação da tela"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que o aplicativo use qualquer decodificador de mídia instalado para reprodução."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gerenciar credenciais confiáveis"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que o aplicativo instale e desinstale certificados CA como credenciais confiáveis."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"executar o aplicativo durante o tempo ocioso"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Permite que o sistema Android execute o aplicativo em segundo plano enquanto o dispositivo não está em uso."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"associar a serviços inativos"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Permite que o sistema Android seja associado aos serviços inativos de um aplicativo."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"ler/gravar em recursos pertencentes ao diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que um aplicativo leia e grave em qualquer recurso que pertença ao grupo de diagnósticos, por exemplo, arquivos in/dev. Isso pode afetar a estabilidade e a segurança do sistema. Esse recurso deve ser usado APENAS para diagnósticos específicos do hardware realizados pelo fabricante ou pela operadora."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"ativar ou desativar os componentes do aplicativo"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Permite que o aplicativo leia informações de perfil pessoal armazenadas no dispositivo, como seu nome e dados de contato. Isso significa que o aplicativo poderá identificá-lo e enviar suas informações de perfil para terceiros."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"mod. próprio cartão contato"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Permite que o aplicativo altere ou adicione informações pessoais de perfil armazenadas em seu dispositivo, como seu nome e informações de contato. Isso significa que o aplicativo pode identificá-lo e enviar as informações de seus perfil para terceiros."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"sensores corporais"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Permite que o aplicativo acesse dados de sensores usados para medir o que acontece em seu corpo, como seus batimentos cardíacos."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"ler suas transmissões sociais"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Permite que o aplicativo acesse e sincronize suas atualizações sociais e as de seus amigos. Tenha cuidado ao compartilhar informações: isto permite que o aplicativo leia as mensagens trocadas por você e seus amigos em redes sociais, independentemente de sua confidencialidade. Obsservaç: pode não ser aplicável a todas as redes sociais."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"escrever p/ suas transm. soc."</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permite que o aplicativo controle os recursos de telefone do dispositivo. Um aplicativo com essa permissão pode alternar entre redes, ligar e desligar o rádio do telefone e assim por diante, sem nunca notificá-lo."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"ler status e identidade do telefone"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que o aplicativo acesse os recursos de telefonia do dispositivo. Esta permissão autoriza o aplicativo a determinar o número de telefone e IDs de dispositivo, quando uma chamada está ativa, e o número remoto conectado a uma chamada."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"ler estados precisos do telefone"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permite que o aplicativo acesse estados precisos do telefone. Permite que o aplicativo determine o status real da chamada, se uma chamada está ativa em segundo plano, falhas em chamadas, o status preciso da conexão de dados e falhas na conexão de dados."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"impedir modo de inatividade do tablet"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir modo de inatividade do telefone"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que o aplicativo impeça o tablet de entrar no modo de inatividade."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Alterar estado do WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite que o aplicativo conecte e desconecte o tablet de redes WiMAX."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permite que o aplicativo conecte e desconecte o telefone de redes WiMAX."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"avaliar redes"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Permite que o aplicativo classifique as redes e influencie a escolha de redes pelo tablet."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Permite que o aplicativo classifique as redes e influencie a escolha de redes pelo smartphone."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"parear com dispositivos Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permite que o aplicativo acesse a configuração do Bluetooth no tablet, além de fazer e aceitar conexões com dispositivos pareados."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permite que o aplicativo acesse a configuração do Bluetooth no telefone, além de fazer e aceitar conexões com dispositivos pareados."</string>
@@ -703,18 +683,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que o aplicativo recupere, examine e limpe notificações, inclusive as postadas por outros aplicativos."</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 aplicativos comuns."</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invocar o aplicativo de configuração fornecido pela operadora"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite que o proprietário invoque o aplicativo de configuração fornecido pela operadora. Não deve ser necessário para aplicativos comuns."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"detectar observações nas condições da rede"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que o aplicativo detecte observações nas condições da rede. Não deve ser necessário para aplicativos comuns."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"alterar calibragem do dispositivo de entrada"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permite que o aplicativo modifique os parâmetros de calibragem da tela sensível ao toque. Não deve ser necessário para aplicativos normais."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"acessar certificados de DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Permite que o aplicativo provisione e use certificados de DRM. Não deve ser necessário para aplicativos 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="policylab_watchLogin" msgid="914130646942199503">"Monitorar tentativas de desbloqueio da tela"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permite que o aplicativo acesse o armazenamento seguro do bloqueio de teclado."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Controlar a exibição e ocultação do bloqueio de tela"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permite que o aplicativo controle o bloqueio de teclado."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Detectar alterações no estado de confiança."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite que o aplicativo detecte alterações no estado de confiança."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Associar a um serviço de agente de confiança"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite que o aplicativo se associe a um serviço de agente de confiança."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interagir com o sistema de atualizações e recuperação"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Permite que um aplicativo interaja com o sistema de recuperação e as atualizações do sistema."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Toque duas vezes para controlar o zoom"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Plano de fundo"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Alterar plano de fundo"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Ouvinte de notificações"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN ativada"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"A VPN está ativada por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Toque para gerenciar a rede."</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index a4d58411..407f6ed 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -160,8 +160,6 @@
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Memia blers cuntegns stizzads (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
     <!-- no translation found for low_memory (6494019234102154896) -->
     <skip />
-    <!-- no translation found for low_memory (4415914910770005166) -->
-    <skip />
     <!-- no translation found for low_memory (3475999286680000541) -->
     <skip />
     <!-- no translation found for ssl_ca_cert_warning (5848402127455021714) -->
@@ -188,8 +186,6 @@
     <string name="shutdown_progress" msgid="2281079257329981203">"Vegn serrà..."</string>
     <!-- no translation found for shutdown_confirm (3385745179555731470) -->
     <skip />
-    <!-- no translation found for shutdown_confirm (3490275567476369184) -->
-    <skip />
     <!-- no translation found for shutdown_confirm (649792175242821353) -->
     <skip />
     <!-- no translation found for shutdown_confirm_question (2906544768881136183) -->
@@ -218,8 +214,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modus d\'aviun"</string>
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Il modus d\'aviun è activà"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Il modus d\'aviun è deactivà."</string>
-    <!-- no translation found for global_action_settings (1756531602592545966) -->
-    <skip />
     <!-- no translation found for status_bar_notification_info_overflow (5301981741705354993) -->
     <skip />
     <string name="safeMode" msgid="2788228061547930246">"Modus segirà"</string>
@@ -369,7 +363,7 @@
     <skip />
     <!-- no translation found for permlab_processOutgoingCalls (3906007831192990946) -->
     <skip />
-    <!-- no translation found for permdesc_processOutgoingCalls (5156385005547315876) -->
+    <!-- no translation found for permdesc_processOutgoingCalls (5331318931937402040) -->
     <skip />
     <!-- no translation found for permlab_receiveSms (8673471768947895082) -->
     <skip />
@@ -484,18 +478,18 @@
     <skip />
     <!-- no translation found for permdesc_temporary_enable_accessibility (8079456293182975464) -->
     <skip />
-    <!-- no translation found for permlab_retrieveWindowToken (7154762602367758602) -->
+    <!-- no translation found for permlab_retrieve_window_info (8532295199112519378) -->
     <skip />
-    <!-- no translation found for permdesc_retrieveWindowToken (668173747687795074) -->
-    <skip />
-    <!-- no translation found for permlab_frameStats (7056374987314361639) -->
-    <skip />
-    <!-- no translation found for permdesc_frameStats (4758001089491284919) -->
+    <!-- no translation found for permdesc_retrieve_window_info (4998836370424186849) -->
     <skip />
     <!-- no translation found for permlab_filter_events (8675535648807427389) -->
     <skip />
     <!-- no translation found for permdesc_filter_events (8006236315888347680) -->
     <skip />
+    <!-- no translation found for permlab_magnify_display (5973626738170618775) -->
+    <skip />
+    <!-- no translation found for permdesc_magnify_display (7121235684515003792) -->
+    <skip />
     <string name="permlab_shutdown" msgid="7185747824038909016">"serrar parzialmain"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Metta l\'administratur dad activitads en in stadi da pausa. El na vegn betg serrà dal tut."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"evitar il midar tranter applicaziuns"</string>
@@ -518,10 +512,6 @@
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"trametter in broadcast retschavì da WAP-PUSH"</string>
     <!-- no translation found for permdesc_broadcastWapPush (4783402525039442729) -->
     <skip />
-    <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
-    <skip />
-    <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
-    <skip />
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar il dumber maximal da process exequids"</string>
     <!-- no translation found for permdesc_setProcessLimit (7318061314040879542) -->
     <skip />
@@ -608,10 +598,6 @@
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"sa fixar vid in fund davos"</string>
     <!-- no translation found for permdesc_bindWallpaper (7108428692595491668) -->
     <skip />
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <!-- no translation found for permlab_bindRemoteDisplay (1782923938029941960) -->
     <skip />
     <!-- no translation found for permdesc_bindRemoteDisplay (1261242718727295981) -->
@@ -620,17 +606,9 @@
     <skip />
     <!-- no translation found for permdesc_bindRemoteViews (4717987810137692572) -->
     <skip />
-    <!-- no translation found for permlab_bindRouteProvider (4869394607915096847) -->
-    <skip />
-    <!-- no translation found for permdesc_bindRouteProvider (4703804520859960329) -->
-    <skip />
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interacziun cun in administratur dad apparats"</string>
     <!-- no translation found for permdesc_bindDeviceAdmin (569715419543907930) -->
     <skip />
-    <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
-    <skip />
-    <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
-    <skip />
     <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
     <skip />
     <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
@@ -700,9 +678,9 @@
     <skip />
     <!-- no translation found for permdesc_manageCaCertificates (4015644047196937014) -->
     <skip />
-    <!-- no translation found for permlab_bindIdleService (816311765497613780) -->
+    <!-- no translation found for permlab_bindIdleService (7521398788076342815) -->
     <skip />
-    <!-- no translation found for permdesc_bindIdleService (1767538493214100612) -->
+    <!-- no translation found for permdesc_bindIdleService (7747505810143356528) -->
     <skip />
     <string name="permlab_diagnostic" msgid="8076743953908000342">"leger/scriver en resursas che appartegnan a diagnostics"</string>
     <!-- no translation found for permdesc_diagnostic (6608295692002452283) -->
@@ -774,10 +752,6 @@
     <skip />
     <!-- no translation found for permdesc_writeProfile (5552084294598465899) -->
     <skip />
-    <!-- no translation found for permlab_bodySensors (4871091374767171066) -->
-    <skip />
-    <!-- no translation found for permdesc_bodySensors (2998865085124153531) -->
-    <skip />
     <!-- no translation found for permlab_readSocialStream (1268920956152419170) -->
     <skip />
     <!-- no translation found for permdesc_readSocialStream (4255706027172050872) -->
@@ -961,10 +935,6 @@
     <skip />
     <!-- no translation found for permdesc_readPhoneState (1639212771826125528) -->
     <skip />
-    <!-- no translation found for permlab_readPrecisePhoneState (5476483020282007597) -->
-    <skip />
-    <!-- no translation found for permdesc_readPrecisePhoneState (6648009074263855418) -->
-    <skip />
     <!-- no translation found for permlab_wakeLock (1531731435011495015) -->
     <skip />
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"evitar ch\'il telefon midia en il modus stand-by"</string>
@@ -1087,12 +1057,6 @@
     <skip />
     <!-- no translation found for permdesc_changeWimaxState (697025043004923798) -->
     <skip />
-    <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
-    <skip />
-    <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
-    <skip />
-    <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
-    <skip />
     <!-- no translation found for permlab_bluetooth (6127769336339276828) -->
     <skip />
     <!-- no translation found for permdesc_bluetooth (3480722181852438628) -->
@@ -1194,10 +1158,6 @@
     <skip />
     <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
     <skip />
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
     <skip />
     <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
@@ -1206,14 +1166,6 @@
     <skip />
     <!-- no translation found for permdesc_accessNetworkConditions (6899102075825272211) -->
     <skip />
-    <!-- no translation found for permlab_setInputCalibration (4902620118878467615) -->
-    <skip />
-    <!-- no translation found for permdesc_setInputCalibration (4527511047549456929) -->
-    <skip />
-    <!-- no translation found for permlab_accessDrmCertificates (7436886640723203615) -->
-    <skip />
-    <!-- no translation found for permdesc_accessDrmCertificates (8073288354426159089) -->
-    <skip />
     <!-- no translation found for policylab_limitPassword (4497420728857585791) -->
     <skip />
     <!-- no translation found for policydesc_limitPassword (3252114203919510394) -->
@@ -2152,14 +2104,6 @@
     <skip />
     <!-- no translation found for permdesc_control_keyguard (3043732290518629061) -->
     <skip />
-    <!-- no translation found for permlab_trust_listener (1765718054003704476) -->
-    <skip />
-    <!-- no translation found for permdesc_trust_listener (8233895334214716864) -->
-    <skip />
-    <!-- no translation found for permlab_bind_trust_agent_service (8242093169457695334) -->
-    <skip />
-    <!-- no translation found for permdesc_bind_trust_agent_service (7041930026024507515) -->
-    <skip />
     <!-- no translation found for permlab_recovery (3157024487744125846) -->
     <skip />
     <!-- no translation found for permdesc_recovery (8511774533266359571) -->
@@ -2196,8 +2140,6 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Midar il fund davos"</string>
     <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
     <skip />
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <!-- no translation found for vpn_title (19615213552042827) -->
     <skip />
     <!-- no translation found for vpn_title_long (6400714798049252294) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 8a69824..21c8a11 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronizare"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Prea multe ştergeri <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Stocarea pe tabletă este plină. Ștergeţi câteva fişiere pentru a elibera spaţiu."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Spațiul de stocare de pe ceas este plin! Ștergeți câteva fișiere pentru a elibera spațiu."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Stocarea pe telefon este plină. Ștergeţi câteva fişiere pentru a elibera spaţiu."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Rețeaua poate fi monitorizată"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"De o terță parte necunoscută"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Sonerie activată"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Se închide..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Computerul dvs. tablet PC se va închide."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Ceasul dvs. se va închide."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefonul dvs. se va închide."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Doriţi să închideţi?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Reporniţi în modul sigur"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mod Avion"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"˃999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mod sigur"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistemul Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"dezinstalează comenzi rapide"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Permite aplicației să elimine comenzi rapide de pe ecranul de pornire, fără intervenția utilizatorului."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"redirecţionează apelurile efectuate"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Permite aplicației să vadă numărul format în timpul unui apel de ieșire, cu opțiunea de a redirecționa apelul către un alt număr sau de a întrerupe apelul."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Permite aplicaţiei să proceseze apelurile efectuate şi să schimbe numărul care trebuie format. Cu această permisiune aplicaţia poate monitoriza, redirecţiona sau împiedica apelurile efectuate."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"primeşte mesaje text (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Permite aplicaţiei să primească şi să proceseze mesaje SMS. Acest lucru înseamnă că aplicaţia ar putea monitoriza sau şterge mesajele trimise pe dispozitivul dvs. fără a vi le arăta."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"primeşte mesaje text (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Permite aplicaţiei să preia conţinutul ferestrei active. Aplicaţiile rău intenţionate pot să preia întregul conţinut al ferestrei şi să examineze integral textul acesteia, cu excepţia parolelor."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"activare temporară a accesibilității"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Permite unei aplicaţii să activeze temporar accesibilitatea pe gadget. Aplicaţiile rău intenţionate o pot activa fără consimţământul utilizatorului."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"preluarea indicativului ferestrei"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Permite unei aplicații să preia indicativul ferestrei. Aplicațiile dăunătoare pot interacționa neautorizat cu fereastra aplicației substituindu-se sistemului."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"preluarea statisticilor de referință"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Permite unei aplicații să culeagă statistici de referință. Aplicațiile dăunătoare ar putea urmări statisticile de referință ale ferestrelor din alte aplicații."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"preluare informaţii despre ferestre"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Permite unei aplicaţii să preia informaţii despre ferestrele din managerul de ferestre. Aplicaţiile rău intenţionate pot prelua informaţii care sunt destinate utilizării sistemului intern."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filtrare evenimente"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Permite unei aplicaţii să înregistreze un filtru de intrare, care filtrează transmiterea în flux a tuturor evenimentelor utilizatorilor înainte ca acestea să fie expediate. Aplicaţiile rău intenţionate pot controla interfaţa de utilizare a sistemului fără intervenţia utilizatorului."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"măreşte afişajul"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Permite unei aplicaţii să mărească conţinutul unui afişaj. Aplicaţiile rău intenţionate pot transforma conţinutul afişajului într-un mod care ar face inutilizabil dispozitivul."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"închidere parţială"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Plasează Managerul de activităţi într-o stare de închidere. Nu efectuează o închidere completă."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"împiedicare comutare între aplicaţii"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permite aplicaţiei să difuzeze o notificare de primire a unui mesaj SMS. Aplicaţiile rău intenţionate pot să utilizeze această permisiune pentru a deturna primirea mesajelor SMS."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"trimitere mesaj difuzat primit prin WAP-PUSH"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permite aplicaţiei să difuzeze o notificare de primire a unui mesaj WAP PUSH. Aplicaţiile rău intenţionate pot să utilizeze această permisiune pentru a deturna primirea mesajelor MMS sau pentru a înlocui fără a vă înştiinţa conţinutul oricărei pagini web cu variante rău intenţionate."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"trimiteți transmisia cu rețelele punctate"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Permite aplicației să transmită o notificare de care rețelele au nevoie pentru a fi punctate. Nu este necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitare număr de procese în derulare"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permite aplicaţiei să controleze numărul maxim de procese care vor rula. Nu este niciodată necesară pentru aplicaţiile obişnuite."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forţează închiderea aplicaţiilor de fundal"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unui serviciu VPN. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"conectare la o imagine de fundal"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unei imagini de fundal. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"conectare la un ecran la distanță"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite proprietarului să se conecteze la interfața de nivel superior a unui ecran la distanță. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"conectare la un serviciu widget"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Permite proprietarului să se conecteze la interfața de nivel superior a unei intrări TV. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"adăugarea sau eliminarea unui administrator de dispozitiv"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite proprietarului să adauge sau să elimine administratorii activi ai dispozitivului. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"modificare orientare ecran"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite aplicaţiei să utilizeze orice decodor media instalat pentru a decodifica redarea."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestionarea acreditărilor de încredere"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite aplicației să instaleze și să dezinstaleze certificate CA ca acreditări de încredere."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"rulează aplicația în timp ce dispozitivul este inactiv"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Cu această permisiune, sistemul Android poate rula aplicația în fundal în timp ce dispozitivul nu este utilizat."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"asociați cu serviciile inactive"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Această autorizare permite sistemului Android să se conecteze la serviciile inactive ale unei aplicații."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"citire/scriere în resursele deţinute de diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite aplicaţiei să citească şi să scrie în orice resursă deţinută de grupul diag, de ex., fişierele din /dev. Această permisiune ar putea să afecteze stabilitatea şi securitatea sistemului. Permisiunea trebuie utilizată NUMAI de producător sau de operator pentru diagnostice specifice pentru hardware."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activare sau dezactivare a componentelor aplicaţiei"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Permite aplicaţiei să citească informaţiile personale din profil stocate pe dispozitiv, cum ar fi numele şi informaţiile de contact, ceea ce înseamnă că aplicaţia vă poate identifica şi poate trimite informaţiile dvs. de profil altor utilizatori."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"modifică cartea dvs. de vizită"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Permite aplicaţiei să schimbe sau să adauge conţinut în informaţiile personale din profil stocate pe dispozitivul dvs., cum ar fi numele şi informaţiile dvs. de contact. Aceasta înseamnă că aplicaţia vă poate identifica şi poate trimite informaţiile din profilul dvs. altor persoane."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"senzori (ex.: senzori de ritm cardiac)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Permite aplicației să acceseze datele de la senzorii pe care îi utilizați pentru a măsura funcțiile corpului, cum ar fi ritmul cardiac."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"citeşte fluxul social"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Permite aplicaţiei să acceseze şi să sincronizeze actualizările sociale de la dvs. şi de la prietenii dvs. Daţi dovadă de precauţie când distribuiţi informaţii - cu această permisiune aplicaţia citeşte comunicările realizate între dvs. şi prietenii dvs. în reţelele sociale, indiferent de gradul de confidenţialitate a acestora. Notă: această permisiune nu poate fi aplicată pentru toate reţelele sociale."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"scrie în fluxul social"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permite aplicaţiei să controleze funcţiile de telefon ale dispozitivului. O aplicaţie cu această permisiune poate să schimbe reţeaua, să închidă şi să deschidă radioul şi să efectueze alte acţiuni similare, fără să vă înştiinţeze."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"citeşte starea şi identitatea telefonului"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite aplicaţiei să acceseze funcţiile de telefon ale dispozitivului. Cu această permisiune aplicaţia stabileşte numărul de telefon şi ID-urile de dispozitiv, dacă un apel este activ, precum şi numărul de la distanţă conectat printr-un apel."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"accesați stările exacte ale telefonului"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permite aplicației să acceseze stările exacte ale telefonului. Cu această permisiune, aplicația poate să determine starea reală a apelului, dacă apelul este activ sau în fundal, dacă apelul eșuează, starea exactă și întreruperile conexiunii de date."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"împiedicarea computerului tablet PC să intre în repaus"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"împiedicare intrare telefon în repaus"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite aplicaţiei să împiedice intrarea tabletei în stare de repaus."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Schimbaţi starea WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite aplicaţiei să conecteze şi să deconecteze tableta la şi de la reţelele WiMAX."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permite aplicaţiei să conecteze şi să deconecteze telefonul la şi de la reţelele WiMAX."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"rețele punctate"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Permite aplicației să clasifice rețelele și să stabilească ce rețele preferă tableta."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Permite aplicației să clasifice rețelele și să stabilească ce rețele preferă telefonul."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"conectează dispozitive Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permite aplicaţiei să vadă configuraţia tabletei Bluetooth, să efectueze şi să accepte conexiuni cu dispozitive împerecheate."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permite aplicaţiei să vadă configuraţia telefonului Bluetooth, să efectueze şi să accepte conexiuni cu dispozitive împerecheate."</string>
@@ -703,18 +683,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"apelarea aplicației de configurare furnizată de operator"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite proprietarului să apeleze aplicația de configurare furnizată de operator. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ascultă observații despre starea rețelei"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite unei aplicații să asculte observații despre starea rețelei. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"schimbați calibrarea dispozitivului de intrare"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permite aplicației să modifice parametrii de calibrare a ecranului tactil. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"accesează certificatele DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Permite unei aplicații să furnizeze și să utilizeze certificate DRM. Nu ar trebui să fie 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="policylab_watchLogin" msgid="914130646942199503">"Monitorizaţi încercările de deblocare a ecranului"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permite unei aplicații să acceseze stocarea securizată când tastatura este blocată."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Stabilește afișarea și ascunderea blocării tastaturii"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permite unei aplicații să controleze blocarea tastaturii."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Detectarea modificărilor în starea de încredere."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite unei aplicații să detecteze modificările în starea de încredere."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Asocierea la un serviciu „agenți de încredere”."</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite unei aplicații să se asocieze la un serviciu „agent de încredere”."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interacțiune cu sistemul de recuperare și de actualizare"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Permite unei aplicații să interacționeze cu sistemul de recuperare și cu actualizările de sistem."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Atingeţi de două ori pentru a mări/micşora"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Imagine de fundal"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Modificaţi imaginea de fundal"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Serviciu de citire a notificărilor"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN activat"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN este activată de <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Atingeţi pentru a gestiona reţeaua."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 70e7044..9bc6bcd 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -135,9 +135,8 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Синхр."</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Слишком много удалений <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Память планшетного ПК заполнена. Удалите какие-нибудь файлы, чтобы освободить место."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Память устройства заполнена. Удалите файлы, чтобы освободить место."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Память телефона заполнена. Удалите какие-нибудь файлы, чтобы освободить место."</string>
-    <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Сеть может отслеживаться"</string>
+    <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Действия в сети могут отслеживаться"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"администратором"</string>
     <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"администратором домена <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
     <string name="me" msgid="6545696007631404292">"Я"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Звонок включен"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Выключение..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Планшетный ПК будет отключен."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Устройство будет отключено."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Телефон будет выключен."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Завершить работу?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Переход в безопасный режим"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Режим полета"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безопасный режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"Удаление ярлыков"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Приложение сможет удалять ярлыки с главного экрана без вмешательства пользователя."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"Перенаправление исходящих вызовов"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Приложение сможет видеть набранный номер во время исходящего вызова и при необходимости перенаправлять вызов или завершать его."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Приложение сможет обрабатывать исходящие вызовы и изменять набираемые номера, а также отслеживать, перенаправлять или блокировать исходящие вызовы."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"Прием SMS-сообщений"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Приложение сможет получать и обрабатывать SMS. Это значит, что оно сможет отслеживать и удалять отправленные на ваше устройство сообщения, не показывая их."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"Прием MMS-сообщений"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Приложение сможет получать контент активного окна. Вредоносные программы смогут перехватывать такой контент и анализировать любой текст, кроме паролей."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"Включение специальных возможностей"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Приложение сможет временно включать на устройстве специальные возможности. Вредоносные приложения смогут включать их без вашего ведома."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"получение токена окна"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Приложение может получать токен окна. Вредоносные программы могут взаимодействовать с окном приложения под видом системы."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"получение статистики по фреймам"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Приложение может собирать статистику по фреймам. Вредоносные приложения могут получать доступ к такой статистике у других программ."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"Доступ к информации в окне"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Открывает приложению доступ к информации из диспетчера окон. Обратите внимание, что вредоносное ПО может получить доступ к некоторой системной информации устройства."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"Фильтрация событий"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Разрешает приложению зарегистрировать входной фильтр, который анализирует весь поток пользовательских событий. Обратите внимание, что вредоносное ПО может получить доступ к управлению интерфейсом без ведома пользователя."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"Увеличение изображений"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Приложение сможет увеличивать содержимое экрана. Вредоносные программы смогут изменять изображение таким образом, что устройством нельзя будет пользоваться."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"Частичное завершение работы"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Завершает работу диспетчера активности. Не выполняет полное завершение работы."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"Защита от переключения приложений"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Приложение сможет уведомлять о получении SMS. Вредоносные программы смогут таким образом подделывать входящие SMS."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"Отправка уведомлений о доставке SMS с ссылкой на WAP-страницу"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Приложение сможет уведомлять о получении сообщений WAP PUSH. Вредоносные программы смогут таким образом фальсифицировать получение MMS или незаметно подменять содержание любой страницы вредоносными данными."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"Отправка уведомлений о рейтинге сетей"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Приложение сможет отправлять уведомления о том, что сети необходимо присвоить рейтинг. Это разрешение обычно используется только специальными приложениями."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"Ограничение количества запущенных процессов"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Приложение сможет управлять максимальным количеством процессов, которые могут быть запущены. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"Закрытие фоновых приложений"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Приложение сможет подключаться к базовому интерфейсу службы VPN. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"Привязка к фоновому рисунку"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Приложение сможет подключаться к базовому интерфейсу службы обоев. Это разрешение не используется обычными приложениями."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"Подключение к удаленному дисплею"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Приложение сможет подключаться к базовому интерфейсу ТВ-входа. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"Добавление/удаление администратора устройства"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Владелец сможет добавлять и удалять администраторов устройства (используется лишь в некоторых приложениях)."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"Изменение ориентации экрана"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Приложение сможет использовать любой установленный дешифратор."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Управление учетными данными"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Приложение сможет устанавливать сертификаты ЦС в качестве надежных учетных данных, а также удалять их."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"выполнение приложения в спящем режиме"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Система Android сможет выполнять приложение в фоновом режиме, когда устройство не используется."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"привязка неактивных сервисов"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Android сможет подключаться к неактивным сервисам."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"Чтение/запись данных в системы диагностики"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Приложение сможет считывать и записывать данные системы диагностики (например, файлы в каталоге /dev). Это может повлиять на стабильность и безопасность системы. Это разрешение должно использоваться ТОЛЬКО производителем или оператором для диагностики аппаратного обеспечения."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"Включение/отключение компонентов приложения"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Приложение сможет просматривать вашу личную информацию (например, имя и контактные данные), сохраненную на устройстве. Получив эти данные, приложение сможет отправить их другим пользователям."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"Изменение ваших контактных данных"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Приложение сможет изменять вашу личную информацию (например, имя и контактные данные), сохраненную на устройстве. Получив эти данные, приложение сможет отправить их другим пользователям."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"датчики (например, пульсометр)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Приложение получит доступ к данным приборов, используемых для измерения ваших физиологических показателей (например, пульса)."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"Просмотр записей в вашей социальной ленте"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Приложение сможет просматривать и синхронизировать записи, публикуемые вами и вашими друзьями в социальных сетях. Будьте осторожны при передаче информации! С этим разрешением приложение сможет просматривать вашу переписку с друзьями в социальных сетях независимо от настроек конфиденциальности. Примечание. Это разрешение может применяться не во всех социальных сетях."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"Добавление записей в вашу социальную ленту"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Приложение сможет управлять на устройстве функциями телефона: переключать сети, включать и выключать приемопередатчик, а также выполнять другие подобные действия без уведомления."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"Получение данных о статусе телефона"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Приложение получит доступ к функциям телефона на устройстве. Кроме того, оно сможет определять номера телефонов и серийные номера моделей, состояние активности вызова, а также удаленные номера, с которыми установлено соединение."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"Доступ к точным статусам телефона"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Приложение сможет определять точный статус вызовов (активный, в фоновом режиме или сбой), а также статус интернет-соединения (в том числе, если подключиться не удалось)."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"Отключение спящего режима"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Отключение спящего режима"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Приложение сможет запрещать перевод планшетного ПК в спящий режим."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Изменение статуса WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Приложение сможет подключать устройство к сетям WiMAX и отключать его от них."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Приложение сможет подключать устройство к сетям WiMAX и отключать его от них."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"Определение рейтинга сетей"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Приложение сможет присваивать сетям рейтинг и решать, к каким из них устройство должно подключаться в первую очередь."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Приложение сможет присваивать сетям рейтинг и решать, к каким из них устройство должно подключаться в первую очередь."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"Установление связи с устройствами Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Приложение сможет просматривать конфигурацию Bluetooth на планшетном ПК, а также запрашивать и подтверждать соединение с другими устройствами."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Приложение сможет просматривать конфигурацию Bluetooth на телефоне, а также запрашивать и подтверждать соединение с другими устройствами."</string>
@@ -703,18 +683,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Приложение сможет получать, проверять и удалять уведомления, включая те, что опубликованы другими приложениями."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"Подключение к службе просмотра уведомлений"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Приложение сможет подключаться к базовому интерфейсу службы просмотра уведомлений. Это разрешение не используется обычными приложениями."</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"Запуск приложения настроек, предоставленного оператором"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Владелец сможет запускать приложение настроек, предоставленное оператором. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Использование данных о состоянии сети"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Приложение сможет использовать данные о состоянии сети. Это разрешение обычно используется только специальными приложениями."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"изменение параметров калибровки экрана"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Приложение сможет изменять параметры калибровки сенсорного экрана. Это разрешение обычно используется только специальными приложениями."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"Доступ к сертификатам DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Приложение сможет синхронизировать и использовать сертификаты DRM (разрешение актуально только для специальных приложений)."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Правила выбора паролей"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролировать длину и символы при вводе паролей для снятия блокировки экрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Отслеживать попытки снятия блокировки экрана"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Приложение сможет получить доступ к хранилищу ключей."</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>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Подключение к службе Trust Agents"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Приложение сможет подключаться к службе Trust Agents."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Взаимодействовать с системой восстановления и обновлениями"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Приложение сможет взаимодействовать с системой восстановления и обновлениями системы."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Нажмите дважды для изменения масштаба"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Фоновый рисунок"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Сменить обои"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Служба просмотра уведомлений"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"Сеть VPN активна"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Сеть VPN активирована приложением <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Нажмите, чтобы открыть настройки."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 055d23b..5fc592c 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -38,7 +38,7 @@
     <string name="mmiFdnError" msgid="5224398216385316471">"Operácia je obmedzená len na režim čísla pevného vytáčania."</string>
     <string name="serviceEnabled" msgid="8147278346414714315">"Služba bola povolená."</string>
     <string name="serviceEnabledFor" msgid="6856228140453471041">"Služba bola povolená pre:"</string>
-    <string name="serviceDisabled" msgid="1937553226592516411">"Služba bola vypnutá."</string>
+    <string name="serviceDisabled" msgid="1937553226592516411">"Služba bola zakázaná."</string>
     <string name="serviceRegistered" msgid="6275019082598102493">"Registrácia prebehla úspešne."</string>
     <string name="serviceErased" msgid="1288584695297200972">"Vymazanie prebehlo úspešne."</string>
     <string name="passwordIncorrect" msgid="7612208839450128715">"Nesprávne heslo."</string>
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronizovať"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Príliš veľa odstránených položiek služby <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Ukladací priestor tabletu je plný. Odstráňte niektoré súbory a uvoľnite miesto."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Ukladací priestor hodiniek je plný. Uvoľnite miesto odstránením niektorých súborov."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Pamäť telefónu je plná. Odstráňte niektoré súbory a uvoľnite miesto."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Sieť môže byť monitorovaná"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Neznámou treťou stranou"</string>
@@ -146,14 +145,13 @@
     <string name="silent_mode" msgid="7167703389802618663">"Tichý režim"</string>
     <string name="turn_on_radio" msgid="3912793092339962371">"Zapnúť bezdrôtové pripojenie"</string>
     <string name="turn_off_radio" msgid="8198784949987062346">"Vypnúť bezdrôtové pripojenie"</string>
-    <string name="screen_lock" msgid="799094655496098153">"Zámka obrazovky"</string>
+    <string name="screen_lock" msgid="799094655496098153">"Uzamknutie obrazovky"</string>
     <string name="power_off" msgid="4266614107412865048">"Vypnúť"</string>
     <string name="silent_mode_silent" msgid="319298163018473078">"Zvonenie je vypnuté"</string>
     <string name="silent_mode_vibrate" msgid="7072043388581551395">"Vibračné zvonenie"</string>
     <string name="silent_mode_ring" msgid="8592241816194074353">"Zvonenie je zapnuté"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Prebieha vypínanie..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Váš tablet bude vypnutý."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Hodinky sa vypnú."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Váš telefón bude vypnutý."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Chcete zariadenie vypnúť?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Reštartovať do núdzového režimu"</string>
@@ -162,18 +160,17 @@
     <string name="no_recent_tasks" msgid="8794906658732193473">"Žiadne nedávne aplikácie"</string>
     <string name="global_actions" product="tablet" msgid="408477140088053665">"Možnosti tabletu"</string>
     <string name="global_actions" product="default" msgid="2406416831541615258">"Možnosti telefónu"</string>
-    <string name="global_action_lock" msgid="2844945191792119712">"Zámka obrazovky"</string>
+    <string name="global_action_lock" msgid="2844945191792119712">"Uzamknutie obrazovky"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Vypnúť"</string>
-    <string name="global_action_bug_report" msgid="7934010578922304799">"Hlásenie o chybách"</string>
-    <string name="bugreport_title" msgid="2667494803742548533">"Vytvoriť hlásenie o chybách"</string>
-    <string name="bugreport_message" msgid="398447048750350456">"Zhromaždí informácie o aktuálnom stave zariadenia na odoslanie v e-mailovej správe. Chvíľu však potrvá, kým bude hlásenie o chybách pripravené na odoslanie. Prosíme vás preto o trpezlivosť."</string>
+    <string name="global_action_bug_report" msgid="7934010578922304799">"Správa o chybe"</string>
+    <string name="bugreport_title" msgid="2667494803742548533">"Zaznamenať správu o chybe"</string>
+    <string name="bugreport_message" msgid="398447048750350456">"Zhromažďuje informácie o aktuálnom stave zariadenia a tieto informácie je následne možné odoslať prostredníctvom e-mailovej správy. Od spustenia vytvárania správy o chybe až do chvíle, kedy je tento nástroj pripravený odoslať prvú správu, môže uplynúť nejaký čas. Prosíme vás preto o trpezlivosť."</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Tichý režim"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Zvuk je VYPNUTÝ."</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Zvuk je zapnutý"</string>
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Režim V lietadle"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Núdzový režim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
@@ -193,7 +190,7 @@
     <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Prístup k zariadeniam a sieťam prostredníctvom rozhrania Bluetooth."</string>
     <string name="permgrouplab_audioSettings" msgid="8329261670151871235">"Nastavenia zvuku"</string>
     <string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"Zmena nastavení zvuku."</string>
-    <string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Vplyv na batériu"</string>
+    <string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Má vplyv na batériu"</string>
     <string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"Používanie funkcií, ktoré môžu rýchlo vyčerpať batériu."</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendár"</string>
     <string name="permgroupdesc_calendar" msgid="5777534316982184416">"Priamy prístup ku kalendáru a udalostiam."</string>
@@ -235,8 +232,8 @@
     <string name="permgroupdesc_developmentTools" msgid="7058828032358142018">"Funkcie len pre vývojárov aplikácií."</string>
     <string name="permgrouplab_display" msgid="4279909676036402636">"Používateľské rozhranie iných aplikácií"</string>
     <string name="permgroupdesc_display" msgid="6051002031933013714">"Vplyv na používateľské rozhranie ďalších aplikácií."</string>
-    <string name="permgrouplab_storage" msgid="1971118770546336966">"Úložisko"</string>
-    <string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"Prístup do úložiska USB."</string>
+    <string name="permgrouplab_storage" msgid="1971118770546336966">"Ukladací priestor"</string>
+    <string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"Prístup do ukl. priestoru USB."</string>
     <string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Prístup na kartu SD."</string>
     <string name="permgrouplab_accessibilityFeatures" msgid="7919025602283593907">"Funkcie zjednodušenia ovládania"</string>
     <string name="permgroupdesc_accessibilityFeatures" msgid="4205196881678144335">"Funkcie, ktoré môže vyžadovať nápomocná technológia."</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"odinštalovať odkazy"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Povoľuje aplikácii odstrániť odkazy na ploche bez zásahu používateľa."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"presmerovať odchádzajúce hovory"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Umožňuje aplikácii počas odchádzajúceho hovoru rozpoznať vytáčané číslo a poskytuje možnosť presmerovať daný hovor na odlišné číslo alebo ho úplne zrušiť."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Umožňuje aplikácii spracovávať odchádzajúce hovory a meniť vytáčané číslo. Toto povolenie umožňuje aplikácii sledovať a presmerovať odchádzajúce hovory alebo im zabrániť."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"prijímať textové správy (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Umožňuje aplikácii prijímať a spracovávať správy SMS. Znamená to, že aplikácia môže sledovať správy odoslané na vaše zariadenie alebo ich odstrániť bez toho, aby sa vám zobrazili."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"prijímať textové správy (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Umožňuje aplikácii načítať obsah aktívneho okna. Škodlivé aplikácie môžu získať celý obsah okna a preskúmať celý jeho text okrem hesiel."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"dočasné povolenie zjednodušenia ovládania"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Umožňuje aplikácii dočasne povoliť zjednodušenie ovládania v zariadení. Škodlivé aplikáciu môžu zjednodušenie ovládania povoliť bez súhlasu používateľa."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"získať token okna"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Umožňuje aplikácii získať token okna. Škodlivé aplikácie sa môžu správať ako systém a vykonať neautorizovanú interakciu s oknom aplikácie."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"získať štatistiky rámcov"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Umožňuje aplikácii zhromažďovať štatistiky rámcov. Škodlivé aplikácie môžu sledovať štatistiky rámcov okien z iných aplikácií."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"načítanie informácií o oknách"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Umožňuje aplikácii načítať informácie o oknách zo správcu okien. Škodlivé aplikácie môžu načítať informácie, ktoré sú určené pre interné využitie systému."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filtrovanie udalostí"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Umožňuje aplikácii zaregistrovať vstupný filter, ktorý filtruje stream všetkých prenosov používateľa pred ich odvysielaním. Škodlivá aplikácia môže bez zásahu používateľa ovládať používateľské rozhranie systému."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"priblížiť zobrazenie"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Umožňuje aplikácii priblížiť obsah displeja. Škodlivé aplikácie môžu zmeniť zobrazenie obsahu tak, že sa zariadenie stane nepoužiteľným."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"Čiastočné vypnutie"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Uvedie správcu činností do vypnutého stavu. Úplné vypnutie však nenastane."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"zabrániť prepínaniu aplikácií"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Umožňuje aplikácii vysielať oznámenie, že správa SMS bola doručená. Škodlivé aplikácie môžu toto nastavenie použiť na falšovanie prichádzajúcich správ SMS."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"odoslanie vysielania typu WAP-PUSH-received"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Umožňuje aplikácii vysielať oznámenie, že správa WAP PUSH bola doručená. Škodlivé aplikácie môžu použiť toto nastavenie na vytvorenie potvrdenia o doručení správy MMS alebo na utajené nahradenie obsahu akejkoľvek stránky škodlivými variantmi."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"odoslanie skóre vysielaných sieťami"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Umožňuje aplikácii vysielať upozornenie, že je potrebné zadať skóre sietí. Bežné aplikácie toto povolenie nepotrebujú."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"obmedzenie počtu spustených procesov"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Umožňuje aplikácii kontrolovať maximálny počet spustených procesov. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"vynútiť zavretie aplikácií na pozadí"</string>
@@ -356,7 +351,7 @@
     <string name="permdesc_backup" msgid="6912230525140589891">"Umožňuje aplikácii ovládať mechanizmus na zálohovanie a obnovu údajov systému. Bežné aplikácie toto nastavenie nepoužívajú."</string>
     <string name="permlab_confirm_full_backup" msgid="5557071325804469102">"potvrdenie operácie úplnej zálohy alebo úplného obnovenia"</string>
     <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Umožňuje aplikácii spustiť používateľské rozhranie potvrdenia úplnej zálohy. Toto nastavenie by nemala používať žiadna aplikácia."</string>
-    <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"zobraziť neoprávnené okná"</string>
+    <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"zobrazenie neoprávnených okien"</string>
     <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Umožňuje aplikácii vytvárať okná, ktoré majú byť použité interným systémom používateľského rozhrania. Bežné aplikácie toto nastavenie nepoužívajú."</string>
     <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"vykresliť cez ďalšie aplikácie"</string>
     <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Umožňuje aplikáciu vykresľovanie nad inými aplikáciami alebo súčasťami používateľského rozhrania. Táto funkcia môže zasahovať do vášho používania rozhrania inej aplikácie alebo meniť zobrazovaný obsah v iných aplikáciách."</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby VPN. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"väzba na tapetu"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania tapety. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"viazať na vzdialený displej"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania vzdialeného displeja. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"viazať sa k službe miniaplikácie"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Umožňuje aplikácii používať na reprodukciu ľubovoľný nainštalovaný dekódovač na dekódovanie."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"spravovať dôveryhodné poverenia"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Umožňuje aplikácii inštalovať a odinštalovať certifikáty CA ako dôveryhodné poverenia."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"spustiť aplikáciu počas nečinnosti"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Toto povolenie umožňuje systému Android spustiť aplikáciu na pozadí, keď sa zariadenie nepoužíva."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"previazať s nečinnými službami"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Toto povolenie umožní systému Android viazať sa na nečinné služby aplikácie."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"čítanie alebo zápis do prostriedkov funkcie diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Umožňuje aplikácii čítať ľubovoľné prostriedky v skupine diag, napr. súbory v priečinku /dev, a zapisovať do nich. Môže dôjsť k ovplyvneniu stability a bezpečnosti systému. Toto nastavenie by mal používať IBA výrobca či operátor na diagnostiku hardvéru."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"povoliť alebo zakázať súčasti aplikácie"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Umožňuje aplikácii čítať informácie v osobnom profile uložené v zariadení, ako je vaše meno a kontaktné informácie. Znamená to, že vás ostatné aplikácie môžu identifikovať a odoslať informácie o vašom profile iným aplikáciám."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"upraviť vlastnú kartu kontaktu"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Umožňuje aplikácii zmeniť alebo pridať do osobného profilu informácie uložené vo vašom zariadení, ako je vaše meno a kontaktné informácie. Znamená to, že vás aplikácia môže identifikovať a odoslať informácie o vašom profile ostatným aplikáciám."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"telesné senzory (napr. snímače tepu)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Umožňuje aplikácii pristupovať k údajom zo senzorov, pomocou ktorých meriate činnosť svojho tela, napríklad tep."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"čítať váš sociálny stream"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Umožňuje aplikácii pristupovať k sociálnym aktualizáciám od vás a vašich priateľov a synchronizovať ich. Pri zdieľaní informácií dávajte pozor – toto povolenie umožňuje aplikácii čítať komunikáciu medzi vami a vašimi priateľmi v sociálnych sieťach, a to bez ohľadu na jej dôvernosť. Poznámka: Toto povolenie nie je možné vynucovať v prípade všetkých sociálnych sietí."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"písať do vášho sociálneho streamu"</string>
@@ -493,9 +480,9 @@
     <string name="permdesc_accessLocationExtraCommands" msgid="5945166642335800763">"Umožňuje aplikácii pristupovať k ďalším príkazom poskytovateľa informácií o polohe. Aplikácii to môže umožniť zasahovať do činnosti systému GPS alebo iných zdrojov informácií o polohe."</string>
     <string name="permlab_installLocationProvider" msgid="6578101199825193873">"Oprávnenie na inštaláciu poskytovateľa polohy"</string>
     <string name="permdesc_installLocationProvider" msgid="9066146120470591509">"Vytváranie simulovaných zdrojov polohy na testovanie alebo inštalácia nového poskytovateľa informácií o polohe. Aplikácii to umožní nahradiť polohu a stav, ktoré vracajú iné zdroje informácií o polohe, ako sú napríklad systém GPS alebo poskytovatelia informácií o polohe."</string>
-    <string name="permlab_accessFineLocation" msgid="1191898061965273372">"zistiť presnú polohu (pomocou GPS a siete)"</string>
+    <string name="permlab_accessFineLocation" msgid="1191898061965273372">"presná poloha (pomocou GPS a siete)"</string>
     <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Umožňuje aplikácii získať vašu presnú polohu pomocou systému GPS (Global Positioning System) alebo zdrojov určenia polohy siete, napríklad mobilných veží a sietí Wi-Fi. Tieto služby určovania polohy musia byť na vašom zariadení zapnuté a dostupné, inak ich aplikácia nebude môcť využívať. Aplikácie môžu tieto služby využívať na určenie vašej polohy. Tieto služby môžu zvýšiť spotrebu batérie."</string>
-    <string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"zistiť približnú polohu (pomocou siete)"</string>
+    <string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"približná poloha (pomocou siete)"</string>
     <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Umožňuje aplikácii získať vašu približnú polohu. Táto poloha je odvodená zo služieb určovania polohy pomocou zdrojov určenia polohy siete, napríklad mobilných veží a sietí Wi-Fi. Tieto služby určovania polohy musia byť na vašom zariadení zapnuté a dostupné, inak ich aplikácia nebude môcť využívať. Aplikácie môžu tieto služby využívať na určenie vašej približnej polohy."</string>
     <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"prístup k službe SurfaceFlinger"</string>
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Umožňuje aplikácii používať funkcie nízkej úrovne aplikácie SurfaceFlinger."</string>
@@ -517,13 +504,13 @@
     <string name="permdesc_captureSecureVideoOutput" msgid="2779793064709350289">"Umožňuje aplikácii zachytiť a presmerovať zabezpečený výstup videa."</string>
     <string name="permlab_mediaContentControl" msgid="8749790560720562511">"ovládanie reprodukcie médií a prístup k metadátam"</string>
     <string name="permdesc_mediaContentControl" msgid="1637478200272062">"Umožňuje aplikácii ovládať reprodukciu médií a pristupovať k informáciám o médiách (názov, autor...)."</string>
-    <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"meniť nastavenia zvuku"</string>
+    <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"zmeny vašich nastavení zvuku"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Umožňuje aplikácii upraviť globálne nastavenia zvuku, ako je hlasitosť, alebo určiť, z ktorého reproduktora bude zvuk vychádzať."</string>
-    <string name="permlab_recordAudio" msgid="3876049771427466323">"nahrávať zvuk"</string>
+    <string name="permlab_recordAudio" msgid="3876049771427466323">"záznam zvuku"</string>
     <string name="permdesc_recordAudio" msgid="4906839301087980680">"Umožňuje aplikácii zaznamenávať zvuk pomocou mikrofónu. Toto povolenie umožňuje aplikácii zaznamenávať zvuk kedykoľvek bez vášho potvrdenia."</string>
     <string name="permlab_sim_communication" msgid="1180265879464893029">"komunikácia s kartou SIM"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"Umožňuje aplikácii odosielať príkazy na kartu SIM. Toto je veľmi nebezpečné povolenie."</string>
-    <string name="permlab_camera" msgid="3616391919559751192">"fotiť a nakrúcať videá"</string>
+    <string name="permlab_camera" msgid="3616391919559751192">"snímanie fotografií a natáčanie videí"</string>
     <string name="permdesc_camera" msgid="8497216524735535009">"Umožňuje aplikácii fotografovať a nahrávať videá pomocou fotoaparátu. Toto povolenie umožňuje aplikácii používať fotoaparát kedykoľvek a bez vášho potvrdenia."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"Zakázať indikátor LED prenosu pri používaní fotoaparátu"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Umožňuje v predinštalovanej systémovej aplikácii zakázať indikátor LED používania fotoaparátu."</string>
@@ -543,17 +530,17 @@
     <string name="permdesc_mount_format_filesystems" msgid="8784268246779198627">"Umožňuje aplikácii formátovať vymeniteľný ukladací priestor."</string>
     <string name="permlab_asec_access" msgid="3411338632002193846">"získať informácie o internom ukladacom priestore"</string>
     <string name="permdesc_asec_access" msgid="3094563844593878548">"Umožňuje aplikácii získať informácie o internom ukladacom priestore."</string>
-    <string name="permlab_asec_create" msgid="6414757234789336327">"vytvoriť interné úložisko"</string>
-    <string name="permdesc_asec_create" msgid="4558869273585856876">"Umožňuje aplikácii vytvoriť interné úložisko."</string>
-    <string name="permlab_asec_destroy" msgid="526928328301618022">"zničiť interné úložisko"</string>
-    <string name="permdesc_asec_destroy" msgid="7218749286145526537">"Umožňuje aplikácii zničiť interné úložisko."</string>
-    <string name="permlab_asec_mount_unmount" msgid="8877998101944999386">"pripojiť alebo odpojiť interné úložisko"</string>
-    <string name="permdesc_asec_mount_unmount" msgid="3451360114902490929">"Umožňuje aplikácii pripojiť alebo odpojiť interné úložisko."</string>
-    <string name="permlab_asec_rename" msgid="7496633954080472417">"premenovať interné úložisko"</string>
-    <string name="permdesc_asec_rename" msgid="1794757588472127675">"Umožňuje aplikácii premenovať interné úložisko."</string>
+    <string name="permlab_asec_create" msgid="6414757234789336327">"vytvoriť interný ukladací priestor"</string>
+    <string name="permdesc_asec_create" msgid="4558869273585856876">"Umožňuje aplikácii vytvoriť interný ukladací priestor."</string>
+    <string name="permlab_asec_destroy" msgid="526928328301618022">"zničiť interný ukladací priestor"</string>
+    <string name="permdesc_asec_destroy" msgid="7218749286145526537">"Umožňuje aplikácii zničiť interný ukladací priestor."</string>
+    <string name="permlab_asec_mount_unmount" msgid="8877998101944999386">"pripojiť alebo odpojiť interný ukladací priestor"</string>
+    <string name="permdesc_asec_mount_unmount" msgid="3451360114902490929">"Umožňuje aplikácii pripojiť alebo odpojiť interný ukladací priestor."</string>
+    <string name="permlab_asec_rename" msgid="7496633954080472417">"premenovať interný ukladací priestor"</string>
+    <string name="permdesc_asec_rename" msgid="1794757588472127675">"Umožňuje aplikácii premenovať interný ukladací priestor."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ovládať vibrovanie"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Umožňuje aplikácii ovládať vibrácie."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ovládať kontrolku"</string>
+    <string name="permlab_flashlight" msgid="2155920810121984215">"ovládanie kontrolky"</string>
     <string name="permdesc_flashlight" msgid="6522284794568368310">"Umožňuje aplikácii ovládať svetlo."</string>
     <string name="permlab_manageUsb" msgid="1113453430645402723">"spravovať predvoľby a povolenia zariadení USB"</string>
     <string name="permdesc_manageUsb" msgid="7776155430218239833">"Umožňuje aplikácii spravovať predvoľby a povolenia zariadení USB."</string>
@@ -561,9 +548,9 @@
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Povoľuje prístup k ovládaču kernel MTP na implementáciu protokolu MTP USB."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"testovanie hardvéru"</string>
     <string name="permdesc_hardware_test" msgid="6597964191208016605">"Umožňuje aplikácii ovládať rôzne periférie na účely testovania hardvéru."</string>
-    <string name="permlab_callPhone" msgid="3925836347681847954">"priamo volať na telefónne čísla"</string>
+    <string name="permlab_callPhone" msgid="3925836347681847954">"priame volanie na telefónne čísla"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Umožňuje aplikácii volať telefónne čísla bez vášho zásahu. V dôsledku toho sa môžu účtovať neočakávané poplatky alebo sa môžu uskutočniť neočakávané hovory. Toto povolenie neumožňuje aplikácii volať na čísla tiesňového volania."</string>
-    <string name="permlab_callPrivileged" msgid="4198349211108497879">"priamo volať na ľubovoľné telefónne čísla"</string>
+    <string name="permlab_callPrivileged" msgid="4198349211108497879">"priame volanie na ľubovoľné telefónne čísla"</string>
     <string name="permdesc_callPrivileged" msgid="1689024901509996810">"Umožňuje aplikácii volať na akékoľvek telefónne číslo (bez vášho zásahu) vrátane čísiel tiesňového volania. Škodlivé aplikácie môžu uskutočňovať zbytočné a nezákonné volania na tiesňové linky."</string>
     <string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"priamo spustiť nastavenie tabletu CDMA"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"priamo spustiť nastavenie telefónu CDMA"</string>
@@ -578,10 +565,8 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Umožňuje aplikácii ovládať telefónne funkcie zariadenia. Aplikácia s týmto povolením môže prepínať siete alebo zapnúť a vypnúť rádio bez toho, aby vás na to upozornila."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"čítať stav a identitu telefónu"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Umožňuje aplikácii pristupovať k telefónnym funkciám zariadenia. Aplikácia s týmto povolením môže určiť telefónne číslo a ID zariadenia, či práve prebieha hovor, a vzdialené číslo, s ktorým je prostredníctvom hovoru nadviazané spojenie."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"čítanie presných stavov telefónu"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Umožňuje aplikácii pristupovať k presným stavom telefónu. Toto povolenie umožňuje aplikácii zistiť skutočný stav hovoru, či je hovor aktívny alebo na pozadí, zlyhania hovorov, presný stav dátového pripojenia a zlyhania dátového pripojenia."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"zabránenie prechodu tabletu do režimu spánku"</string>
-    <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"deaktivovať režim spánku"</string>
+    <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"zabránenie prechodu telefónu do režimu spánku"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Umožňuje aplikácii zabrániť prechodu tabletu do režimu spánku."</string>
     <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Umožňuje aplikácii zabrániť prechodu telefónu do režimu spánku."</string>
     <string name="permlab_transmitIr" msgid="7545858504238530105">"infračervený prenos"</string>
@@ -594,7 +579,7 @@
     <string name="permlab_factoryTest" msgid="3715225492696416187">"spustenie v režime továrenského testu"</string>
     <string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Umožňuje aplikácii spustenie v režime nízkoúrovňového testu výrobcu a povolí úplný prístup k hardvéru tabletu. K dispozícii iba vtedy, keď je tablet spustený v režime testovania výrobcu."</string>
     <string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Umožňuje aplikácii spustenie v režime nízkoúrovňového testu výrobcu a povolí úplný prístup k hardvéru telefónu. K dispozícii iba vtedy, keď je telefón spustený v režime testovania výrobcu."</string>
-    <string name="permlab_setWallpaper" msgid="6627192333373465143">"nastaviť tapetu"</string>
+    <string name="permlab_setWallpaper" msgid="6627192333373465143">"nastavenie tapety"</string>
     <string name="permdesc_setWallpaper" msgid="7373447920977624745">"Umožňuje aplikácii nastaviť tapetu systému."</string>
     <string name="permlab_setWallpaperHints" msgid="3278608165977736538">"upraviť veľkosť tapety"</string>
     <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"Umožňuje aplikácii nastaviť tipy pre veľkosť tapety systému."</string>
@@ -629,7 +614,7 @@
     <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Umožňuje aplikácii zmeniť stav sieťového pripojenia zdieľaného pomocou tetheringu."</string>
     <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"zmeniť nastavenie použitia údajov na pozadí"</string>
     <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"Umožňuje aplikácii zmeniť nastavenie používania údajov na pozadí."</string>
-    <string name="permlab_accessWifiState" msgid="5202012949247040011">"zobraziť pripojenia Wi-Fi"</string>
+    <string name="permlab_accessWifiState" msgid="5202012949247040011">"zobraziť pripojenia siete Wi-Fi"</string>
     <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>
@@ -647,25 +632,22 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Zmeniť stav siete WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Umožňuje aplikácii pripojiť tablet k sieťam WiMAX a odpojiť ho od nich."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Umožňuje aplikácii pripojiť telefón k sieťam WiMAX a odpojiť ho od nich."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"zadanie skóre sietí"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Umožňuje aplikácii hodnotiť siete a ovplyvňovať, ktoré siete by mal tablet preferovať."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Umožňuje aplikácii hodnotiť siete a ovplyvňovať, ktoré siete by mal telefón preferovať."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"párovať so zariadeniami Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Umožňuje aplikácii zobraziť informácie o konfigurácii Bluetooth na tablete. Taktiež jej umožňuje nadväzovať a akceptovať spojenia so spárovanými zariadeniami."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Umožňuje aplikácii zobraziť informácie o konfigurácii Bluetooth na telefóne. Taktiež jej umožňuje nadväzovať a akceptovať spojenia so spárovanými zariadeniami."</string>
-    <string name="permlab_nfc" msgid="4423351274757876953">"ovládať technológiu NFC"</string>
-    <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="permlab_nfc" msgid="4423351274757876953">"ovládať technológiu Near Field Communication"</string>
+    <string name="permdesc_nfc" msgid="7120611819401789907">"Umožňuje aplikácii komunikovať so značkami, kartami a čítačkami s podporou technológie Near Field Communication (NFC)."</string>
+    <string name="permlab_disableKeyguard" msgid="3598496301486439258">"zakázať uzamknutie 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_readSyncSettings" msgid="6201810008230503052">"čítať nastavenia synchronizácie"</string>
+    <string name="permlab_readSyncSettings" msgid="6201810008230503052">"čítanie nastavení 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>
+    <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"prepínať nastavenie synchronizácie medzi hodnotou zapnuté a vypnuté"</string>
     <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Umožňuje aplikácii upraviť nastavenia synchronizácie v účte. Pomocou tohto povolenia je možné napríklad povoliť synchronizáciu aplikácie Ľudia s účtom."</string>
     <string name="permlab_readSyncStats" msgid="7396577451360202448">"čítanie štatistických údajov o synchronizácii"</string>
     <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Umožňuje aplikácii čítať štatistické informácie o synchronizácii v účte vrátane histórie uskutočnených synchronizácií a informácií o množstve synchronizovaných údajov."</string>
-    <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"čítať odoberané informačné kanály"</string>
+    <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"čítanie zdrojov prihlásených na odber"</string>
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Umožňuje aplikácii získať podrobnosti o aktuálne synchronizovaných informačných kanáloch."</string>
-    <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"zapisovať odoberané informačné kanály"</string>
+    <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"zápis odoberaných zdrojov"</string>
     <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"Umožňuje aplikácii upraviť vaše aktuálne synchronizované informačné kanály. Škodlivé aplikácie môžu synchronizované informačné kanály zmeniť."</string>
     <string name="permlab_readDictionary" msgid="4107101525746035718">"čítať výrazy pridané do slovníka"</string>
     <string name="permdesc_readDictionary" msgid="659614600338904243">"Umožňuje aplikácii čítať všetky slová, názvy a frázy, ktoré mohol používateľ uložiť do svojho slovníka."</string>
@@ -703,18 +685,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"vyvolanie aplikácie pre konfiguráciu poskytnutú operátorom"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Umožňuje držiteľovi vyvolať aplikáciu pre konfiguráciu poskytnutú operátorom. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"zachytávať informácie o stave siete"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Umožňuje aplikácii zachytávať informácie o stave siete. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"zmeniť kalibráciu vstupného zariadenia"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Umožňuje aplikácii upraviť parametre kalibrácie dotykovej obrazovky. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"prístup k certifikátom DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Umožňuje aplikácii vydávať a používať certifikáty DRM. Bežné aplikácie by toto povolenie 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="policylab_watchLogin" msgid="914130646942199503">"Sledovať pokusy o odomknutie obrazovky"</string>
@@ -729,7 +703,7 @@
     <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_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="policylab_expirePassword" msgid="885279151847254056">"Nastav. koniec platnosti hesla"</string>
     <string name="policydesc_expirePassword" msgid="1729725226314691591">"Nastavte, ako často sa musí zmeniť heslo na uzamknutie obrazovky."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Nastaviť šifr. ukl. priestoru"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Vyžadovať šifrovanie uložených údajov aplikácií."</string>
@@ -1172,7 +1146,7 @@
     <string name="anr_application_process" msgid="8941757607340481057">"Aplikácia <xliff:g id="APPLICATION">%1$s</xliff:g> neodpovedá. Chcete ju zavrieť?"</string>
     <string name="anr_process" msgid="6513209874880517125">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> neodpovedá. \n\nChcete ho zavrieť?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
-    <string name="report" msgid="4060218260984795706">"Nahlásiť"</string>
+    <string name="report" msgid="4060218260984795706">"Prehľad"</string>
     <string name="wait" msgid="7147118217226317732">"Čakajte"</string>
     <string name="webpage_unresponsive" msgid="3272758351138122503">"Stránka nereaguje.\n\nChcete ju zavrieť?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Presmerovaná aplikácia"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Umožňuje aplikácii získať prístup k ukladaciemu priestoru zabezpečenému technológiou keyguard."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Ovládanie zobrazenia alebo skrytia technológie keyguard"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Umožňuje aplikácii ovládať technológiu keyguard."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Reagovanie na zmeny stavu dôveryhodnosti."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Umožňuje aplikácii reagovať na zmeny stavu dôveryhodnosti."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Viazanie sa na službu zástupcu dôveryhodnosti"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Umožňuje aplikácii viazať sa na službu zástupcu dôveryhodnosti."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interakcia so systémom aktualizácií a obnovenia"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Umožňuje aplikácii interakciu so systémom obnovenia a s aktualizáciami systému."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Ovládacie prvky lupy zobrazíte dvojitým dotknutím"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Zmeniť tapetu"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Aplikácia na počúvanie upozornení"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"Sieť VPN je aktivovaná"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Aplikáciu <xliff:g id="APP">%s</xliff:g> aktivovala sieť VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Dotykom môžete spravovať sieť."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 2a04337..1f1ab78 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinhronizacija"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Preveč izbrisov vsebine <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Pomnilnik tabličnega računalnika je poln. Izbrišite nekaj datotek, da sprostite prostor."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Shramba ure je polna. Izbrišite nekaj datotek, da sprostite prostor."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Pomnilnik telefona je poln. Izbrišite nekaj datotek, da sprostite prostor."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Omrežje je lahko nadzorovano"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Neznana tretja oseba"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Vklopi zvonjenje"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Se zaustavlja ..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tablični računalnik se bo zaustavil."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Ura se bo izklopila."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefon bo zaustavljen."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Ali želite izklopiti napravo?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Vnovičen zagon v varnem načinu"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Način za letalo"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
     <string name="safeMode" msgid="2788228061547930246">"Varni način"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"odstranjevanje bližnjic"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Aplikaciji omogoča odstranjevanje bližnjic z začetnega zaslona brez posredovanja uporabnika."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"preusmeritev odhodnih klicev"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Aplikaciji dovoli ogled klicane številke pri odhodnem klicu in ji omogoča preusmeritev klica na drugo številko ali prekinitev klica."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Aplikaciji omogoča, da obdela odhodne klice in spreminja klicne številke. S tem lahko aplikacija nadzira, preusmerja ali preprečuje odhodne klice."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"prejemanje sporočil (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Aplikaciji omogoča prejemanje in obdelavo SMS-ov. S tem lahko aplikacija nadzoruje ali izbriše sporočila, poslana v napravo, ne da bi vam jih pokazala."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"prejemanje sporočil (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Programu omogoča dostop do vsebine aktivnega okna. Zlonamerni programi lahko dobijo vso vsebino okna in pregledajo njeno besedilo razen gesel."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"začasno omogoči pripomočke za ljudi s posebnimi potrebami"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Aplikaciji omogoča, da v napravi začasno omogoči pripomočke za ljudi s posebnimi potrebami. Zlonamerne aplikacije jih lahko omogočijo brez soglasja uporabnika."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"pridobivanje žetona okna"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Aplikaciji dovoli, da pridobi žeton okna. Zlonamerne aplikacije lahko z oknom aplikacije vzpostavijo stik brez pooblastila in se lažno predstavljajo kot sistem."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"pridobivanje statističnih podatkov o okvirjih"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Aplikaciji dovoli, da zbira statistične podatke o okvirjih. Zlonamerne aplikacije lahko vidijo statistične podatke o okvirjih oken iz drugih aplikacij."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"prenos podatkov o oknih"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Omogoča, da aplikacija iz upravitelja oken pridobiva podatke o oknih. Zlonamerne aplikacije lahko pridobivajo podatke, namenjene za notranjo uporabo v sistemu."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filtriranje dogodkov"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Omogoča, da aplikacija registrira vhodni filter, ki pred razpošiljanjem filtrira tok vseh uporabniških dogodkov. Zlonamerne aplikacije lahko nadzirajo uporabniški vmesnik sistema brez posega uporabnika."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"povečevanje zaslona"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Omogoča aplikaciji povečevanje vsebine zaslona. Zlonamerne aplikacije lahko preoblikujejo vsebino zaslona tako, da je naprava neuporabna."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"delna zaustavitev"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Upravitelja dejavnosti preklopi v stanje za zaustavitev. Ne izvede celotne zaustavitve."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"preprečevanje preklopa programov"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Programu omogoča oddajo obvestila o prejetih sporočilih SMS. Zlonamerni programi lahko to uporabijo za ponarejanje dohodnih SMS-ov."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"pošiljanje oddaje, prejete s potisnim sporočilom WAP"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Programu omogoča oddajo obvestila, da je bilo potisno sporočilo WAP prejeto. Zlonamerni programi lahko to uporabijo za ponarejanje potrdila o prejemu sporočila MMS ali za neopazno menjavo vsebine poljubne spletne strani z zlonamernimi različicami."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"pošiljanje oddaj o ocenjevanju omrežij"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Aplikaciji dovoli oddajo obvestila, da je treba omrežja oceniti. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"omejevanje števila izvajajočih se procesov"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Programu omogoča nadzor največjega števila postopkov, ki se bodo izvajali. Tega nikoli ni treba uporabiti za navadne programe."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"vsiljeno zapiranje aplikacij v ozadju"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Lastniku omogoča povezovanje z vmesnikom storitve navideznega zasebnega omrežja najvišje ravni. Ne uporabljajte za navadne programe."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"povezovanje z ozadjem"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Imetniku omogoča povezavo z vmesnikom ozadja najvišje ravni. Tega nikoli ni treba uporabiti za navadne programe."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"povezava z oddaljenim prikazom"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Imetniku omogoča povezovanje z vmesnikom oddaljenega prikaza najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"poveži s storitvijo pripomočka"</string>
     <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 programe."</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 programe."</string>
-    <string name="permlab_bindTvInput" msgid="5601264742478168987">"povezava s TV-vhodom"</string>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Imetniku omogoča povezovanje z vmesnikom TV-vhoda najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"dodajanje ali odstranjevanje skrbnikov naprave"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Imetniku omogoča, da doda ali odstrani aktivne skrbnike naprave. Normalne aplikacije tega načeloma ne potrebujejo."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"spreminjanje usmerjenosti zaslona"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Programu omogoča, da uporabi kateri koli dekodirnik večpredstavnosti za predvajanje."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"upravljanje preverjenih poverilnic"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Aplikaciji dovoli nameščanje in odstranjevanje potrdil overitelja potrdil kot preverjenih poverilnic."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"izvajanje aplikacije ob nedejavnosti"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"To dovoljenje sistemu Android omogoča, da izvaja aplikacijo v ozadju, ko naprava ni v uporabi."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"vezanje na nedejavne storitve"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"To dovoljenje dovoli sistemu Android vezanje nedejavnih storitev aplikacije."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"branje/pisanje v sredstva, ki so v lasti skupine za diagnostiko"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Programu omogoča branje in pisanje na poljuben vir, ki je v lasti skupine za diagnostiko; na primer datoteke v mapi /dev. To lahko vpliva na stabilnost in varnost sistema. To naj uporablja SAMO izdelovalec ali operater za diagnostiko, specifično za strojno opremo."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"omogočanje ali onemogočanje komponent programa"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Aplikaciji omogoča branje osebnih podatkov v profilu, ki so shranjeni v napravi, na primer ime in podatki za stik. To pomeni, da vas lahko aplikacija prepozna in vaše podatke v profilu pošlje drugim."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"spreminj. vaše osebne vizitke"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Aplikaciji omogoča spreminjanje ali dodajanje osebnih podatkov v profilu, ki so shranjeni v napravi, na primer ime in podatki za stik. To pomeni, da vas lahko aplikacija prepozna in vaše podatke v profilu pošlje drugim."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"tipala telesnih funkcij (npr. merilniki srčnega utripa)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Aplikaciji dovoli dostop do podatkov tipal, ki jih uporabljate za merjenje procesov v telesu, kot je srčni utrip."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"branje vašega družabnega toka"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Aplikaciji omogoča dostop do vaših objav in objav vaših prijateljev v družabnih omrežjih ter njihovo sinhronizacijo. Previdno pri objavljanju informacij – aplikacija lahko s tem bere komunikacijo med vami in prijatelji v družabnih omrežjih, ne glede na zasebnost. Opomba: Tega dovoljenja ni mogoče uveljaviti v vseh družabnih omrežjih."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"pisanje v vaš družabni tok"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Programu omogoča nadziranje telefonskih funkcij naprave. Program lahko s tem dovoljenjem preklaplja omrežja, vklopi ali izklopi radio v telefonu, ne da bi vas obvestil."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"branje stanja in identitete telefona"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Aplikaciji omogoča dostop do funkcij telefona v napravi. S tem dovoljenjem lahko aplikacija določi telefonsko številko in ID-je naprave, določi lahko tudi, ali je klic aktiven, in oddaljeno številko, s katero je klic povezan."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"branje natančnih stanj telefona"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Aplikaciji dovoli dostop do natančnih stanj telefona. To dovoljenje aplikaciji omogoča ugotoviti pravo stanje klica; ali je klic aktiven ali v ozadju; neuspele klice; natančno stanje podatkovne povezave in neuspele podatkovne povezave."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"preprečitev prehoda tabličnega računalnika v stanje pripravljenosti"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"preprečevanje prehoda v stanje pripravljenosti telefona"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Omogoča, da program prepreči prehod tabličnega računalnika v stanje pripravljenosti."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Sprememba stanja omrežja WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Aplikaciji omogoča, da vzpostavi povezavo med tabličnim računalnikom in omrežjem WiMAX ter jo prekine."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Aplikaciji omogoča, da vzpostavi povezavo med telefonom in omrežjem WiMAX ter jo prekine."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ocenjevanje omrežij"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Aplikaciji dovoli, da omrežja razvršča in vpliva na to, katera naj tablični računalnik prednostno izbere."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Aplikaciji dovoli, da omrežja razvršča in vpliva na to, katera naj telefon prednostno izbere."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"seznanitev z napravami Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Aplikaciji omogoča ogled konfiguracije Bluetootha tabličnega računalnika ter vzpostavljanje in sprejemanje povezave s seznanjenimi napravami."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Aplikaciji omogoča ogled konfiguracije Bluetootha telefona ter ustvarjanje in sprejemanje povezave s seznanjenimi napravami."</string>
@@ -703,18 +683,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"sprožitev operaterjeve aplikacije za konfiguracijo"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Lastniku omogoča sproženje operaterjeve aplikacije za konfiguracijo. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"spremljanje razmer v omrežju"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Aplikaciji omogoča spremljanje razmer v omrežju. Pri navadnih aplikacijah to ne bi smelo biti potrebno."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"sprememba umerjanja vhodne naprave"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Aplikaciji dovoli spreminjanje parametrov za umerjanje zaslona na dotik. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"dostop do potrdil za upravljanje digitalnih pravic"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Aplikaciji omogoča pripravo in uporabo potrdil za upravljanje digitalnih pravic. To naj ne bi bilo nikoli potrebno za običajne 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="policylab_watchLogin" msgid="914130646942199503">"nadzor nad poskusi odklepanja zaslona"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Aplikaciji omogoča dostop do varne shrambe Keyguard."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Nadzira prikaz in skrivanje zaklepanja tipkovnice"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Aplikaciji omogoča nadzor zaklepanja tipkovnice."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Spremljanje sprememb stanja zaupanja."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Aplikaciji dovoli spremljanje sprememb stanja zaupanja."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Povezovanje s storitvijo posrednikov zaupanja"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Aplikaciji dovoli povezovanje s storitvijo posrednikov zaupanja."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Uporaba sistema za posodobitev in obnovitev"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Aplikaciji dovoli uporabo sistema za obnovitev in posodobitev sistema."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Dvakrat se dotaknite za nadzor povečave/pomanjšave"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Ozadje"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Spreminjanje ozadja"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Poslušalec obvestil"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN aktiviran"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN je aktiviral program <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Dotaknite se, če želite upravljati omrežje."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 5d03ffa..4a12386 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Синхронизација"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Превише <xliff:g id="CONTENT_TYPE">%s</xliff:g> избрисаних ставки."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Меморија таблета је пуна! Избришите неке датотеке да бисте ослободили простор."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Меморија сата је пуна. Избришите неке датотеке да бисте ослободили простор."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Складиште телефона је пуно! Избришите неке датотеке како бисте ослободили простор."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мрежа се можда надгледа"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Од стране непознате треће стране"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Звоно је укључено"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Искључивање…"</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Таблет ће се искључити."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Сат ће се угасити."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Телефон ће се искључити."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Да ли желите да искључите телефон?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Поново покрени систем у безбедном режиму"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Режим рада у авиону"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безбедни режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android систем"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"деинсталирање пречица"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Омогућава апликацији да уклања пречице са почетног екрана без интервенције корисника."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"преусмеравање одлазних позива"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Дозвољава апликацији да види који број се бира при одлазном позиву уз опцију да преусмери позив на други број или га потпуно прекине."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Дозвољава апликацији да обрађује одлазне позиве и промени број који се бира. Ова дозвола омогућава апликацији да надгледа, преусмерава или спречава одлазне позиве."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"пријем текстуалних порука (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Дозвољава апликацији да прима и обрађује SMS поруке. То значи да апликација може да надгледа или брише поруке које се шаљу уређају, а да вам их не прикаже."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"пријем текстуалних порука (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Дозвољава апликацији да преузме садржај активног прозора. Злонамерне апликације могу да преузму цео садржај прозора и прегледају целокупан текст, осим лозинки."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"привремено омогућавање приступачности"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Дозвољава апликацији да привремено омогући приступачност на уређају. Злонамерне апликације могу да омогуће приступачност без дозволе корисника."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"преузимање токена прозора"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Дозвољава апликацији да преузима токен прозора. Злонамерне апликације могу да ступе у неовлашћену интеракцију са прозором апликације лажно се представљајући као систем."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"преузимње статистике оквира"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Дозвољава апликацији да прикупља статистику о оквиру. Злонамерне апликације могу да прате статистику оквира прозора из других апликација."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"преузимање информација о прозорима"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Омогућава апликацији да преузме информације о прозорима од менаџера прозора. Злонамерне апликације могу да преузму информације које су намењене за интерну употребу система."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"филтрирање догађаја"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Омогућава апликацији да региструје филтер улазног садржаја који филтрира стрим свих догађаја корисника пре њиховог слања. Злонамерна апликација може да контролише кориснички интерфејс система без интервенције корисника."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"увеличавање екрана"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Дозвољава апликацији да увеличава садржај екрана. Злонамерне апликације могу да промене садржај екрана до те мере да уређај постаје неупотребљив."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"делимично искључивање"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Ставља менаџера активности у стање искључивања. Не искључује га у потпуности."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"спречавање пребацивања са једне апликације на другу"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Дозвољава апликацији да емитује обавештење да је SMS порука примљена. Злонамерне апликације на тај начин могу да фалсификују долазне SMS поруке."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"слање примљених PUSH емитовања преко WAP-а"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Дозвољава апликацији да емитује обавештење да је примљена PUSH порука преко WAP-а. Злонамерне апликације то могу да искористе да фалсификују пријем MMS порука или да кришом замене садржај било које веб-странице уносом злонамерног садржаја."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"шаљи обавештења о тестирању мрежа"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Омогућава апликацији да емитује обавештење да је потребно тестирање мрежа. Никада није потребно за стандардне апликације."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"ограничење броја покренутих процеса"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Дозвољава апликацији да управља максималним бројем процеса који ће моћи да се покрену. Никада није потребна уобичајеним апликацијама."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"принудно затварање позадинских апликација"</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Дозвољава власнику да се повеже са интерфејсом VPN услуге највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"обавезивање на позадину"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дозвољава власнику да се повеже са интерфејсом позадине највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"повезивање са удаљеним екраном"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Омогућава апликацији да користи било који инсталирани декодер медија за декодирање за репродукцију."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"управљање поузданим акредитивима"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Дозвољава апликацији да инсталира и деинсталира CA сертификате као поуздане акредитиве."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"покреће апликације током неактивности"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Ова дозвола омогућава систему Android да покреће апликације у позадини док се уређај не користи."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"повезивање са неактивним услугама"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Ова дозвола дозвољава систему Android да се веже за неактивне услуге апликације."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"читање ресурса у власништву дијагностике и уписивање података у њих"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Дозвољава апликацији да чита и уписује податке у било који ресурс у власништву групе за дијагностиковање, на пример, датотеке у директоријуму /dev. То може да угрози стабилност и безбедност система и треба да је користе САМО произвођач или оператер у сврхе дијагностиковањa хардвера."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"омогућавање или онемогућавање компоненти апликације"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Дозвољава апликацији да чита личне информације о профилу ускладиштене на уређају, као што су име и контакт информације. То значи да апликација може да вас идентификује и шаље другима информације о профилу."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"измена ваше контакт картице"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Дозвољава апликацији да мења или додаје нове личне информације о профилу ускладиштене на уређају, као што су име и контакт информације. То значи да апликација може да вас идентификује и шаље другима информације о профилу."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"телесни сензори (нпр. срчани монитор)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Дозвољава апликацији да приступа подацима сензора које користите за мерење телесних функција, као што је срчани пулс."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"читање друштвеног стрима"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Дозвољава апликацији да приступа вашим друштвеним ажурирањима и друштвеним ажурирањима пријатеља и да их синхронизује. Будите опрезни када делите информације – ово омогућава апликацији да чита преписке између вас и пријатеља на друштвеним мрежама, без обзира на поверљивост. Напомена: Ова дозвола се можда не примењује на све друштвене мреже."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"писање у друштвени стрим"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Дозвољава апликацији да управља функцијама телефона на уређају. Апликација са овом дозволом може да прелази са једне мреже на другу и да без обавештења укључује и искључује радио телефона и сличне функције."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"читање статуса и идентитета телефона"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Дозвољава апликацији да приступа функцијама телефона на уређају. Ова дозвола омогућава апликацији да утврди број телефона и ИД-ове уређаја, затим да ли је позив активан, као и број даљинског уређаја са којим је успостављен позив."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"читај прецизне статусе телефона"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Омогућава апликацији да приступа прецизним статусима телефона. Ова дозвола омогућава апликацији да утврди стварни статус позива, да ли је позив активан или у позадини, неуспеле позиве, прецизан статус везе за пренос података и неуспела успостављања везе за пренос података."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"спречавање преласка таблета у стање спавања"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"спречавање преласка телефона у стање спавања"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Дозвољава апликацији да спречи таблет да пређе у стање спавања."</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Промени WiMAX статус"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Дозвољава апликацији да повезује таблет са WiMAX мрежама и прекида везе са њима."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Дозвољава апликацији да повезује телефон са WiMAX мрежама и прекида везе са њима."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"тестирај мреже"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Омогућава апликацији да рангира мреже и утиче на то које су мреже примарне на таблету."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Омогућава апликацији да рангира мреже и утиче на то које су мреже примарне на телефону."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"упаривање са Bluetooth уређајима"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Дозвољава апликацији да прегледа конфигурацију Bluetooth-а на таблету, као и да успоставља и прихвата везе са упареним уређајима."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Дозвољава апликацији да прегледа конфигурацију Bluetooth-а на телефону, као и да успоставља и прихвата везе са упареним уређајима."</string>
@@ -703,18 +685,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозвољава апликацији да преузима, испитује и брише обавештења, укључујући она која постављају друге апликације."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"повезивање са услугом монитора обавештења"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозвољава власнику да се повеже са интерфејсом услуге монитора обавештења највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"позивање апликације са конфигурацијом коју одређује оператер"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Дозвољава власнику да позива апликацију са конфигурацијом коју одређује оператер. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"праћење података о условима на мрежи"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Дозвољава апликацији да прати податке о условима на мрежи. Не би никада требало да буде потребно за нормалне апликације."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"промени калибрацију улазног уређаја"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Дозвољава апликацији да модификује параметре калибрације додирног екрана. Не би требало да буде потребно за нормалне апликације."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"приступ DRM сертификатима"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Дозвољава апликацији да додељује и користи DRM сертификате. Никада не би требало да се користи за уобичајене апликације."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Подешавање правила за лозинку"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролишите дужину и знакове дозвољене у лозинкама за откључавање екрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Надгледање покушаја откључавања екрана"</string>
@@ -908,7 +882,7 @@
     <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Откључавање налога"</string>
     <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Превише покушаја уноса шаблона"</string>
     <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Да бисте откључали, пријавите се помоћу Google налога."</string>
-    <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Корисничко име (имејл адреса)"</string>
+    <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Корисничко име (адреса е-поште)"</string>
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Лозинка"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Пријави ме"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Неважеће корисничко име или лозинка."</string>
@@ -1262,7 +1236,7 @@
     <string name="sim_removed_message" msgid="2333164559970958645">"Мобилна мрежа неће бити доступна док не покренете систем поново уз уметање важеће SIM картице."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Готово"</string>
     <string name="sim_added_title" msgid="3719670512889674693">"SIM картица је додата"</string>
-    <string name="sim_added_message" msgid="6599945301141050216">"Рестартујте уређај да бисте могли да приступите мобилној мрежи."</string>
+    <string name="sim_added_message" msgid="6599945301141050216">"Поново покрените уређај да бисте могли да приступите мобилној мрежи."</string>
     <string name="sim_restart_button" msgid="4722407842815232347">"Поново покрени"</string>
     <string name="time_picker_dialog_title" msgid="8349362623068819295">"Подешавање времена"</string>
     <string name="date_picker_dialog_title" msgid="5879450659453782278">"Подешавање датума"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Дозвољава апликацији да приступа безбедној меморији заштићеној шифром."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Контролиши приказивање и скривање заштите шифром"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Дозвољава апликацији да контролише заштиту шифром."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Праћење промена Trust стања."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Дозвољава апликацији да прати промене Trust стања."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Везивање за услугу Trust agents"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Дозвољава апликацији да се веже за услугу Trust agents."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Интеракција са системом за ажурирање и опоравак"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Дозвољава апликацији да ступа у интеракцију са системом за опоравак и ажурирањима система."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Додирните двапут да бисте контролисали зум"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Позадина"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Промена позадине"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Монитор обавештења"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN је активиран"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Апликација <xliff:g id="APP">%s</xliff:g> је активирала VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Додирните да бисте управљали мрежом."</string>
@@ -1567,7 +1535,7 @@
     <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_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>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 3599074..cdc1ffb 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synkronisera"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"För många <xliff:g id="CONTENT_TYPE">%s</xliff:g>-borttagningar."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Pekdatorns lagringsutrymme är fullt. Ta bort några filer för att frigöra utrymme."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Klockans lagringsutrymme är fullt. Ta bort några filer för att frigöra utrymme."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Mobilens lagringsutrymme är fullt. Ta bort några filer för att frigöra utrymme."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Nätverket kan vara övervakat"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Av en okänd tredje part"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Ringsignal på"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Avslutar…"</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Din surfplatta stängs av."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Klockan stängs av."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Din telefon stängs av."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Vill du stänga av?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Starta om i felsäkert läge"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flygplansläge"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Säkert läge"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"avinstallera genvägar"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Tillåter att appen tar bort genvägar på startskärmen utan åtgärd från användaren."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"omdirigera utgående samtal"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Tillåter att appen ser numret du slår under ett utgående samtal och har möjlighet att koppla samtalet till ett annat nummer eller avbryta samtalet helt."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Tillåter att appen hanterar utgående samtal och ändrar numret som ska ringas upp. Med den här behörigheten kan appen övervaka, omdirigera eller förhindra utgående samtal."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"ta emot textmeddelanden (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Tillåter att appen tar emot och hanterar SMS. Detta innebär att appen kan övervaka eller ta bort meddelanden som skickats till enheten utan att visa dem för dig."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"ta emot textmeddelanden (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Tillåter att appen hämtar innehållet i det aktiva fönstret. Skadliga appar kan hämta allt innehåll i fönstret och läsa all text utom lösenord."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"aktivera tillgänglighetsläget tillfälligt"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Tillåt att en app tillfälligt aktiverar tillgänglighetsläget på enheten. Skadliga appar kan aktivera tillgänglighetsläget utan användarens medgivande."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"hämta fönstrets token"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Appen tillåts hämta fönstrets token. Skadliga appar kan interagera med appens fönster på ett otillåtet sätt och efterlikna systemet."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"hämta ramstatistik"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Appen tillåts samla in ramstatistik. Skadliga appar kan registrera statistik om ramar i andra appars fönster."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"hämta information om fönster"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Tillåter att appen hämtar information om fönstren från fönsterhanteraren. Skadliga appar kan hämta information som är avsedd för användning i det interna systemet."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"filtrera händelser"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Tillåter att appen registrerar indatafilter som filtrerar flödet med användarhändelser innan de skickas. Skadliga appar kan styra systemets användargränssnitt utan att användaren gör något."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"förstora skärmen"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Tillåter att en app förstorar innehållet på en skärm. Skadliga appar kan förvandla skärminnehållet på ett sätt som gör att enheten blir oanvändbar."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"avsluta delvis"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Sätter aktivitetshanteraren i avstängningsläge. Utför inte en fullständig avstängning."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"förhindrar programbyten"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Tillåter att appen sänder ut en avisering när SMS tas emot. Skadliga appar kan använda detta för att förfalska inkommande SMS."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"skicka WAP-PUSH-mottagen sändning"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Tillåter att appen skickar ett meddelande om att ett WAP PUSH-meddelande har tagits emot. Skadliga appar kan använda detta för att förfalska mottagning av MMS eller för att obemärkt byta ut innehållet på en webbsida mot skadligt innehåll."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"skicka betyg som nätverk skickar"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Tillåter att appen skickar ett meddelande om att nätverket måste betygsättas. Ska inte behövas för vanliga appar."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"begränsa antalet processer som körs"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Tillåter att appen styr högsta antalet processer som körs. Behövs inte för vanliga appar."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"tvinga bakgrundsappar att avslutas"</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en VPN-tjänst. Ska inte behövas för vanliga appar."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"binda till en bakgrund"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Innehavaren kan binda till den översta nivåns gränssnitt för en bakgrund. Ska inte behövas för vanliga appar."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind till en fjärrskärm"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en fjärrskärm. Ska inte behövas för vanliga appar."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind till en widget"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Tillåter att appen använder installerade medieavkodare för att avkoda media för uppspelning."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"hantera betrodda uppgifter"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Tillåter att appen installerar och avinstallerar CA-certifikat som betrodda uppgifter."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"kör appen när enheten är inaktiv"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Med den här behörigheten tillåts Android-systemet att köra appen i bakgrunden när enheten inte används."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"knyt till inaktiva tjänster"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Med den här behörigheten kan Android-systemet bindas till en apps inaktiva tjänster."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"läsa/skriva till resurser som ägs av diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Tillåter att appen läser och skriver till en resurs som ägs av diag-gruppen, till exempel filer i /dev. Detta kan eventuellt påverka systemets stabilitet och säkerhet. Detta bör ENDAST användas av tillverkaren eller operatören för maskinvaruspecifik diagnostik."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivera eller inaktivera appkomponenter"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Tillåter att appen läser personliga profiluppgifter som sparats på din enhet, t.ex. ditt namn och kontaktuppgifter. Det innebär att appen kan identifiera dig och skicka profiluppgifter till andra."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"ändra ditt eget kontaktkort"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Tillåter att appen ändrar eller lägger till personliga profiluppgifter som sparats på din enhet, till exempel ditt namn och dina kontaktuppgifter. Det innebär att appen kan identifiera dig och skicka profiluppgifter till andra."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"kroppssens. (för hjärtat m.m.)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Tillåter att appen får åtkomst till data från sensorer som används för att mäta vad som sker inuti kroppen, till exempel hjärtfrekvens."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"läs mitt sociala flöde"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Tillåter att appen kommer åt och synkroniserar sociala uppdateringar från dig och dina vänner. Var försiktig när du delar information – med den här behörigheten tillåts appen att läsa kommunikation mellan dig och dina vänner på sociala nätverk oavsett sekretessnivå. Observera att den här behörigheten kanske inte är tillämplig på alla sociala nätverk."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"skriv till mitt sociala flöde"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Tillåter att appen styr enhetens telefonfunktioner. En app med den här behörigheten kan byta nätverk, aktivera/inaktivera mobilens radio och liknande utan att meddela dig."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"läsa telefonens status och identitet"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Tillåter att appen kommer åt enhetens telefonfunktioner. Med den här behörigheten tillåts appen att identifiera mobilens telefonnummer och enhets-ID, om ett samtal pågår och vilket nummer samtalet är kopplat till."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"läsa mobilens exakta status"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Tillåter att appen får tillgång till mobilens exakta status. Appen får behörighet att avgöra mobilens faktiska samtalsstatus, om samtalet är aktivt eller i bakgrunden, om samtal misslyckas, mobilens exakta dataanslutningsstatus och om dataanslutningar misslyckas."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"förhindra att surfplattan går in i viloläge"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"förhindra att telefonen sätts i viloläge"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Tillåter att appen förhindrar att surfplattan går in i viloläge."</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"ändra WiMAX-status"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Tillåter att appen ansluter surfplattan till eller kopplar från WiMAX-nätverk."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Tillåter att appen ansluter mobilen till eller kopplar från WiMAX-nätverk."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"betygsätt nätverk"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Tillåter att appen betygsätter nätverk och påverkar vilka nätverk som ska användas i första hand av surfplattan."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Tillåter att appen betygsätter nätverk och påverkar vilka nätverk som ska användas i första hand av mobilen."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"koppla till Bluetooth-enheter"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Tillåter att appen kommer åt pekdatorns Bluetooth-konfiguration och upprättar och godkänner anslutningar till parkopplade enheter."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Tillåter att appen kommer åt mobilens Bluetooth-konfiguration och upprättar och godkänner anslutningar till parkopplade enheter."</string>
@@ -703,18 +685,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"anropa konfigurationsappen från operatören"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Innehavaren tillåts att anropa konfigurationsappen från operatören. Ska inte behövas för vanliga appar."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"lyssna efter information om nätverksförhållanden"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Tillåter att appen lyssnar efter information om nätverksförhållanden. Vanliga appar bör aldrig behöva den här behörigheten."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"ändra kalibreringen för inmatningsenheten"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Tillåter att appen ändrar kalibreringsparametrarna för pekskärmen. Detta behövs aldrig för vanliga appar."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"tillgång till DRM-certifikat"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Tillåter att en app tillhandahåller och använder DRM-certifikat. Behövs inte 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="policylab_watchLogin" msgid="914130646942199503">"Övervaka försök att låsa upp skärmen"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Tillåter att en app får åtkomst till säkert keyguard-lagringsutrymme."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Kontrollera hur knapplåset visas och döljs"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Tillåter att en app kontrollerar knapplåsfunktionen."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Lyssna efter ändringar i betrodda agenters status."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Tillåter att en app lyssnar efter ändringar i den betrodda agentens status."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Bind till en tjänst från en betrodd agent"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Tillåter att en app binds vid en tjänst från en betrodd agent."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Interagera med uppdaterings- och återställningssystemet"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Tillåter att en app interagerar med systemuppdateringar och återställningssystemet."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Tryck två gånger för zoomkontroll"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Bakgrund"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Ändra bakgrund"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Meddelandelyssnare"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN är aktiverat"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN aktiveras av <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Tryck om du vill hantera nätverket."</string>
@@ -1493,7 +1461,7 @@
     <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Gränsen för data via Wi-Fi har överskridits"</string>
     <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> över angiven gräns."</string>
     <string name="data_usage_restricted_title" msgid="5965157361036321914">"Bakgrundsdata är begränsade"</string>
-    <string name="data_usage_restricted_body" msgid="6741521330997452990">"Tryck för att ta bort begränsning"</string>
+    <string name="data_usage_restricted_body" msgid="6741521330997452990">"Tryck för att radera begränsning"</string>
     <string name="ssl_certificate" msgid="6510040486049237639">"Säkerhetscertifikat"</string>
     <string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Certifikatet är giltigt."</string>
     <string name="issued_to" msgid="454239480274921032">"Utfärdad till:"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 0c21017..e840e37 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -100,7 +100,7 @@
     <string name="roamingText4" msgid="8808456682550796530">"Nje ya Jengo"</string>
     <string name="roamingText5" msgid="7604063252850354350">"Urandaji - Mfumo unaopendelewa"</string>
     <string name="roamingText6" msgid="2059440825782871513">"Uzururaji - Mfumo Unaopatikana"</string>
-    <string name="roamingText7" msgid="7112078724097233605">"Roaming - Alliance Partner"</string>
+    <string name="roamingText7" msgid="7112078724097233605">"Uzururaji - Mwenza wa Ushirikiamo"</string>
     <string name="roamingText8" msgid="5989569778604089291">"Uzururaji - Mwenzi wa Thamani"</string>
     <string name="roamingText9" msgid="7969296811355152491">"Uzururaji - Utendajikazi Kamili wa Huduma"</string>
     <string name="roamingText10" msgid="3992906999815316417">"Uzururaji - Utendajikazi Nusi wa Huduma"</string>
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sawazisha"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Ufutaji mwingi sana <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Hifadhi ya kompyuta kibao imejaa. Futa baadhi ya faili ili kupata nafasi."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Hifadhi ya saa imejaa. Futa baadhi ya faili ili uweze kupata nafasi."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Hifadhi ya simu imejaa. Futa baadhi ya faili ili uweze kupata nafasi."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Huenda mtandao unafuatiliwa"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Na mtu mwingine asiyejulikana"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Programu ya milio imewashwa"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Inafunga..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Kompyuta kibao yako itazima."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Saa yako itajizima."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Simu yako itazima."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Unataka kuzima?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Washa upya kwa hali salama"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Hali ya ndege"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mtindo salama"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Mfumo wa Android"</string>
@@ -254,12 +251,12 @@
     <string name="permdesc_statusBarService" msgid="716113660795976060">"Inaruhusu programu kuwa upau wa hali."</string>
     <string name="permlab_expandStatusBar" msgid="1148198785937489264">"panua/kunja mwambaa hali"</string>
     <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"Inaruhusu programu kupanua au kukunja upau wa hali."</string>
-    <string name="permlab_install_shortcut" msgid="4279070216371564234">"kuweka njia za mkato"</string>
+    <string name="permlab_install_shortcut" msgid="4279070216371564234">"sakinisha njia za mkato"</string>
     <string name="permdesc_install_shortcut" msgid="8341295916286736996">"Huruhusu programu kuongeza njia za mkato za Skrini ya kwanza bila mtumiaji kuingilia."</string>
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"ondoa njia za mikato"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Huruhusu programu kuondoa njia za mkato za Skrini ya kwanza bila mtumiaji kuingilia."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"panga upya simu zinazotoka"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Huruhusu programu kuona nambari inayopigwa wakati simu inapigwa ikiwa na chaguo la kuelekeza simu kwenye nambari tofauti au kukata simu kabisa."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Inaruhusu programu kuchakata simu zinazotoka nje na kubadilisha nambari ya kupigwa. Idhini hii inaruhusu programu kuchunguza, kuelekeza upya, au kuzuia simu zinazotoka nje."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"pokea ujumbe wa maandishi wa SMS"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Inaruhusu programu kupokea na kuchakata ujumbe wa SMS. Hii inamaanisha programu hii inaweza kuchunguza na kufuta ujumbe uliotumwa katika kifaa chako bila ya kukuonyesha."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"pokea ujumbe wa maandishi wa MMS"</string>
@@ -282,7 +279,7 @@
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Inaruhusu programu kupokea na kuchakata ujumbe wa WAP. Idhini hii inajumuisha uwezo wa kuchunguza na kufuta ujumbe uliotumwa kwako bila ya kukuonyesha."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"rudisha programu zinazoendeshwa"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Inaruhusu programu kurudisha taarifa kuhusu kazi zinazoendeshwa sasa na hivi karibuni. Hii inaweza kuruhusu programu kugundua taarifa kuhusu ni programu zipi zinazotumika kwenye kifaa."</string>
-    <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"kuwasiliana na watumiaji wengine"</string>
+    <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"Tagusana na watumiaji"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Inaruhusu programu kutenda vitendo kwa watumiaji tofauti kwenye kifaa. Programu hasidi huenda zikatumia hii ili kukiuka ulinzi kati ya watumiaji."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"leseni kamili ili kushirikiana na watumiaji"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Inaruhusu miingialiano yote inayowezekana kwa watumiaji."</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Inaruhusu programu kutoa maudhui ya dirisha amilifu. Programu hasidi zinaweza kutoa maudhui yote ya dirisha na kuchunguza maandishi yake yote isipokuwa nenosiri."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"wezesha ufikivu kwa muda"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Inaruhusu programu kuwezesha kwa muda ufikivu kwenye kifaa. Huenda programu hasidi zikawezesha ufikivu bila kibali cha mtumiaji."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"rejesha tokeni ya dirisha"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Inaruhusu programu kurejesha tokeni ya dirisha. Programu hasidi zinaweza kutekeleza mwingiliano usioidhinishwa na dirisha la programu zikiiga mfumo."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"rejesha takwimu za fremu"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Inaruhusu programu kukusanya takwimu za fremu. Programu hasidi zinaweza kuchunguza takwimu za fremu za dirisha kutoka kwenye programu zingine."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"okoa maelezo ya dirisha"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Huruhusu programu kuokoa maelezo kuhusu madirisha kutoka kwenye kidhibiti dirisha. Huenda programu hasidi ikakusanya maelezo ambayo yamekusudiwa kwa matumizi ya mfumo wa ndani."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"chuja matukio"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Huruhusu programu kusajili kichujio ingizo kinachochuja mkondo wa matukio ya mtumiaji kabla ya kutumwa. Huenda programu hasidi ikadhibiti mfumo wa UI bila mtumiaji kuingilia kati."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"kuza oneysho"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Inaruhusu programu kukuza maudhui ya onyesho. Programu hasidi zinaweza kubadili maudhui kwa njia ambayo inaweza kukifanya kifaa kutotumika."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"Zima nusu"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Huweka kisimamia shughuli katika hali ya kuzima. Haiadhiri uzimaji kamili"</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"zuia swichi za app"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Huruhusu programu kutangaza taarifa kwamba ujumbe wa SMS umeingia. Programu hasidi zinaweza kutumia hii kubuni SMS zinazoingia."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"tuma tangazo lililopokewa la MSUKUMO WA WAP"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Inaruhusu programu kutangaza taarifa kwamba ujumbe wa WAP PUSH umepokewa. Programu hasidi zinaweza kutumia hii kubuni risiti ya ujumbe wa MMS au polepole kubadilisha maudhui yoyote ya ukurasa wa tovuti na vibadala vibovu."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"tuma tangazo la alama za mitandao"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Huruhusu programu kutangaza arifa kuwa mitandao inafaa kupewa alama. Haihitajiki kamwe kwa programu za kawaida."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"zuia idadi ya michakato inayoendeshwa"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Inaruhusu programu kudhibiti upeo wa idadi ya michakato ambayo itaendeshwa. Kamwe hazihitajiki kwa programu za kwaida."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"lazimisha programu za usuli kufunga"</string>
@@ -353,7 +348,7 @@
     <string name="permlab_updateAppOpsStats" msgid="8829097373851521505">"rekebisha takwimu za oparesheni ya programu"</string>
     <string name="permdesc_updateAppOpsStats" msgid="50784596594403483">"Inaruhusu programu kurekebisha takwimu za matumizi ya programu zilizokusanywa. Si ya kutumiwa na programu za kawaida."</string>
     <string name="permlab_backup" msgid="470013022865453920">"Dhibiti kuhifadhi nakala na kurejesha kwa mfumo"</string>
-    <string name="permdesc_backup" msgid="6912230525140589891">"Huruhusu programu kudhibiti utaratibu wa kuhifadhi nakala rudufu na kurejesha mfumo. Haifai kutumiwa na programu za kawaida."</string>
+    <string name="permdesc_backup" msgid="6912230525140589891">"Inaruhusu programu kudhibiti utaratibu wa kucheleza na kurejesha wa mfumo. Si kwa matumizi na programu za kawaida."</string>
     <string name="permlab_confirm_full_backup" msgid="5557071325804469102">"thibitisha chelezo kamilifu au rejesha upya uendeshaji"</string>
     <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Huruhusu programu kuzindua kiolesura cha kuthibitisha kuhifadhiwa kwa nakala rudufu kamili. Haitumiwi na programu yoyote."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"onyesha madirisha yasiyoidhinishwa"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Inaruhusu kishikiliaji kushurutisha kusano ya kiwango cha juu cha huduma ya Vpn. Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"funga kwa mandhari"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Inaruhusu kishikiliaji kushurutisha kwa kusano ya kiwango cha juu cha mandhari. Haipaswi kamwe kuhitajika kwa programu za kawaida."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"fungisha kwenye mwonekano wa mbali"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Huruhusu mtumiaji kujifungia kiolesura cha kiwango cha juu cha mwonekano wa mbali. Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"funga kwenye huduma ya widget"</string>
     <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">"Inamruhusu mmiliki kutuma malengo kwa msimamizi wa kifaa. Haipaswi kuhitajika kwa programu za kawaida."</string>
-    <string name="permlab_bindTvInput" msgid="5601264742478168987">"bandika kwenye zana za data ya runinga"</string>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Inaruhusu kishikiliaji kubandika kwenye kusano la kiwango cha juu cha zana za data kwenye runinga. Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ongeza au ondoa msimamizi wa kifaa"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Inaruhusu mmiliki kuongeza au kuondoa wasimamizi wa kifaa waliopo. Kamwe kisihitajike kwa ajili ya programu za kawaida."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"badilisha uelekezo wa skrini"</string>
@@ -424,7 +411,7 @@
     <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Inaruhusu Programu kupata tena msimbo, data na ukubwa wa kache yake."</string>
     <string name="permlab_installPackages" msgid="2199128482820306924">"sakinisha programu moja kwa moja"</string>
     <string name="permdesc_installPackages" msgid="5628530972548071284">"Inaruhusu programu kusakanisha au kusasisha furushi mpya za Android. Programu hasidi zinaweza kutumia hii kuongeza programu mpya ambazo zina ruhusa zenye nguvu."</string>
-    <string name="permlab_clearAppCache" msgid="7487279391723526815">"kufuta data yote kwenye akiba ya programu"</string>
+    <string name="permlab_clearAppCache" msgid="7487279391723526815">"Futa data yote kwenye kache ya programu"</string>
     <string name="permdesc_clearAppCache" product="tablet" msgid="8974640871945434565">"Inaruhusu programu kutoa nafasi ya hifadhi ya kompyuta ndogo kwa kufuta faili katika saraka za kache za programu nyingine. Huenda hii ikasababisha programu nyingine kuanza polepole zaidi kwa sababu zinahitaji kuepua data zazo."</string>
     <string name="permdesc_clearAppCache" product="default" msgid="2459441021956436779">"Inaruhusu programu kutoa nafasi ya hifadhi ya simu kwa kufuta faili katika saraka za kache za programu nyingine. Huenda hii ikasababisha programu nyingine kuanza polepole zaidi kwa sababu zinahitaji kuepua data zazo."</string>
     <string name="permlab_movePackage" msgid="3289890271645921411">"songesha rasilimali ya programu"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Huruhusu programu kutumia vyombo vyovyote vya habari vilivyosakinishwa ili kusimbua kwa ajili ya kucheza tena."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"dhibiti vitambulisho vinavyoaminika"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Huruhusu programu kusakinisha na kusanidua vyeti vya CA kama vitambulisho vinavyoaminika."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"endesha programu wakati kifaa hakifanyi kitu"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Ruhusa hii huwezesha mfumo wa Android kuendesha programu chini kwa chini wakati kifaa hakitumiki."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"funga kwenye huduma zisizofanya kitu"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Ruhusa hii huruhusu mfumo wa Android kuunga kwenye huduma za programu amabazo hazitumiki."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"soma/andika kwa vyanzo vinavyomilikiwa na diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Inaruhusu programu kusoma na kuandika kwa chanzo chochote kinachomilikiwa na kikundi cha diag; kwa mfano, faili katika /dev. Hii inaweza kuathiri udhabiti na usalama wa mfumo. Hii inapaswa kutumiwa TU kwa utambuzi mahsusi wa maunzi na mtengenezaji au opareta."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"wezesha au lemeza vijenzi vya programu"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Inaruhusu programu kusoma taarifa ya kibinafsi ya maelezo mafupi yaliyohifadhiwa kwenye kifaa chako, kama vile jina lako na taarifa ya anwani. Hii inamaanisha kuwa programu inaweza kukutambua na inaweza kuwatumia wengine taarifa yako ya maelezo mafupi."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"rekebisha kadi yako mwenyewe ya mawasiliano"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Inaruhusu programu kubadilisha au kuongeza taarifa ya maelezo mafupi ya kibinafsi yaliyohifadhiwa kwenye kifaa chako, kama vile jina lako na taarifa ya anwani. Hii inamaanisha kuwa programu inaweza kukutambua na inaweza kutuma taarifa ya maelezo yako mafupi kwa wengine."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"vipima hali ya mwili (kama mpigo wa moyo)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Huruhusu programu kufikia data kutoka kwenye vipima mawimbi unavyotumia kupima kinachoendelea mwilini mwako kama vile mpigo wa moyo."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"soma mipasho yako wa kijamii"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Huruhusu programu kufikia na kupatanisha masasisho ya kijamii kutoka kwa marafiki zako. Kuwa makini wakati unashiriki taarifa -- hii huruhusu programu kusoma mawasiliano kati yako na marafiki zako kwenye mitandao jamii, bila kujali usiri. Kumbuka: idhini hii haiwezi kutekelezwa kwenye mitandao yote ya jamii."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"kuandikia mipasho yako wa kijamii"</string>
@@ -551,7 +536,7 @@
     <string name="permdesc_asec_mount_unmount" msgid="3451360114902490929">"Inaruhusu programu kupachika/kupachua hifadhi ya ndani."</string>
     <string name="permlab_asec_rename" msgid="7496633954080472417">"ipe hifadhi ya ndani jina jipya"</string>
     <string name="permdesc_asec_rename" msgid="1794757588472127675">"Inaruhusu programu kubadilisha jina la hifadhi ya ndani."</string>
-    <string name="permlab_vibrate" msgid="7696427026057705834">"Kudhibiti mtetemo"</string>
+    <string name="permlab_vibrate" msgid="7696427026057705834">"dhibiti mtetemo"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Inaruhusu programu kudhibiti kitingishi."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"dhibiti tochi"</string>
     <string name="permdesc_flashlight" msgid="6522284794568368310">"Inaruhusu programu kudhibiti tochi."</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Inaruhusu programu kudhibiti vipengee vya kifaa. Programu iliyo na ruhusa hii inaweza badilisha mtandao, kuzima na kuwasha redio ya simu bila hata kukujulisha."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"kusoma hali na kitambulisho cha simu"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Inaruhusu programu kufikia vipengele vya simu vya kifaa. Idhini hii inaruhusu programu kutambua nambari ya simu na kifaa, kama simu ni amilifu, na nambari ya mbali iliyounganishwa kwa simu."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"Soma hali sahihi ya simu"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Huruhusu programu kufikia hali sahihi ya simu. Ruhusa hii huwezesha programu kufahamu hali sahihi ya simu, iwapo simu inatumika au iko katika hali ya chini kwa chini, simu inaposhindikana, hali sahihi ya muunganisho wa data na muunganisho wa data unaposhindikana."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"zuia kompyuta ndogo dhidi ya kulala"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"kuzuia simu isilale"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Inaruhusu programu kuzuia kompyuta kibao  kwenda kulala."</string>
@@ -617,19 +600,19 @@
     <string name="permdesc_manageAccounts" msgid="8698295625488292506">"Inaruhusu programu kutekeleza shughuli kama vile kuongeza na kutoa akaunti, na kufuta manenosiri yazo."</string>
     <string name="permlab_useCredentials" msgid="235481396163877642">"kutumia akaunti zilizo kwenye kifaa"</string>
     <string name="permdesc_useCredentials" msgid="7984227147403346422">"Inaruhusu programu kuomba shuhuda za uthibitisho."</string>
-    <string name="permlab_accessNetworkState" msgid="4951027964348974773">"kuona mitandao"</string>
+    <string name="permlab_accessNetworkState" msgid="4951027964348974773">"Kuangalia mitandao"</string>
     <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Inaruhusu programu kuona taarifa kuhusu miunganisho ya mtandao kama vile mitandao ipi iliyopo na imeunganishwa."</string>
     <string name="permlab_createNetworkSockets" msgid="8018758136404323658">"ufikiaji kamili wa mtandao"</string>
     <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Inaruhusu programu kuunda soketi za mtandao na kutumia itifaki za mtandao maalum. Kivinajri na programu nyingine zilizotolewa zinamaanisha kutuma data kwenye mtandao, kwa hivyo kibali hiki hakihitajiki kutuma data kwenye mtandao."</string>
     <string name="permlab_writeApnSettings" msgid="505660159675751896">"mabadiliko / kuingilia mipangilio ya mtandao/msonmgamano"</string>
     <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"Inaruhusu programu kubadilisha mipangilio ya mtandao na kukatiza na kukagua uendaji wa mtandao, kwa mfano kubadilisha kituo tarishi na mbadala cha APN yoyote. Programu hasidi zinaweza kuangalia, kuelekeza kwingine, au kurekebisha furushi za mtandao bila ya wewe kujua."</string>
-    <string name="permlab_changeNetworkState" msgid="958884291454327309">"kubadilisha muunganisho wa mtandao"</string>
+    <string name="permlab_changeNetworkState" msgid="958884291454327309">"badilisha muunganisho wa mtandao"</string>
     <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Inaruhusu programu kubadilisha hali ya muunganisho wa mtandao."</string>
     <string name="permlab_changeTetherState" msgid="5952584964373017960">"Badilisha muunganisho uliofunganishwa"</string>
     <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Inaruhusu programu kubadilisha hali ya muunganisho wa mtandao uliofungwa."</string>
     <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"badilisha mpangilio wa utumiaji data ya mandharinyuma"</string>
     <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"Inaruhusu programu kubadilisha mpangilio wa matumizi ya data ya usuli."</string>
-    <string name="permlab_accessWifiState" msgid="5202012949247040011">"Kuona miunganisho ya Wi-Fi"</string>
+    <string name="permlab_accessWifiState" msgid="5202012949247040011">"ona miunganisho ya Wi-Fi"</string>
     <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Inaruhusu programu kuona taarifa kuhusu mtandao wa Wi-Fi, kama vile ikiwa Wi-Fi imewezeshwa mna jina la vifaa vya Wi-Fi vilivyounganishwa."</string>
     <string name="permlab_changeWifiState" msgid="6550641188749128035">"unganisha na utenganishe kutoka kwa Wi-Fi"</string>
     <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Inaruhusu programu kuunganisha kwenye au kukata kutoka pointi za ufikivu wa Wi-Fi na kufanya mabadiliko kwenye usanidi wa kifaa cha mitandao ya Wi-Fi."</string>
@@ -647,31 +630,28 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Badilisha hali ya WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Inaruhusu programu kuunganisha kompyuta kibao,  na kukata kompyuta kibao kutoka mitandao ya WiMAX."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Inaruhusu programu kuunganisha simu kwenye, na kukata simu kutoka mitandao ya WiMAX."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ipe mitandao alama"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Huruhusu programu kupanga mitandao kwa alama na kushawishi mitandao ambayo kompyuta kibao inapaswa kupendelea."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Huruhusu programu kupanga mitandao kwa alama na kushawishi mitandao ambayo simu inapaswa kupendelea."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"oanisha na vifaa vya Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Inaruhusu programu kuona usanidi wa Bluetooth kwenye kompyuta kibao, na kuunda na kukubali miunganisho kwa vifaa vilivyooanishwa."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Inaruhusu programu kuona usanidi wa Bluetooth kwenye simu, na kuunda na kukubali miunganisho kwa vifaa vilivyooanishwa."</string>
-    <string name="permlab_nfc" msgid="4423351274757876953">"kudhibiti Mawasiliano ya Vifaa Vilivyokaribu (NFC)"</string>
+    <string name="permlab_nfc" msgid="4423351274757876953">"dhibiti Mawasiliano ya vifaa vilivyo Karibu"</string>
     <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_readSyncSettings" msgid="6201810008230503052">"kusoma mipangilio ya usawazishaji"</string>
+    <string name="permlab_readSyncSettings" msgid="6201810008230503052">"soma 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>
+    <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"washa na uzime usawazishaji"</string>
     <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Inaruhusu programu kurekebisha mipangalio ya upatanishi wa akaunti. Kwa mfano, hii inaweza kuwezesha programu ya upatanishi wa Watu na akaunti."</string>
-    <string name="permlab_readSyncStats" msgid="7396577451360202448">"kusoma takwimu za usawazishaji"</string>
+    <string name="permlab_readSyncStats" msgid="7396577451360202448">"soma takwimu za usawazishaji"</string>
     <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Inaruhusu programu kusoma takwimu za upatanishi za akaunti, ikiwa ni pamoja na historia ya matukio ya upatanishi na kiasi cha data kimepatanishwa."</string>
-    <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"kusoma mipasho kutoka vyanzo unavyofuatilia"</string>
+    <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"soma milisho ya kujiunga"</string>
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Inaruhusu programu kupata maelezo kuhusu mlisho iliyolandanishwa kwa sasa."</string>
-    <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"kuandika mipasho kutoka vyanzo unavyofuatilia"</string>
+    <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"andika milisho ya kujiunga"</string>
     <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"Inaruhusu programu kurekebisha milisho yako iliyolandanishwa kwa sasa. Programu hasidi zinaweza kubadilisha milisho yako iliyolandanishwa."</string>
     <string name="permlab_readDictionary" msgid="4107101525746035718">"soma maneno uliyoongeza kwenye kamusi"</string>
     <string name="permdesc_readDictionary" msgid="659614600338904243">"Inaruhusu programu kusoma maneno, majina na misemo yote ambayo mtumiaji alihifadhi katika kamusi ya mtumiaji."</string>
     <string name="permlab_writeDictionary" msgid="2183110402314441106">"ongeza maneno katika kamusi ya mtumiaji iliyofafanuliwa"</string>
     <string name="permdesc_writeDictionary" msgid="8185385716255065291">"Inaruhusu programu kuandika maneno mapya katika kamusi ya mtumiaji."</string>
-    <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"kusoma maudhui yaliyo kwenye hifadhi yako ya USB"</string>
+    <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"soma maudhui ya hifadhi yako ya USB"</string>
     <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"soma maudhui ya kadi yako ya SD"</string>
     <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Huruhusu programu kusoma maudhui ya hifadhi ya USB."</string>
     <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Huruhusu programu kusoma maudhui ya kadi yako ya SD."</string>
@@ -703,18 +683,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"omba programu ya usakinishaji inayotolewa na mtoa huduma."</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Inaruhusu kishikiliaji kuomba programu ya usakinishaji inayotolewa na mto huduma. Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"sikiliza matukio katika hali za mtandao"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Huruhusu programu kusikiliza matukio katika hali za mtandao. Haipaswi kuhitajika kamwe kwa programu za kawaida."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"badilisha urekebishaji wa kifaa cha kuingiza data"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Huruhusu programu kubadilisha vigezo vya urekebishaji vya skrini ya kugusa. Havipaswi kuhitajika kamwe kwa programu za kawaida."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"fikia vyeti vya DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Huruhusu programu kwa utoaji na matumizi ya vyeti vya DRM. Havifahi kuhitajika kwa ajili ya 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="policylab_watchLogin" msgid="914130646942199503">"Kuhesabu idadi ya mara ambazo skrini inajaribu kufunguliwa"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Inaruhusu programu kufikia hifadhi salama ya ufunguo wa ulinzi."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Dhibiti uonyeshaji na ufichaji wa kilinda-funguo"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Huruhusu programu kudhibiti kilinda-funguo."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Sikiliza mabadiliko ya hali ya kuaminiwa."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Huruhusu programu kusikiliza mabadiliko katika hali ya kuaminiwa."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Funga kwenye huduma ya dalali wa kuaminiwa"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Huruhusu programu kufungamanisha kwenye huduma ya dalali wa kuaminiwa."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Ingiliana na sasisho na mfumo wa kurejesha"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Huruhusu programu kuingiliana na mfumo wa kurejesha na sasisho la mfumo."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Gusa mara mbili kwa udhibiti cha kuza"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Mandhari"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Badilisha mandhari"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Kisikilizi cha arifa"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN imewezeshwa"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN imeamilishwa na <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Gusa ili kudhibiti mtandao."</string>
diff --git a/core/res/res/values-television/themes.xml b/core/res/res/values-television/themes.xml
new file mode 100644
index 0000000..6e17cdd3
--- /dev/null
+++ b/core/res/res/values-television/themes.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <style name="Theme.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
+    <style name="Theme.Dialog.AppError" parent="Theme.Leanback.Dialog.AppError" />
+    <style name="Theme.Holo.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
+    <style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
+    <style name="Theme.Quantum.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
+    <style name="Theme.Quantum.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
+</resources>
diff --git a/core/res/res/values-television/themes_device_defaults.xml b/core/res/res/values-television/themes_device_defaults.xml
new file mode 100644
index 0000000..e01caa3
--- /dev/null
+++ b/core/res/res/values-television/themes_device_defaults.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.
+-->
+<resources>
+    <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
+    <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
+</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index ded9706..c1f1c9b 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"ซิงค์"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"มีการลบ <xliff:g id="CONTENT_TYPE">%s</xliff:g> มากเกินไป"</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"ที่จัดเก็บข้อมูลของแท็บเล็ตเต็ม ลบไฟล์บางไฟล์เพื่อเพิ่มพื้นที่ว่าง"</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"ที่เก็บข้อมูลนาฬิกาเต็ม โปรดลบไฟล์บางไฟล์เพื่อเพิ่มพื้นที่ว่าง"</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"ที่เก็บข้อมูลโทรศัพท์เต็ม ลบบางไฟล์เพื่อเพิ่มที่ว่าง"</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"เครือข่ายอาจได้รับการตรวจสอบ"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"โดยบุคคลที่สามที่ไม่รู้จัก"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"เปิดเสียง"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"กำลังปิดระบบ..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"แท็บเล็ตของคุณจะปิดการทำงาน"</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"นาฬิกาจะปิดการทำงาน"</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"โทรศัพท์ของคุณจะปิดเครื่อง"</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"คุณต้องการปิดการทำงานหรือไม่"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"รีบูตเข้าสู่โหมดปลอดภัย"</string>
@@ -164,16 +162,15 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"ตัวเลือกโทรศัพท์"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"ล็อกหน้าจอ"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"ปิดเครื่อง"</string>
-    <string name="global_action_bug_report" msgid="7934010578922304799">"รายงานข้อบกพร่อง"</string>
-    <string name="bugreport_title" msgid="2667494803742548533">"ใช้รายงานข้อบกพร่อง"</string>
-    <string name="bugreport_message" msgid="398447048750350456">"การดำเนินการนี้จะรวบรวมข้อมูลเกี่ยวกับสถานะปัจจุบันของอุปกรณ์ของคุณ โดยจะส่งไปในรูปแบบข้อความอีเมล อาจใช้เวลาสักครู่ตั้งแต่เริ่มการสร้างรายงานข้อบกพร่องจนกระทั่งเสร็จสมบูรณ์ โปรดอดทนรอ"</string>
+    <string name="global_action_bug_report" msgid="7934010578922304799">"รายงานบั๊ก"</string>
+    <string name="bugreport_title" msgid="2667494803742548533">"ใช้รายงานบั๊ก"</string>
+    <string name="bugreport_message" msgid="398447048750350456">"การดำเนินการนี้จะรวบรวมข้อมูลเกี่ยวกับสถานะปัจจุบันของอุปกรณ์ของคุณ โดยจะส่งไปในรูปแบบข้อความอีเมล อาจใช้เวลาสักครู่ตั้งแต่เริ่มการสร้างรายงานบั๊กจนกระทั่งเสร็จสมบูรณ์ โปรดอดทนรอ"</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"โหมดปิดเสียง"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"ปิดเสียงไว้"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"เปิดเสียงแล้ว"</string>
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"โหมดใช้งานบนเครื่องบิน"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"โหมดปลอดภัย"</string>
     <string name="android_system_label" msgid="6577375335728551336">"ระบบ Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"ถอนการติดตั้งทางลัด"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"อนุญาตให้แอปพลิเคชันลบทางลัดหน้าจอหลักโดยไม่ต้องให้ผู้ใช้จัดการ"</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"จัดเส้นทางการโทรออกใหม่"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"อนุญาตให้แอปดูหมายเลขที่โทรในระหว่างการโทรออกโดยสามารถเลือกเปลี่ยนเส้นทางการโทรไปยังหมายเลขอื่นหรือยกเลิกการโทรไปเลยได้"</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"อนุญาตให้แอปพลิเคชันประมวลผลการโทรออกและเปลี่ยนแปลงหมายเลขที่จะโทรไป การอนุญาตนี้จะทำให้แอปพลิเคชันสามารถตรวจสอบ เปลี่ยนเส้นทาง หรือกีดขวางไม่ให้โทรออกได้"</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"รับข้อความ (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"อนุญาตให้แอปพลิเคชันรับและประมวลผลข้อความ SMS ซึ่งหมายความว่าแอปพลิเคชันจะสามารถตรวจสอบหรือลบข้อความที่ส่งมายังอุปกรณ์ของคุณได้โดยไม่ต้องแสดงให้คุณเห็น"</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"รับข้อความ (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"อนุญาตให้แอปพลิเคชันดึงเนื้อหาของหน้าต่างที่ใช้งานอยู่ แอปพลิเคชันที่เป็นอันตรายอาจดึงเนื้อหาจากหน้าต่างทั้งหมดและตรวจสอบข้อความทั้งหมดยกเว้นรหัสผ่าน"</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"เปิดใช้งานการเข้าถึงชั่วคราว"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"ช่วยให้แอปพลิเคชันสามารถเปิดใช้งานการเข้าถึงบนอุปกรณ์เป็นการชั่วคราว แอปพลิเคชันที่เป็นอันตรายอาจเปิดใช้งานการเข้าถึงโดยไม่ได้รับความยินยอมจากผู้ใช้"</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"เรียกโทเค็นหน้าต่าง"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"อนุญาตให้แอปพลิเคชันเรียกโทเค็นหน้าต่าง แอปที่เป็นอันตรายอาจทำการโต้ตอบที่ไม่ได้รับอนุญาตกับหน้าต่างแอปพลิเคชันโดยปลอมแปลงเป็นระบบ"</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"เรียกสถิติเฟรม"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"อนุญาตให้แอปพลิเคชันเก็บสถิติเฟรม แอปที่เป็นอันตรายอาจดูสถิติเฟรมของหน้าต่างจากแอปอื่น"</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"เรียกข้อมูลหน้าต่าง"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"อนุญาตให้แอปพลิเคชันดึงข้อมูลเกี่ยวกับหน้าต่างจากเครื่องมือจัดการหน้าต่าง แอปพลิเคชันที่เป็นอันตรายอาจดึงข้อมูลที่มีไว้เพื่อการใช้ของระบบภายใน"</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"กรองกิจกรรม"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"อนุญาตให้แอปพลิเคชันลงทะเบียนตัวกรองข้อมูลซึ่งจะกรองสตรีมกิจกรรมทั้งหมดของผู้ใช้ก่อนที่จะทำการเผยแพร่ออกไป แอปพลิเคชันที่เป็นอันตรายอาจควบคุม UI ของระบบโดยไม่ต้องให้ผู้ใช้จัดการ"</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"ขยายการแสดงผล"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"อนุญาตให้แอปพลิเคชันขยายเนื้อหาที่แสดงผล แอปพลิเคชันที่เป็นอันตรายอาจแปลงเนื้อหาที่แสดงในลักษณะที่ทำให้ไม่สามารถใช้อุปกรณ์ได้"</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"ปิดการทำงานบางส่วน"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"กำหนดให้ตัวจัดการกิจกรรมอยู่ในสถานะปิดระบบ โดยไม่ได้ปิดระบบอย่างสมบูรณ์"</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"ป้องกันการเปลี่ยนแอปพลิเคชัน"</string>
@@ -332,14 +329,12 @@
     <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"ช่วยให้เจ้าของสามารถดึงข้อมูลส่วนตัวเกี่ยวกับแอปพลิเคชันปัจจุบันในส่วนหน้าของหน้าจอ"</string>
     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"ตรวจสอบและควบคุมแอปพลิเคชันทั้งหมดที่เปิดใช้งาน"</string>
     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"อนุญาตให้แอปพลิเคชันตรวจสอบและควบคุมวิธีการที่ระบบเปิดกิจกรรมต่างๆ แอปพลิเคชันที่เป็นอันตรายอาจทำอันตรายแก่ระบบได้อย่างสิ้นเชิง การอนุญาตนี้จำเป็นสำหรับการพัฒนาเท่านั้น ไม่ใช้สำหรับแอปพลิเคชันทั่วไปโดยเด็ดขาด"</string>
-    <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"ส่งการกระจายข้อมูลว่ามีการนำแพ็กเกจออก"</string>
-    <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"อนุญาตให้แอปพลิเคชันกระจายข้อมูลการแจ้งเตือนว่าแพ็กเกจของแอปพลิเคชันหนึ่งๆ ได้ถูกนำออกไปแล้ว แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ยุติแอปพลิเคชันอื่นๆ ที่กำลังทำงานอยู่"</string>
+    <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"ส่งการกระจายข้อมูลว่ามีการนำแพคเกจออก"</string>
+    <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"อนุญาตให้แอปพลิเคชันกระจายข้อมูลการแจ้งเตือนว่าแพคเกจของแอปพลิเคชันหนึ่งๆ ได้ถูกนำออกไปแล้ว แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ยุติแอปพลิเคชันอื่นๆ ที่กำลังทำงานอยู่"</string>
     <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"ส่งการกระจายข้อมูลว่าได้รับ SMS"</string>
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"อนุญาตให้แอปพลิเคชันกระจายข้อมูลการแจ้งเตือนว่าได้รับข้อความ SMS แล้ว แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ปลอมข้อความ SMS ที่เข้ามา"</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"ส่งการกระจายข้อมูลว่าได้รับ WAP-PUSH"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"อนุญาตให้แอปพลิเคชันกระจายข้อมูลการแจ้งเตือนว่าได้รับข้อความ WAP PUSH แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ปลอมการแจ้งรับข้อความ MMS หรือแอบเปลี่ยนเนื้อหาในหน้าเว็บโดยใช้ตัวแปรที่เป็นอันตราย"</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ส่งเผยแพร่การให้คะแนนเครือข่าย"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"อนุญาตให้แอปนี้เผยแพร่ข้อมูลการแจ้งเตือนว่าเครือข่ายจะต้องผ่านการให้คะแนน ไม่จำเป็นสำหรับแอปทั่วไป"</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"จำกัดจำนวนกระบวนการที่กำลังทำงาน"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"อนุญาตให้แอปพลิเคชันควบคุมจำนวนสูงสุดของกระบวนการที่จะเรียกใช้ ไม่จำเป็นต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"บังคับปิดแอปพลิเคชันในพื้นหลัง"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"อนุญาตให้เจ้าของเชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของบริการ VPN ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"เชื่อมโยงกับวอลเปเปอร์"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของวอลเปเปอร์ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ผูกกับจอแสดงผลระยะไกล"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"อนุญาตให้เจ้าของเชื่อมโยงกับส่วนติดต่อระดับสูงสุดของอินพุตทีวี ซึ่งแอปทั่วไปไม่จำเป็นต้องใช้"</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"เพิ่มหรือลบผู้ดูแลระบบอุปกรณ์"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"อนุญาตให้เจ้าของเพิ่มหรือลบผู้ดูแลระบบอุปกรณ์ที่ใช้งาน ไม่ควรต้องใช้สำหรับแอปปกติ"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"เปลี่ยนการวางแนวหน้าจอ"</string>
@@ -415,7 +402,7 @@
     <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"อนุญาตให้แอปพลิเคชันทำให้ส่วนหนึ่งของตัวเองคงอยู่ถาวรในหน่วยความจำ ซึ่งจะจำกัดพื้นที่หน่วยความจำที่ใช้งานได้ของแอปพลิเคชันอื่นๆ และทำให้แท็บเล็ตทำงานช้าลง"</string>
     <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"อนุญาตให้แอปพลิเคชันทำให้ส่วนหนึ่งของตัวเองคงอยู่ถาวรในหน่วยความจำ ซึ่งจะจำกัดพื้นที่หน่วยความจำที่ใช้งานได้ของแอปพลิเคชันอื่นๆ และทำให้โทรศัพท์ทำงานช้าลง"</string>
     <string name="permlab_deletePackages" msgid="184385129537705938">"ลบแอปพลิเคชัน"</string>
-    <string name="permdesc_deletePackages" msgid="7411480275167205081">"อนุญาตให้แอปพลิเคชันลบแพ็กเกจ Android แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ลบแอปพลิเคชันที่สำคัญ"</string>
+    <string name="permdesc_deletePackages" msgid="7411480275167205081">"อนุญาตให้แอปพลิเคชันลบแพคเกจ Android แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ลบแอปพลิเคชันที่สำคัญ"</string>
     <string name="permlab_clearAppUserData" msgid="274109191845842756">"ลบข้อมูลของแอปพลิเคชันอื่น"</string>
     <string name="permdesc_clearAppUserData" msgid="4625323684125459488">"อนุญาตให้แอปพลิเคชันล้างข้อมูลผู้ใช้"</string>
     <string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"ลบแคชของแอปพลิเคชันอื่น"</string>
@@ -423,7 +410,7 @@
     <string name="permlab_getPackageSize" msgid="7472921768357981986">"วัดพื้นที่เก็บข้อมูลของแอปพลิเคชัน"</string>
     <string name="permdesc_getPackageSize" msgid="3921068154420738296">"อนุญาตให้แอปพลิเคชันเรียกดูรหัส ข้อมูล และขนาดแคชของตน"</string>
     <string name="permlab_installPackages" msgid="2199128482820306924">"ติดตั้งแอปพลิเคชันโดยตรง"</string>
-    <string name="permdesc_installPackages" msgid="5628530972548071284">"อนุญาตให้แอปพลิเคชันติดตั้งแพ็กเกจ Android ใหม่หรือที่อัปเดต แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ในการเพิ่มแอปพลิเคชันใหม่ๆ ด้วยสิทธิ์ที่สูงนี้ได้ตามต้องการ"</string>
+    <string name="permdesc_installPackages" msgid="5628530972548071284">"อนุญาตให้แอปพลิเคชันติดตั้งแพคเกจ Android ใหม่หรือที่อัปเดต แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ในการเพิ่มแอปพลิเคชันใหม่ๆ ด้วยสิทธิ์ที่สูงนี้ได้ตามต้องการ"</string>
     <string name="permlab_clearAppCache" msgid="7487279391723526815">"ลบข้อมูลแคชของแอปพลิเคชันทั้งหมด"</string>
     <string name="permdesc_clearAppCache" product="tablet" msgid="8974640871945434565">"อนุญาตให้แอปพลิเคชันสร้างพื้นที่ว่างในที่จัดเก็บข้อมูลของแท็บเล็ต โดยลบไฟล์ในไดเรกทอรีแคชของแอปพลิเคชันอื่นๆ ซึ่งอาจทำให้แอปพลิเคชันอื่นเริ่มทำงานช้ากว่าเดิมเนื่องจากต้องดึงข้อมูลของตนซ้ำ"</string>
     <string name="permdesc_clearAppCache" product="default" msgid="2459441021956436779">"อนุญาตให้แอปพลิเคชันสร้างพื้นที่ว่างในที่จัดเก็บข้อมูลของโทรศัพท์ โดยลบไฟล์ในไดเรกทอรีแคชของแอปพลิเคชันอื่นๆ ซึ่งอาจทำให้แอปพลิเคชันอื่นเริ่มทำงานช้ากว่าเดิมเนื่องจากต้องดึงข้อมูลของตนซ้ำ"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"อนุญาตให้แอปพลิเคชันใช้ตัวถอดรหัสสื่อใดก็ได้ที่ติดตั้งไว้เพื่อถอดรหัสสำหรับการเล่น"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"จัดการข้อมูลรับรองที่เชื่อถือได้"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"อนุญาตให้แอปติดตั้งและถอนการติดตั้งใบรับรอง CA ในฐานะข้อมูลรับรองที่เชื่อถือได้"</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"เรียกใช้แอปพลิเคชันในระหว่างที่ไม่ได้ใช้งาน"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"สิทธิ์นี้ช่วยให้ระบบแอนดรอยด์สามารถเรียกใช้แอปพลิเคชันในพื้นหลังขณะไม่ได้ใช้งานอุปกรณ์อยู่"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"เชื่อมโยงกับบริการที่ไม่ได้ใช้งาน"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"สิทธิ์นี้จะทำให้ระบบแอนดรอยด์สามารถเชื่อมโยงกับบริการรายงานเวลาที่ไม่มีการใช้งานของแอปพลิเคชัน"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"อ่าน/เขียนไปยังรีซอร์สที่เป็นเจ้าของโดยกลุ่มวินิจฉัย"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"อนุญาตให้แอปพลิเคชันอ่านและเขียนไปยังทรัพยากรที่เป็นของกลุ่มวินิจฉัย เช่น ไฟล์ใน /dev การทำเช่นนี้อาจส่งผลต่อความเสถียรและความปลอดภัยของระบบ และควรใช้สำหรับการวินิจฉัยเกี่ยวกับฮาร์ดแวร์โดยเฉพาะที่ทำโดยผู้ผลิตหรือผู้ให้บริการเท่านั้น"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"เปิดหรือปิดใช้งานคอมโพเนนต์ของแอปพลิเคชัน"</string>
@@ -460,14 +447,14 @@
     <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"อนุญาตให้แอปพลิเคชันส่งการกระจายข้อมูลที่ติดหนึบ ซึ่งจะยังคงอยู่หลังจากการกระจายข้อมูลจบไปแล้ว การใช้งานมากเกินไปอาจทำให้แท็บเล็ตทำงานช้าลงหรือไม่เสถียรโดยการใช้หน่วยความจำมากเกินไป"</string>
     <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"อนุญาตให้แอปพลิเคชันส่งการกระจายข้อมูลที่ติดหนึบ ซึ่งจะยังคงอยู่หลังจากการกระจายข้อมูลจบไปแล้ว การใช้งานมากเกินไปอาจทำให้โทรศัพท์ทำงานช้าลงหรือไม่เสถียรโดยการใช้หน่วยความจำมากเกินไป"</string>
     <string name="permlab_readContacts" msgid="8348481131899886131">"อ่านผู้ติดต่อของคุณ"</string>
-    <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"อนุญาตให้แอปพลิเคชันอ่านข้อมูลผู้ติดต่อที่จัดเก็บไว้ในแท็บเล็ต ซึ่งรวมถึงความถี่ในการโทร ส่งอีเมล หรือการติดต่อด้วยวิธีอื่นๆ กับบุคคลใดบุคคลหนึ่ง การอนุญาตนี้ทำให้แอปพลิเคชันสามารถบันทึกข้อมูลผู้ติดต่อของคุณ และแอปพลิเคชันที่เป็นอันตรายอาจแชร์ข้อมูลผู้ติดต่อโดยไม่แจ้งให้คุณทราบ"</string>
-    <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"อนุญาตให้แอปพลิเคชันอ่านข้อมูลผู้ติดต่อที่จัดเก็บไว้ในโทรศัพท์ ซึ่งรวมถึงความถี่ในการโทร ส่งอีเมล หรือการติดต่อด้วยวิธีอื่นๆ กับบุคคลใดบุคคลหนึ่ง การอนุญาตนี้ทำให้แอปพลิเคชันสามารถบันทึกข้อมูลผู้ติดต่อของคุณ และแอปพลิเคชันที่เป็นอันตรายอาจแชร์ข้อมูลผู้ติดต่อโดยไม่แจ้งให้คุณทราบ"</string>
+    <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"อนุญาตให้แอปพลิเคชันอ่านข้อมูลผู้ติดต่อที่จัดเก็บไว้ในแท็บเล็ต ซึ่งรวมถึงความถี่ในการโทร ส่งอีเมล หรือการติดต่อด้วยวิธีอื่นๆ กับบุคคลใดบุคคลหนึ่ง การอนุญาตนี้ทำให้แอปพลิเคชันสามารถบันทึกข้อมูลผู้ติดต่อของคุณ และแอปพลิเคชันที่เป็นอันตรายอาจแบ่งปันข้อมูลผู้ติดต่อโดยไม่แจ้งให้คุณทราบ"</string>
+    <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"อนุญาตให้แอปพลิเคชันอ่านข้อมูลผู้ติดต่อที่จัดเก็บไว้ในโทรศัพท์ ซึ่งรวมถึงความถี่ในการโทร ส่งอีเมล หรือการติดต่อด้วยวิธีอื่นๆ กับบุคคลใดบุคคลหนึ่ง การอนุญาตนี้ทำให้แอปพลิเคชันสามารถบันทึกข้อมูลผู้ติดต่อของคุณ และแอปพลิเคชันที่เป็นอันตรายอาจแบ่งปันข้อมูลผู้ติดต่อโดยไม่แจ้งให้คุณทราบ"</string>
     <string name="permlab_writeContacts" msgid="5107492086416793544">"แก้ไขผู้ติดต่อของคุณ"</string>
     <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"อนุญาตให้แอปพลิเคชันเปลี่ยนแปลงข้อมูลผู้ติดต่อที่จัดเก็บไว้ในแท็บเล็ต ซึ่งรวมถึงความถี่ในการโทร ส่งอีเมล หรือการติดต่อด้วยวิธีอื่นๆ กับบุคคลใดบุคคลหนึ่ง การอนุญาตนี้ทำให้แอปพลิเคชันสามารถลบข้อมูลผู้ติดต่อได้"</string>
     <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"อนุญาตให้แอปพลิเคชันเปลี่ยนแปลงข้อมูลผู้ติดต่อที่จัดเก็บไว้ในโทรศัพท์ ซึ่งรวมถึงความถี่ในการโทร ส่งอีเมล หรือการติดต่อด้วยวิธีอื่นๆ กับบุคคลใดบุคคลหนึ่ง การอนุญาตนี้ทำให้แอปพลิเคชันสามารถลบข้อมูลผู้ติดต่อได้"</string>
     <string name="permlab_readCallLog" msgid="3478133184624102739">"อ่านประวัติการโทร"</string>
-    <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"อนุญาตให้แอปพลิเคชันอ่านบันทึกการโทรของแท็บเล็ต ซึ่งรวมถึงข้อมูลเกี่ยวกับการโทรเข้าและโทรออก การอนุญาตนี้ทำให้แอปพลิเคชันสามารถบันทึกข้อมูลบันทึกการโทรของคุณได้ และแอปพลิเคชันที่เป็นอันตรายอาจแชร์ข้อมูลบันทึกการโทรนี้โดยไม่แจ้งให้คุณทราบ"</string>
-    <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"อนุญาตให้แอปพลิเคชันอ่านบันทึกการโทรของโทรศัพท์ ซึ่งรวมถึงข้อมูลเกี่ยวกับการโทรเข้าและโทรออก การอนุญาตนี้ทำให้แอปพลิเคชันสามารถบันทึกข้อมูลบันทึกการโทรของคุณได้ และแอปพลิเคชันที่เป็นอันตรายอาจแชร์ข้อมูลบันทึกการโทรนี้โดยไม่แจ้งให้คุณทราบ"</string>
+    <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"อนุญาตให้แอปพลิเคชันอ่านบันทึกการโทรของแท็บเล็ต ซึ่งรวมถึงข้อมูลเกี่ยวกับการโทรเข้าและโทรออก การอนุญาตนี้ทำให้แอปพลิเคชันสามารถบันทึกข้อมูลบันทึกการโทรของคุณได้ และแอปพลิเคชันที่เป็นอันตรายอาจแบ่งปันข้อมูลบันทึกการโทรนี้โดยไม่แจ้งให้คุณทราบ"</string>
+    <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"อนุญาตให้แอปพลิเคชันอ่านบันทึกการโทรของโทรศัพท์ ซึ่งรวมถึงข้อมูลเกี่ยวกับการโทรเข้าและโทรออก การอนุญาตนี้ทำให้แอปพลิเคชันสามารถบันทึกข้อมูลบันทึกการโทรของคุณได้ และแอปพลิเคชันที่เป็นอันตรายอาจแบ่งปันข้อมูลบันทึกการโทรนี้โดยไม่แจ้งให้คุณทราบ"</string>
     <string name="permlab_writeCallLog" msgid="8552045664743499354">"เขียนประวัติการโทร"</string>
     <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"อนุญาตให้แอปแก้ไขประวัติการโทรจากแท็บเล็ตของคุณ รวมถึงข้อมูลเกี่ยวกับสายเรียกเข้าและการโทรออก แอปที่เป็นอันตรายอาจใช้สิ่งนี้เพื่อลบหรือแก้ไขประวัติการโทรของคุณ"</string>
     <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"อนุญาตให้แอปแก้ไขประวัติการโทรจากโทรศัพท์ของคุณ รวมถึงข้อมูลเกี่ยวกับสายเรียกเข้าและการโทรออก แอปที่เป็นอันตรายอาจใช้สิ่งนี้เพื่อลบหรือแก้ไขประวัติการโทรของคุณ"</string>
@@ -475,15 +462,13 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"อนุญาตให้แอปพลิเคชันอ่านข้อมูลส่วนตัวในโปรไฟล์ที่จัดเก็บไว้ในอุปกรณ์ของคุณ เช่น ชื่อและข้อมูลติดต่อของคุณ ซึ่งหมายความว่าแอปพลิเคชันสามารถระบุตัวคุณและอาจส่งข้อมูลโปรไฟล์ของคุณให้ผู้อื่น"</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"แก้ไขบัตรผู้ติดต่อของคุณเอง"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"อนุญาตให้แอปพลิเคชันเปลี่ยนแปลงหรือเพิ่มข้อมูลโปรไฟล์ส่วนตัวที่จัดเก็บไว้บนอุปกรณ์ของคุณ เช่น ชื่อและข้อมูลติดต่อ ซึ่งหมายความว่าแอปพลิเคชันจะสามารถระบุตัวตนของคุณและส่งข้อมูลโปรไฟล์ของคุณให้แก่ผู้อื่นได้"</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"เซ็นเซอร์ร่างกาย (เช่น วัดอัตราการเต้นของหัวใจ)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"ช่วยให้แอปสามารถเข้าถึงข้อมูลจากเซ็นเซอร์ที่คุณใช้เพื่อวัดความเป็นไปภายในร่างกายของคุณ เช่น อัตราการเต้นของหัวใจ"</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"อ่านสตรีมเครือข่ายสังคม"</string>
-    <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"อนุญาตให้แอปพลิเคชันเข้าถึงและซิงค์การอัปเดตทางสังคมจากคุณและเพื่อน โปรดแชร์ข้อมูลอย่างระมัดระวังเนื่องจากการอนุญาตนี้ทำให้แอปพลิเคชันสามารถอ่านการติดต่อระหว่างคุณและเพื่อนในเครือข่ายสังคมได้ ไม่ว่าจะมีการรักษาข้อมูลที่เป็นความลับแบบใดก็ตาม หมายเหตุ: การอนุญาตนี้อาจไม่สามารถใช้งานได้กับทุกเครือข่ายสังคม"</string>
+    <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="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"อนุญาตให้แอปพลิเคชันแสดงการอัปเดตทางสังคมจากเพื่อนของคุณ โปรดแบ่งปันข้อมูลอย่างระมัดระวังเนื่องจากการอนุญาตนี้ทำให้แอปพลิเคชันสามารถสร้างข้อความที่ดูเหมือนมาจากเพื่อนได้ หมายเหตุ: การอนุญาตนี้อาจไม่สามารถใช้ได้กับทุกเครือข่ายสังคม"</string>
     <string name="permlab_readCalendar" msgid="5972727560257612398">"อ่านกิจกรรมบนปฏิทินรวมถึงข้อมูลที่เป็นความลับ"</string>
-    <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"อนุญาตให้แอปพลิเคชันอ่านกิจกรรมในปฏิทินทั้งหมดที่จัดเก็บไว้ในแท็บเล็ตของคุณ ซึ่งรวมถึงกิจกรรมของเพื่อนหรือเพื่อนร่วมงานด้วย ซึ่งอาจทำให้แอปพลิเคชันสามารถแชร์หรือบันทึกข้อมูลในปฏิทินของคุณได้ไม่ว่าจะมีการรักษาข้อมูลที่เป็นความลับหรือหรือข้อมูลที่อ่อนไหวแบบใดก็ตาม"</string>
-    <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"อนุญาตให้แอปพลิเคชันอ่านกิจกรรมในปฏิทินทั้งหมดที่จัดเก็บไว้ในโทรศัพท์ของคุณ ซึ่งรวมถึงกิจกรรมของเพื่อนหรือเพื่อนร่วมงานด้วย ซึ่งอาจทำให้แอปพลิเคชันสามารถแชร์หรือบันทึกข้อมูลในปฏิทินของคุณได้ไม่ว่าจะมีการรักษาข้อมูลที่เป็นความลับหรือหรือข้อมูลที่อ่อนไหวแบบใดก็ตาม"</string>
+    <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"อนุญาตให้แอปพลิเคชันอ่านกิจกรรมในปฏิทินทั้งหมดที่จัดเก็บไว้ในแท็บเล็ตของคุณ ซึ่งรวมถึงกิจกรรมของเพื่อนหรือเพื่อนร่วมงานด้วย ซึ่งอาจทำให้แอปพลิเคชันสามารถแบ่งปันหรือบันทึกข้อมูลในปฏิทินของคุณได้ไม่ว่าจะมีการรักษาข้อมูลที่เป็นความลับหรือหรือข้อมูลที่อ่อนไหวแบบใดก็ตาม"</string>
+    <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"อนุญาตให้แอปพลิเคชันอ่านกิจกรรมในปฏิทินทั้งหมดที่จัดเก็บไว้ในโทรศัพท์ของคุณ ซึ่งรวมถึงกิจกรรมของเพื่อนหรือเพื่อนร่วมงานด้วย ซึ่งอาจทำให้แอปพลิเคชันสามารถแบ่งปันหรือบันทึกข้อมูลในปฏิทินของคุณได้ไม่ว่าจะมีการรักษาข้อมูลที่เป็นความลับหรือหรือข้อมูลที่อ่อนไหวแบบใดก็ตาม"</string>
     <string name="permlab_writeCalendar" msgid="8438874755193825647">"เพิ่มหรือแก้ไขกิจกรรมบนปฏิทินและส่งอีเมลให้ผู้เข้าร่วมโดยที่เจ้าของไม่ทราบ"</string>
     <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"อนุญาตให้แอปพลิเคชันเพิ่ม ลบ เปลี่ยนกิจกรรมที่คุณสามารถเปลี่ยนแปลงในแท็บเล็ตได้ รวมถึงกิจกรรมของเพื่อนหรือเพื่อนร่วมงานด้วย การอนุญาตนี้อาจทำให้แอปพลิเคชันสามารถส่งข้อความที่มาจากเจ้าของปฏิทิน หรือเปลี่ยนแปลงกิจกรรมโดยที่เจ้าของไม่ทราบ"</string>
     <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"อนุญาตให้แอปพลิเคชันเพิ่ม ลบ เปลี่ยนกิจกรรมที่คุณสามารถเปลี่ยนแปลงในโทรศัพท์ได้ รวมถึงกิจกรรมของเพื่อนหรือเพื่อนร่วมงานด้วย การอนุญาตนี้อาจทำให้แอปพลิเคชันสามารถส่งข้อความที่มาจากเจ้าของปฏิทิน หรือเปลี่ยนแปลงกิจกรรมโดยที่เจ้าของไม่ทราบ"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"อนุญาตให้แอปพลิชันควบคุมคุณลักษณะโทรศัพท์ของอุปกรณ์ แอปพลิเคชันที่ได้รับอนุญาตจะสามารถสลับเครือข่าย เปิดและปิดวิทยุในโทรศัพท์ และคุณลักษณะอื่นที่คล้ายกันนี้ได้โดยไม่ต้องแจ้งให้คุณทราบ"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"อ่านสถานะและข้อมูลระบุตัวตนของโทรศัพท์"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"อนุญาตให้แอปพลิเคชันเข้าถึงคุณลักษณะโทรศัพท์ของอุปกรณ์ การอนุญาตนี้ทำให้แอปพลิเคชันสามารถตรวจสอบหมายเลขโทรศัพท์และรหัสอุปกรณ์ ตรวจสอบว่ามีการโทรที่ทำงานอยู่หรือไม่ และตรวจสอบหมายเลขระยะไกลที่เชื่อมต่อด้วยการโทร"</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"อ่านสถานะที่แม่นยำของโทรศัพท์"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"ช่วยให้แอปสามารถเข้าถึงสถานะที่แม่นยำของโทรศัพท์ สิทธิ์นี้ช่วยให้แอปสามารถทราบถึงสถานะการโทรที่แท้จริงว่ากำลังมีการโทรอยู่หรือการโทรในพื้นหลัง การโทรล้มเหลว สถานะการเชื่อมต่อข้อมูลที่แม่นยำและการเชื่อมต่อข้อมูลล้มเหลว"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ป้องกันไม่ให้แท็บเล็ตเข้าสู่โหมดสลีป"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ป้องกันไม่ให้โทรศัพท์เข้าโหมดสลีป"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"อนุญาตให้แอปพลิเคชันป้องกันไม่ให้แท็บเล็ตเข้าสู่โหมดสลีป"</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"เปลี่ยนสถานะของ WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"อนุญาตให้แอปพลิเคชันเชื่อมต่อและยกเลิกการเชื่อมต่อแท็บเล็ตกับเครือข่าย WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"อนุญาตให้แอปพลิเคชันเชื่อมต่อและยกเลิกการเชื่อมต่อโทรศัพท์กับเครือข่าย WiMAX"</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ให้คะแนนเครือข่าย"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"อนุญาตให้แอปนี้จัดลำดับเครือข่าย ซึ่งมีผลต่อการเลือกใช้เครือข่ายของแท็บเล็ต"</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"อนุญาตให้แอปนี้จัดอันดับเครือข่ายและมีผลต่อการเลือกใช้เครือข่ายของโทรศัพท์"</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"จับคู่กับอุปกรณ์บลูทูธ"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"อนุญาตให้แอปพลิเคชันดูการกำหนดค่าบลูทูธของแท็บเล็ต ตลอดจนเชื่อมต่อและยอมรับการเชื่อมต่อกับอุปกรณ์ที่จับคู่ไว้"</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"อนุญาตให้แอปพลิเคชันดูการกำหนดค่าบลูทูธของโทรศัพท์ ตลอดจนเชื่อมต่อและยอมรับการเชื่อมต่อกับอุปกรณ์ที่จับคู่ไว้"</string>
@@ -703,18 +683,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"ทำให้แอปสามารถเรียกดู ตรวจสอบ และล้างการแจ้งเตือนได้ ซึ่งรวมถึงการแจ้งเตือนที่โพสต์โดยแอปอื่นๆ ด้วย"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"เชื่อมโยงกับบริการตัวฟังการแจ้งเตือน"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"อนุญาตให้เจ้าของเชื่อมโยงกับอินเตอร์เฟซระดับสูงสุดของบริการตัวฟังการแจ้งเตือน ซึ่งไม่มีความจำเป็นสำหรับแอปธรรมดา"</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"เรียกใช้แอปการกำหนดค่าของผู้ให้บริการ"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"อนุญาตให้ผู้ใช้สามารถเรียกใช้แอปการกำหนดค่าของผู้ให้บริการ ซึ่งแอปทั่วไปไม่จำเป็นต้องใช้"</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ฟังข้อสังเกตเกี่ยวกับสภาวะของเครือข่าย"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"อนุญาตให้แอปพลิเคชันฟังข้อสังเกตเกี่ยวกับสภาวะของเครือข่าย ไม่จำเป็นสำหรับแอปปกติ"</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"เปลี่ยนการเทียบมาตรฐานอุปกรณ์อินพุต"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"อนุญาตให้แอปสามารถปรับพารามิเตอร์การเทียบมาตรฐานของหน้าจอสัมผัส ไม่ควรใช้สำหรับแอปทั่วไป"</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"เข้าถึงใบรับรอง DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"ช่วยให้แอปพลิเคชันสามารถจัดสรรและใช้ใบรับรอง DRM ได้ ไม่จำเป็นสำหรับแอปปกติทั่วไป"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"ตั้งค่ากฎรหัสผ่าน"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"ควบคุมความยาวและอักขระที่อนุญาตให้ใช้ในรหัสผ่านการปลดล็อกหน้าจอ"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"ตรวจสอบความพยายามในการปลดล็อกหน้าจอ"</string>
@@ -953,7 +925,7 @@
     <string name="hour_cap_ampm" msgid="2083465992940444366">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
     <string name="factorytest_failed" msgid="5410270329114212041">"การทดสอบจากโรงงานล้มเหลว"</string>
     <string name="factorytest_not_system" msgid="4435201656767276723">"การทำงาน FACTORY_TEST ได้รับการสนับสนุนเฉพาะสำหรับแพ็คเก็จที่ติดตั้งใน /system/app เท่านั้น"</string>
-    <string name="factorytest_no_action" msgid="872991874799998561">"ไม่พบแพ็กเกจที่มีการทำงาน FACTORY_TEST"</string>
+    <string name="factorytest_no_action" msgid="872991874799998561">"ไม่พบแพคเกจที่มีการทำงาน FACTORY_TEST"</string>
     <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>
@@ -992,10 +964,10 @@
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"อนุญาตให้แอปพลิเคชันเพิ่มข้อความลงในกล่องข้อความเสียงของคุณ"</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"แก้ไขการอนุญาตเกี่ยวกับการระบุตำแหน่งทางภูมิศาสตร์ของเบราว์เซอร์"</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>
-    <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"อนุญาตให้ผู้ใช้ส่งคำขอให้มีการยืนยันแพ็กเกจ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
+    <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"ยืนยันแพคเกจ"</string>
+    <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"อนุญาตให้แอปพลิเคชันยืนยันว่าแพคเกจสามารถติดตั้งได้หรือไม่"</string>
+    <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"เชื่อมโยงกับการยืนยันแพคเกจ"</string>
+    <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"อนุญาตให้ผู้ใช้ส่งคำขอให้มีการยืนยันแพคเกจ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"เข้าถึงพอร์ตอนุกรม"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"อนุญาตให้ผู้ถือสามารถเข้าถึงพอร์ตอนุกรมโดยใช้ SerialManager API"</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"เข้าถึงผู้ให้บริการเนื้อหาจากภายนอก"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"อนุญาตให้แอปพลิเคชันเข้าถึงพื้นที่จัดเก็บที่รักษาความปลอดภัยด้วยคีย์การ์ด"</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>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ผูกกับบริการของตัวแทนที่เชื่อถือได้"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"อนุญาตให้แอปพลิเคชันผูกกับบริการของตัวแทนที่เชื่อถือได้"</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"โต้ตอบกับการอัปเดตและระบบการกู้คืน"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"ช่วยให้แอปพลิเคชันสามารถโต้ตอบกับระบบการกู้คืนและการอัปเดตระบบ"</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"แตะสองครั้งเพื่อควบคุมการซูม"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"วอลเปเปอร์"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"เปลี่ยนวอลเปเปอร์"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"ตัวฟังการแจ้งเตือน"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN เปิดใช้งานแล้ว"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"เปิดใช้งาน VPN โดย <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"แตะเพื่อจัดการเครือข่าย"</string>
@@ -1395,7 +1361,7 @@
     <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"แตะเพื่อออกจากโหมดรถยนต์"</string>
     <string name="tethered_notification_title" msgid="3146694234398202601">"การปล่อยสัญญาณหรือฮอตสปอตทำงานอยู่"</string>
     <string name="tethered_notification_message" msgid="6857031760103062982">"แตะเพื่อตั้งค่า"</string>
-    <string name="back_button_label" msgid="2300470004503343439">"กลับ"</string>
+    <string name="back_button_label" msgid="2300470004503343439">"ย้อนกลับ"</string>
     <string name="next_button_label" msgid="1080555104677992408">"ถัดไป"</string>
     <string name="skip_button_label" msgid="1275362299471631819">"ข้าม"</string>
     <string name="throttle_warning_notification_title" msgid="4890894267454867276">"การใช้งานข้อมูลมือถือในระดับสูง"</string>
@@ -1422,7 +1388,7 @@
     <string name="media_shared" product="nosdcard" msgid="5830814349250834225">"ขณะนี้ที่เก็บข้อมูล USB ถูกใช้งานอยู่โดยคอมพิวเตอร์"</string>
     <string name="media_shared" product="default" msgid="5706130568133540435">"ขณะนี้การ์ด SD มีการใช้งานอยู่โดยคอมพิวเตอร์"</string>
     <string name="media_unknown_state" msgid="729192782197290385">"สื่อภายนอกอยู่ในสถานะที่ไม่รู้จัก"</string>
-    <string name="share" msgid="1778686618230011964">"แชร์"</string>
+    <string name="share" msgid="1778686618230011964">"แบ่งปัน"</string>
     <string name="find" msgid="4808270900322985960">"ค้นหา"</string>
     <string name="websearch" msgid="4337157977400211589">"ค้นเว็บ"</string>
     <string name="find_next" msgid="5742124618942193978">"ค้นหาถัดไป"</string>
@@ -1465,8 +1431,8 @@
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"ป้อน"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"เลือกแอปพลิเคชัน"</string>
     <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"ไม่สามารถเปิด <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
-    <string name="shareactionprovider_share_with" msgid="806688056141131819">"แชร์กับ"</string>
-    <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"แชร์ด้วย <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+    <string name="shareactionprovider_share_with" msgid="806688056141131819">"แบ่งปันกับ"</string>
+    <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"แบ่งปันด้วย <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"ที่จับสำหรับเลื่อน แตะค้างไว้"</string>
     <string name="description_target_unlock_tablet" msgid="3833195335629795055">"กวาดเพื่อปลดล็อก"</string>
     <string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"เสียบชุดหูฟังเพื่อฟังเสียงเมื่อพิมพ์รหัสผ่าน"</string>
@@ -1510,7 +1476,7 @@
     <string name="sha1_fingerprint" msgid="7930330235269404581">"ลายนิ้วมือ SHA-1"</string>
     <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"ดูทั้งหมด"</string>
     <string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"เลือกกิจกรรม"</string>
-    <string name="share_action_provider_share_with" msgid="5247684435979149216">"แชร์กับ"</string>
+    <string name="share_action_provider_share_with" msgid="5247684435979149216">"แบ่งปันกับ"</string>
     <string name="list_delimeter" msgid="3975117572185494152">", "</string>
     <string name="sending" msgid="3245653681008218030">"กำลังส่ง…"</string>
     <string name="launchBrowserDefault" msgid="2057951947297614725">"เปิดเบราว์เซอร์หรือไม่"</string>
@@ -1697,7 +1663,7 @@
     <item quantity="other" msgid="4730868920742952817">"ลองอีกใน <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_mode_confirmation" msgid="7227416894979047467">"กวาดนิ้วจากบนลงล่างเพื่อออกจากโหมดเต็มหน้าจอ"</string>
     <string name="done_label" msgid="2093726099505892398">"เสร็จสิ้น"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"ตัวเลื่อนหมุนระบุชั่วโมง"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"ตัวเลื่อนหมุนระบุนาที"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 4d2d0db..4196a82 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"I-sync"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Masyadong maraming pagtanggal ng <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Puno na ang storage ng tablet. Magtanggal ng ilang file upang magbakante ng espasyo."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Puno na ang storage ng relo. Magtanggal ng ilang file upang magbakante ng espasyo."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Puno na ang storage ng telepono. Magtanggal ng ilang file upang magbakante ng espasyo."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Maaaring sinusubaybayan ang network"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Ng isang di-kilalang third party"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"I-on ang ringer"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Nagsa-shut down…"</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Mag-shut down ang iyong tablet."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Magsa-shut down ang iyong relo."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Magsa-shut down ang iyong telepono."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Nais mo bang mag-shut down?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Mag-reboot sa safe mode"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Airplane mode"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"i-uninstall ang mga shortcut"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Pinapayagan ang application na alisin ang mga shortcut ng Homescreen nang walang panghihimasok ng user."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"baguhin ang ruta ng mga papalabas na tawag"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Pinapayagan ang app na makita ang numerong idina-dial sa isang papalabas na tawag na may opsyon na i-redirect ang tawag sa ibang numero o itigil ang tawag nang tuluyan."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Pinapayagan ang app na magproseso ng mga papalabas na tawag at baguhin ang numerong ida-dial. Pinapayagan ng pahintulot na ito ang app na sumubaybay, mag-redirect, o pumigil ng mga papalabas na tawag."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"tumanggap ng mga text message (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Pinapayagan ang app na tumanggap at magproseso ng mga mensaheng SMS. Nangangahulugan ito na maaaring sumubaybay o magtanggal ang app ng mga mensaheng ipinapadala sa iyong device nang hindi ipinapakita ang mga ito sa iyo."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"tumanggap ng mga text message (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Pinapayagan ang app na bawiin ang nilalaman ng aktibong window. Maaaring bawiin ng nakakahamak na apps ang kabuuang nilalaman ng window at suriin ang lahat ng teksto nito maliban sa mga password."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"pansamantalang paganahin ang accessibility"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Nagbibigay-daan sa isang application na pansamantalang paganahin ang accessibility sa device. Maaaring paganahin ng nakakahamak na apps ang accessibility nang walang pahintulot ng user."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"kunin ang token ng window"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Nagbibigay-daan sa isang application upang makuha ang token ng window. Maaaring magsagawa ng hindi pinapahintulutang pakikipag-ugnayan ang mga nakakahamak na app sa window ng application nang nagkukunwari bilang ang system."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"kunin ang mga istatistika ng frame"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Nagbibigay-daan sa isang application upang mangolekta ng mga istatistika ng frame. Maaaring mag-obserba ng mga window mula sa ibang mga app ang mga nakakahamak na app."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"kunin ang impormasyon ng window"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Pinapayagan ang application na kumuha ng impormasyon tungkol sa mga window mula sa tagapamahala ng window. Maaaring kumuha ang mga nakakahamak na app ng impormasyong nilayon para sa panloob na paggamit ng system."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"i-filter ang mga kaganapan"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Pinapayagan ang isang application na magrehistro ng filter ng input na nagpi-filter sa stream ng lahat ng kaganapan ng user bago maipadala ang mga iyon. Maaaring kontrolin ng nakakahamak na app ang system UI nang hindi nakikialam ang user."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"i-magnify ang display"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Pinapayagan ang isang application na i-magnify ang nilalaman ng isang display. Maaaring ibahin ng nakakahamak na apps ang nilalaman ng display sa paraang nagre-render sa device na hindi kapaki-pakinabang."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"bahagyang pag-shutdown"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Inilalagay ang tagapamahala ng aktibidad sa katayuan ng pag-shutdown. Hindi nagsasagawa ng kumpletong pag-shutdown."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"pigilan ang mga paglipat ng app"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Pinapayagan ang app na mag-broadcast ng isang notification na natanggap ang isang mensaheng SMS. Maaari itong gamitin ng nakakahamak na apps upang dayain ang papasok na mga mensaheng SMS."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"ipadala ang WAP-PUSH-natanggap na pag-broadcast"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Pinapayagan ang app na mag-broadcast ng isang notification na natanggap ang isang mensaheng WAP PUSH. Maaari itong gamitin ng nakakahamak na apps upang dayain ang pagtanggap ng mensaheng MMS o upang tahimik na palitan ang nilalaman ng anumang webpage ng mga nakakahamak na variant."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"magpadala ng broadcast ng mga network ng score"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Nagbibigay-daan sa app na mag-broadcast ng notification na kailangang ma-score ng mga network. Hindi kailanman kinakailangan para sa mga normal na app."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitahan ang numero ng mga tumatakbong proseso"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Pinapayagan ang app na kontrolin ang maximum na bilang ng mga proseso na tatakbo. Hindi kailanman kinakailangan para sa normal na apps."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"pwersahin ang mga app sa background na magsara"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng serbisyo ng Vpn. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"sumailalim sa wallpaper"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng isang wallpaper. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"magpasaklaw sa isang remote na display"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Binibigyang-daan ang may-hawak na masaklaw ang pinakamataas na antas ng interface ng isang remote na display. Hindi dapat kailanman kailanganin ng normal na apps."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"itali sa serbisyo ng widget"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Pinapayagan ang may-hawak na mag-bind sa top-level na interface ng isang TV input. Hindi kailanman kakailanganin ng mga normal na app."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"magdagdag o mag-alis ng admin ng device"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Pinapayagan ang may-ari na magdagdag o mag-alis ng mga aktibong administrator ng device. Hindi dapat kailanganin kailanman para sa normal na apps."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"baguhin ang orientation ng screen"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Pinapayagan ang app na gumamit ng anumang naka-install na media decoder upang mag-decode para sa pag-playback."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"mga pinamamahalaang pinagkakatiwalaang kredensyal"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Pinapayagan ang app na mag-install at mag-uninstall ng mga CA certificate bilang mga pinagkakatiwalaang kredensyal."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"paganahin ang application habang idle"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Nagbibigay-daan ang pahintulot na ito sa Android system na paganahin ang application sa background habang hindi ginagamit ang device."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"sumailalim sa mga idle na serbisyo"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Nagbibigay-daan ang pahintulot na ito sa Android system na sumailalim sa mga idle na serbisyo ng isang application."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"magbasa/magsulat sa mga mapagkukunang pag-aari ng diag"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Pinapayagan ang app na magbasa at magsulat sa anumang mapagkukunang pag-aari ng pangkat ng diag; halimbawa, mga file sa /dev. Maaaring potensyal na maapektuhan nito ang katatagan at seguridad ng system. Dapat LAMANG itong gamitin para sa diagnostics na tukoy sa hardware ng tagagawa o operator."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"paganahin o huwag paganahin ang mga bahagi ng app"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Pinapayagan ang app na basahin ang personal na impormasyon ng profile na naka-imbak sa iyong device, gaya ng iyong pangalan at impormasyon sa pakikipag-ugnay. Nangangahulugan ito na makikilala ka ng app at maaari nitong ipadala ang impormasyon ng iyong profile sa iba."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"baguhin sarili mo contact card"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Pinapayagan ang app na baguhin ang o magdagdag sa personal na impormasyon ng profile na naka-imbak sa iyong device, gaya ng iyong pangalan at impormasyon sa pakikipag-ugnay. Nangangahulugan ito na makikilala ka ng app at maaari nitong ipadala ang impormasyon ng iyong profile sa iba."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"mga sensor sa katawan (gaya ng mga heart rate monitor)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Pinapayagan ang app na i-access ang data mula sa mga sensor na ginagamit mo upang sukatin kung anong nangyayari sa iyong katawan, gaya ng heart rate."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"basahin ang iyong social stream"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Pinapayagan ang app na mag-access at mag-sync ng mga social na update mula sa iyo at sa iyong mga kaibigan. Maging maingat kapag nagbabahagi ng impormasyon -- pinapayagan nito ang app na magbasa ng mga pakikipag-ugnayan sa pagitan mo at ng iyong mga kaibigan sa mga social network, ano pa man ang katayuan sa pagiging kumpedensyal nito. Tandaan: hindi maaaring ipatupad ang pahintulot na ito sa lahat ng social network."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"magsulat sa iyong social stream"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Pinapayagan ang app na kontrolin ang mga tampok ng telepono ng device. Maaaring lumipat ng mga network ang isang app na mayroong ganitong pahintulot, i-on o i-off ang radyo ng telepono at mga kaparehong bagay nang hindi ka nano-notify."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"basahin ang katayuan at pagkakakilanlan ng telepono"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Pinapayagan ang app na i-access ang mga tampok ng telepono ng device. Pinapayagan ng pahintulot na ito ang app na tukuyin ang numero ng telepono at  mga ID ng device, kung aktibo man ang isang tawag, at ang malayuang numerong ikinonekta ng isang tawag."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"basahin ang tiyak na katayuan ng telepono"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Binibigyang-daan ang app na ma-access ang tumpak na katayuan ng telepono. Nagbibigay-daan ang pahintulot na ito sa app na matukoy ang tunay na status ng tawag, kung aktibo ang isang tawag o nasa background, mga hindi natuloy na tawag, tumpak na status ng koneksyon sa data at hindi natuloy na pagkonekta sa data."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"pigilan ang tablet mula sa pag-sleep"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"pigilan ang telepono mula sa paghinto"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Pinapayagan ang app na pigilan ang tablet mula sa pag-sleep."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Baguhin ang katayuan ng WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Pinapayagan ang app na ikonekta ang tablet at idiskonekta ang tablet mula sa mga WiMAX network."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Pinapayagan ang app na ikonekta ang telepono at idiskonekta ang telepono mula sa mga WiMAX network."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"mga network ng score"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Nagbibigay-daan sa app na iranggo ang mga network at impluwensiyahan kung aling mga network ang dapat na piliin ng tablet."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Nagbibigay-daan sa app na iranggo ang mga network at impluwensiyahan kung aling mga network ang dapat na piliin ng telepono."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"ipares sa mga Bluetooth device"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Pinapayagan ang app na tingnan ang configuration ng Bluetooth sa tablet, at na gumawa at tumanggap ng mga koneksyong may mga nakapares na device."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Pinapayagan ang app na tingnan ang configuration ng Bluetooth sa telepono, at na gumawa at tumanggap ng mga koneksyong may mga nakapares na device."</string>
@@ -703,18 +683,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"paganahin ang app ng configuration na ibinigay ng carrier"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Nagbibigay-daan sa may-ari na paganahin ang app ng configuration na ibinigay ng carrier. Hindi dapat kailanganin para sa normal na apps kahit kailan."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"makinig sa mga obserbasyon sa mga kundisyon ng network"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Nagbibigay-daan sa isang application na makinig sa mga obserbasyon sa mga kundisyon ng network. Dapat na hindi kailanman kakailanganin para sa normal na apps."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"baguhin ang pag-calibrate ng input device"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Pinapayagan ang app na baguhin ang mga parameter sa pag-calibrate ng touch screen. Hindi dapat kailanganin sa normal na apps."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"access sa Mga DRM certificate"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Nagbibigay-daan sa isang application na makapagbigay at gumamit ng mga DRM certficate. Hindi dapat kailanman 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="policylab_watchLogin" msgid="914130646942199503">"Subaybayan ang mga pagsubok sa pag-unlock ng screen"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Nagbibigay-daan sa isang application na i-access ang secure na storage ng keyguard."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Kontrolin ang pagpapakita at pagtago sa keyguard"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Pinapayagan ang isang application na kontrolin ang keyguard."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Makinig sa mga pagbabago sa estado ng trust."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Pinapayagan ang isang application na makinig para sa mga pagbabago sa estado ng trust."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Sumailalim sa isang serbisyo ng trust agent"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Pinapayagan ang isang application na sumailalim sa isang serbisyo ng trust agent."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Makipag-ugnay sa system ng pag-update at pagbawi"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Binibigyang-daan ang isang application na makipag-ugnay sa system ng pagbawi at mga pag-update ng system."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Pindutin nang dalawang beses para sa pagkontrol ng zoom"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Baguhin ang wallpaper"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Notification listener"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"Naka-activate ang VPN"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Isinaaktibo ang VPN ng <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Pindutin upang pamahalaan ang network."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 8c97507..132d9f0 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Senk."</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Çok fazla <xliff:g id="CONTENT_TYPE">%s</xliff:g> silme var."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Tabletin depolama alanı dolu! Yer açmak için bazı dosyaları silin."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Saat depolama alanınız dolu. Lütfen yer boşaltmak için bazı dosyaları silin."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Telefonun depolama alanı dolu! Yer açmak için bazı dosyaları silin."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Ağ izlenebilir"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Bunu, bilinmeyen üçüncü taraflar yapabilir"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Telefon zili açık"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Kapanıyor…"</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tabletiniz kapanacak."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Saatiniz kapatılacak."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefonunuz kapanacak."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Kapatmak istiyor musunuz?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Güvenli modda yeniden aç"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Uçak modu"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android Sistemi"</string>
@@ -259,7 +256,7 @@
     <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="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="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Uygulamaya, yapılan çağrıları işleme ve aranacak numarayı değiştirme izni verir. Bu izin, uygulamanın yapılan çağrıları izlemesine, yönlendirmesine ve önlemesine olanak sağlar."</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="permlab_receiveMms" msgid="1821317344668257098">"kısa mesajları (MMS) al"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Uygulamaya, etkin pencerenin içeriğini alma izni verir. Kötü amaçlı uygulamalar tüm pencere içeriğini alabilir ve şifreleri hariç tüm metni inceleyebilir."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"erişilebilirliği geçici olarak etkinleştir"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Uygulamaya, cihazda erişilebilirliği geçici olarak etkinleştirme izni verir. Kötü amaçlı uygulamalar, kullanıcının izni olmadan erişilebilirliği etkinleştirebilirler."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"pencere kodunu alma"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Bir uygulamanın pencere kodunu almasına izin verir. Zararlı uygulamalar, uygulama penceresi yerine geçme sistemiyle yetkisiz etkileşim gerçekleştirebilir."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"çerçeve istatistiklerini alma"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Bir uygulamanın çerçeve istatistikleri toplamasına izin verir. Zararlı uygulamalar, diğer uygulamalardan pencerelerin çerçeve istatistiklerini alabilirler."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"pencere bilgilerini al"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Uygulamaya, pencere yöneticisinden pencerelerle ilgili bilgi alma izni verir. Zararlı uygulamalar dahili sistem kullanımına yönelik bilgileri alabilir."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"etkinlikleri filtrele"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Uygulamaya, tüm kullanıcı etkinlikleri dağıtılmadan önce ilgili akışa filtre uygulayan bir giriş filtresi kaydetme izni verir. Zararlı uygulamalar kullanıcı müdahalesi olmadan sistem arayüzünü denetleyebilir."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"ekranı büyüt"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Uygulamaya bir ekranın içeriğini büyütme izni verir. Kötü amaçlı uygulamalar ekranın içeriğini etkileyerek cihazı kullanılmaz hale getirebilir."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"kısmi kapatma"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Eylem yöneticisini kapalı duruma getirir. Tam kapatma işlemi gerçekleştirmez."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"uygulama değişimlerini engelle"</string>
@@ -338,8 +335,6 @@
     <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="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_broadcastScoreNetworks" msgid="6432008366605475024">"ağları puanlama yayını gönderme"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Uygulamaya, ağların puanlanması gerektiği bildirimini yayınlama izni verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"çalışan işlem sayısını sınırla"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Uygulamaya, çalışacak süreçlerin azami sayısını denetleme izni verir. Normal uygulamalar için gerekli değildir."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"arka plan uygulamaları kapanmaya zorla"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Cihazın sahibine bir VPN hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"bir duvar kağıdına tabi kıl"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Cihazın sahibine, duvar kağıdının en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"uzak ekrana bağlan"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"İzin sahibine, bir uzak ekranın en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bir widget hizmetine bağla"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"İzin sahibine, bir TV girişinin en üst düzey arayüzüne bağlanma olanağı verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"cihaz yöneticisi ekle veya kaldır"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"İzin sahibine, etkin cihaz yöneticileri ekleyip kaldırma izni verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"ekran yönünü değiştir"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Uygulamaya, oynatma kodunu çözmek için herhangi bir yüklü medya kod çözücüyü kullanma izni verir."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"güvenilen kimlik bilgilerini yönetme"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Uygulamaya, güvenilir kimlik bilgileri olarak CA sertifikaları yükleme veya sertifikaların yüklemelerini kaldırma izni verir."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"boşta kaldığında uygulamayı çalıştır"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Bu izin, cihaz kullanımda değilken Android sistemin uygulamayı arka planda çalıştırmasına olanak sağlar."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"boşta kalma hizmetlerine bağlan"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Bu izin, Android sistemin, bir uygulamanın boşta kalma hizmetlerine bağlanmasına olanak sağlar."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"sahibi tanılama olan kaynakları oku/bunlara yaz"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Uygulamaya, tanılama grubunun sahip olduğu tüm kaynaklara (örneğin /dev içindeki dosyalar) okuma ve yazma izni verir. Bu işlevin sistem kararlılığını ve güvenliğini olumsuz etkileme olasılığı vardır. Üretici veya operatör tarafından YALNIZCA donanıma özgü tanılama için kullanılmalıdır."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"uygulama bileşenlerini etkinleştir veya devre dışı bırak"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Uygulamaya adınız ve iletişim bilgileriniz gibi cihazınızda saklanan kişisel profil bilgilerini okuma izni verir. Bu izin, uygulamanın sizi tanımlayabileceği ve profil bilgilerinizi başkalarına gönderebileceği anlamına gelir."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"kendi kişi kartınızı değiştirme"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Uygulamaya adınız ve iletişim bilgileriniz gibi cihazınızda saklanan kişisel profil bilgilerini değiştirme veya bunlara ekleme yapma izni verir. Bu izin, uygulamanın sizi tanımlayabileceği ve profil bilgilerinizi başkalarına gönderebileceği anlamına gelir."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"vücut sensörleri (kalp atış hızı takip cihazları gibi)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Uygulamanın, kalp atış hızınız gibi vücudunuzla ilgili olayları ölçmek için kullandığınız sensörlerden gelen verilere erişmesine izin verir."</string>
     <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>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Uygulamaya, cihazın telefon özelliklerini kontrol etme izni verir. Bu izne sahip bir uygulama sizi hiç uyarmadan ağlar arasında geçiş, telefonun radyosunu açıp kapatma ve benzeri işlemler yapabilir."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"telefonun durumunu ve kimliğini okuma"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Uygulamaya cihazdaki telefon özelliklerine erişme izni verir. Bu izin, uygulamanın telefon numarasını ve cihaz kimliğini, etkin bir çağrı olup olmadığını ve çağrıda bağlanılan karşı tarafın numarasını öğrenmesine olanak sağlar."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"telefon durum bilgilerini hassas bir şekilde oku"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Uygulamanın, telefonun durum bilgilerine hassas bir şekilde erişmesine izin verir. Bu izin sayesinde uygulama, gerçek çağrı durumunu, çağrının aktif mi yoksa arka planda mı olduğunu, çağrının başarısız olup olmadığını, veri bağlantısı durumuyla ilgili hassas bilgileri ve veri bağlantısının başarısız olup olmadığını belirleyebilir."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"tabletin uykuya geçmesini önle"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"telefonun uykuya geçmesini önleme"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Uygulamaya, tabletin uykuya geçmesini önleme izni verir."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX durumunu değiştir"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Uygulamaya, tableti WiMAX ağlarına bağlanma veya bağlantıyı kesme izni verir."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Uygulamaya, telefonu WiMAX ağlarına bağlanma veya bağlantıyı kesme izni verir."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ağları puanlama"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Uygulamaya, ağları sıralama ve tabletin tercih edeceği ağları etkileme izni verir."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Uygulamaya, ağları sıralama ve telefonunun tercih edeceği ağları etkileme izni verir."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"Bluetooth cihazlarla eşle"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Uygulamaya, tabletteki Bluetooth yapılandırmasını görüntüleme, eşleştirilmiş cihazlarla bağlantı yapma ve bu tür bağlantıları kabul etme izni verir."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Uygulamaya, telefondaki Bluetooth yapılandırmasını görüntüleme, eşleştirilmiş cihazlarla bağlantı yapma ve bu tür bağlantıları kabul etme izni verir."</string>
@@ -671,7 +651,7 @@
     <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="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="nosdcard" msgid="367275095159405468">"USB belleğimin içeriğini oku"</string>
     <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"SD kartımın içeriğini oku"</string>
     <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Uygulamaya, USB depolama biriminizin içeriğini okuma izni verir."</string>
     <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Uygulamaya, SD kartınızın içeriğini okuma izni verir."</string>
@@ -703,18 +683,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"operatör tarafından sağlanan yapılandırma uygulamasını çalıştır"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"İzin sahibine, operatör tarafından sağlanan yapılandırma uygulamasını çalıştırma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ağ koşullarındaki gözlemleri dinle"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Bir uygulamaya, ağ koşullarındaki gözlemleri dinleme izni verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"giriş cihazı kalibrasyonunu değiştir"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Uygulamaya, dokunmatik ekranın kalibrasyon parametrelerini değiştirme izni verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM sertifikalarına eriş"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Bir uygulamanın DRM sertifikaları için temel hazırlık yapmasına ve bunları kullanmasına izin verir. Normal uygulamalar için 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="policylab_watchLogin" msgid="914130646942199503">"Ekran kilidini açma denemelerini izle"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Bir uygulamanın tuş kilitli güvenli depolamaya erişimine izin verir."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Tuş koruyucuyu görüntülemeyi ve gizlemeyi kontrol et"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Bir uygulamaya tuş koruyucuyu denetleme izni verir."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Güven durumundaki değişiklileri dinle."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Bir uygulamanın, güven durumundaki değişiklikleri dinlemesine izin verir."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Güven aracı hizmetine bağlan"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Bir uygulamanın, güven aracı hizmetine bağlanmasına izin verir."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Güncelleme ve kurtarma sistemiyle etkileşim kur"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Bir uygulamaya, kurtarma sistemi ve sistem güncellemeriyle etkileşim kurma izni verir."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Yakınlaştırma denetimi için iki kez dokunun"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Duvar Kağıdı"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Duvar kağıdını değiştir"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Bildirim dinleyici"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN etkinleştirildi"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN, <xliff:g id="APP">%s</xliff:g> tarafından etkinleştirildi"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Ağı yönetmek için dokunun."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 104a45c..857e339 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -135,9 +135,8 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Синхр."</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Забагато видалень <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Пам’ять планшетного ПК заповнено. Видаліть якісь файли, щоб звільнити місце."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Пам’ять годинника заповнено. Видаліть файли, щоб звільнити місце."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Пам’ять телефону заповнено. Видаліть якісь файли, щоб звільнити місце."</string>
-    <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мережа може відстежуватися"</string>
+    <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мережу можуть відстежувати"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Невідомою третьою стороною"</string>
     <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Доменом <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
     <string name="me" msgid="6545696007631404292">"Я"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Дзвінок увімкнено"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Вимкнення..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Ваш пристрій буде вимкнено."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Годинник буде вимкнено."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Ваш телефон буде вимкнено."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Вимкнути?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Перейти в безпечний режим"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Режим польоту"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безп. режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"видаляти ярлики"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Дозволяє програмі самостійно вилучати ярлики з головного екрана."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"переадресовувати вихідні виклики"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Дозволяє додатку читати номер вихідного дзвінка, переспрямовувати дзвінок на інший номер або переривати його."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Дозволяє програмі обробляти вихідні дзвінки та змінювати номер для виклику. Такий дозвіл дає програмі змогу відстежувати, переадресовувати чи блокувати вихідні дзвінки."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"отримувати текстові повідомлення (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Дозволяє програмі отримувати й обробляти SMS-повідомлення. Це означає, що програма може відстежувати чи видаляти повідомлення, надіслані на ваш пристрій, навіть не показуючи їх вам."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"отримувати текстові повідомлення (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Дозволяє програмі отримувати вміст активного вікна. Шкідливі програми можуть отримувати весь вміст вікна та вивчати весь його текст, окрім паролів."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"тимчасово вмикати доступність"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Дозволяє програмі тимчасового вмикати доступність на пристрої. Шкідливі програми можуть вмикати доступність без згоди користувача."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"отримувати маркер вікна"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Дозволяє додатку отримувати маркер вікна. Шкідливі додатки можуть без дозволу взаємодіяти з вікном додатка, видаючи себе за систему."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"отримувати статистику частоти кадрів"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Дозволяє додатку збирати статистику частоти кадрів. Шкідливі додатки можуть відстежувати частоту кадрів у вікнах інших додатків."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"отримувати інформацію про вікна"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Дозволяє програмі отримувати інформацію про вікна від диспетчера вікон. Шкідливі програми можуть отримувати інформацію, яка призначена для внутрішнього користування системи."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"фільтрувати події"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Дозволяє програмі реєструвати вхідний фільтр, який фільтрує потік усіх подій користувача перед їх надсиланням. Шкідливі програми можуть контролювати інтерфейс системи без втручання користувача."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"збільшити екран"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Дозволяє програмі збільшувати вміст екрана. Зловмисні програми можуть змінювати вміст екрана так, що пристроєм стає неможливо користуватися."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"частк. заверш. роб."</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Переводить диспетчер дій у стан завершення роботи. Не виконує повне завершення роботи."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"запобіг. зміні програм"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Дозволяє програмі передавати сповіщення про отримання SMS повідомлення. Шкідливі програми можуть використовувати це для підробки вхідних SMS повідомлень."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"надсил. запис, отр. через WAP-PUSH"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Дозволяє програмі передавати сповіщення про отримання повідомлення WAP PUSH. Шкідливі програми можуть використовувати це для підробки отримання MMS повідомлень або для непомітної заміни вмісту будь-якої веб-сторінки шкідливими варіантами."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"надсилати сповіщення про оцінку мереж"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Дозволяє додатку передавати сповіщення про оцінку мереж. Ніколи не застосовується для звичайних додатків."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"обмежувати кількість запущ. процесів"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Дозволяє програмі контролювати максимальну кількість процесів, які буде запущено. Ніколи не вимагається для звичайних програм."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"примусово закривати фонові програми"</string>
@@ -387,20 +382,14 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби VPN. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"прив’язати до фонового малюнка"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня фонового малюнка. Ніколи не застосовується для звичайних програм."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"прив’язуватися до віддаленого екрана"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Додаток зможе підключатися до інтерфейсу верхнього рівня TV-входу. Звичайні додатки ніколи не використовують цей дозвіл."</string>
+    <string name="permlab_bindTvInput" msgid="5601264742478168987">"прив’язуватися до вводу телевізора"</string>
+    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня вводу телевізора. Ніколи не застосовується для звичайних додатків."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"додавати чи вилучати адміністраторів пристрою"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Дозволяє власнику додавати чи вилучати активних адміністраторів пристрою. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"змінювати орієнтацію екрана"</string>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Дозволяє програмі використовувати будь-який установлений медіа-декодер для декодування з метою відтворення."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"керувати захищеними обліковими даними"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Дозволяє програмі встановлювати та видаляти сертифікати центру сертифікації (CA) як захищені облікові дані."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"запускати додаток, коли пристрій неактивний"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Маючи цей дозвіл, система Android може запускати додаток у фоновому режимі, коли пристрій не використовується."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"взаємодіяти з неактивними службами"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Такий дозвіл дає змогу системі Android прив’язуватися до неактивних служб програми."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"чит./зап. на ресури., якими вол. діаг."</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Дозволяє програмі читати та писати на будь-який ресурс, яким володіє діагностична група; наприклад, у файли в папці /dev. Це потенційно може вплинути на стабільність і безпеку системи. Потрібно використовувати ЛИШЕ для певної діагностики обладнання, яку виконує виробник чи оператор."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"вмикати чи вимикати компоненти програми"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Дозволяє програмі читати особисту інформацію профілю, збережену на пристрої, як-от ваше ім’я та контактну інформацію. Це означає, що програма може ідентифікувати вашу особу та надсилати дані вашого профілю іншим."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"змінювати картки контактів"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Дозволяє програмі змінювати чи додавати особисту інформацію профілю, збережену на пристрої, як-от ваше ім’я та контактну інформацію. Це означає, що програма може ідентифікувати вашу особу та надсилати дані вашого профілю іншим."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"датчики на тілі (як-от пульсометр)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Дозволяє додатку отримувати дані з датчиків, які вимірюють фізіологічні процеси, як-от пульс."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"читати ваш соціальний потік"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Дозволяє програмі отримувати доступ до оновлень із соціальних мереж від вас і ваших друзів та синхронізувати їх. Будьте обережні, надаючи доступ до інформації – це дозволяє програмі читати повідомлення, якими ви та ваші друзі обмінювалися в соціальних мережах, незалежно від конфіденційності. Зауважте: цей дозвіл не можна застосовувати в усіх соціальних мережах."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"писати у ваш соціальний потік"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Дозволяє програмі контролювати телефонні функції пристрою. Програма з цим дозволом може переключати мережі, вмикати та вимикати радіо в телефоні тощо без вашого відома."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"читати статус та ідентифікаційну інформацію телефону"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Дозволяє програмі отримувати доступ до телефонних функцій пристрою. Такий дозвіл дає програмі змогу визначати номер телефону й ідентифікатори пристрою, активність виклику, а також віддалений номер, на який здійснюється виклик."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"читати точні статуси телефону"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Дозволяє додатку отримувати доступ до статусів телефону. Цей дозвіл дає додатку змогу визначати статус виклику (активний чи у фоновому режимі), помилки викликів, точний статус передавання даних і помилки передавання даних."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"не доп.перехід пристр.в реж.сну"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"недоп. перехід тел. в реж. сну"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Дозволяє програмі не допускати перехід планшетного ПК у режим сну."</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Змінити стан WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Дозволяє програмі під’єднувати планшетний ПК до мереж WiMAX і від’єднувати його від них."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Дозволяє програмі під’єднувати телефон до мереж WiMAX і від’єднувати його від них."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"оцінювати мережі"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Дозволяє додатку оцінювати мережі та впливати на вибір мережі планшетом."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Дозволяє додатку оцінювати мережі та впливати на вибір мережі телефоном."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"створювати пару з пристроями Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Дозволяє програмі переглядати конфігурацію Bluetooth на планшетному ПК, а також створювати та приймати з’єднання зі спареними пристроями."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Дозволяє програмі переглядати конфігурацію Bluetooth на телефоні, а також створювати та приймати з’єднання зі спареними пристроями."</string>
@@ -703,18 +685,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозволяє програмі отримувати, перевіряти й очищати сповіщення, зокрема опубліковані іншими програмами."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"прив’язуватися до служби читання сповіщень"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня служби читання сповіщень. Ніколи не застосовується для звичайних програм."</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"викликати надану оператором програму конфігурації"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Дозволяє власнику викликати надану оператором програму конфігурації. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"прослуховувати дані спостережень за станом мережі"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Дозволяє програмі прослуховувати дані спостережень за станом мережі. Ніколи не застосовується для звичайних програм."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"змінювати калібрування пристрою введення"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Програма може змінювати параметри калібрування сенсорного екрана. Ніколи не застосовується для звичайних програм."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"отримувати доступ до сертифікатів DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Дозволяє додатку надавати та використовувати сертифікати DRM. Ніколи не застосовується для звичайних додатків."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Устан. правила пароля"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролювати довжину паролів для розблокування екрана та дозволені в них символи."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Відстежув. спроби розблок. екрана"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Дозволяє програмі отримувати доступ до безпечного сховища через клавіатуру."</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>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Прив’язуватися до служби довірчих агентів"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Дозволяє додатку прив’язуватися до служби довірчих агентів."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Взаємодіяти з оновленнями системи та системою відновлення."</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Дозволяє додатку взаємодіяти із системою відновлення й оновленнями системи."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Двічі торкніться, щоб керувати масштабом"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Фоновий мал."</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Змінити фоновий малюнок"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Служба читання сповіщень"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"Мережу VPN активовано"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Мережу VPN активовано програмою <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Торкніться, щоб керувати мережею."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 24d468c..e774e8e 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Đồng bộ hóa"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Quá nhiều lần xóa <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Bộ nhớ máy tính bảng đã đầy. Hãy xóa một số tệp để tạo thêm dung lượng."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Bộ nhớ đồng hồ đã đầy. Hãy xóa một số tệp để giải phóng dung lượng."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Bộ nhớ điện thoại đã đầy. Hãy xóa một số tệp để tạo thêm dung lượng."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mạng có thể được giám sát"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Bởi một bên thứ ba không xác định"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Bật chuông"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Đang tắt…"</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Máy tính bảng của bạn sẽ tắt."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Đồng hồ của bạn sẽ tắt."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Điện thoại của bạn sẽ tắt."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Bạn có muốn tắt không?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Khởi động lại ở chế độ an toàn"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Chế độ trên máy bay"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Chế độ an toàn"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Hệ thống Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"gỡ cài đặt lối tắt"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Cho phép ứng dụng xóa lối tắt trên Màn hình chính mà không cần sự can thiệp của người dùng."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"định tuyến lại cuộc gọi đi"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Cho phép ứng dụng xem số được gọi trong một cuộc gọi đi với tùy chọn chuyển hướng cuộc gọi đến một số khác hoặc hủy cuộc gọi đó hoàn toàn."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Cho phép ứng dụng xử lý cuộc gọi đi và thay đổi số được gọi. Quyền này cho phép ứng dụng theo dõi, chuyển hướng hoặc chặn cuộc gọi đi."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"nhận tin nhắn văn bản (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Cho phép ứng dụng nhận và xử lý tin nhắn SMS. Điều này có nghĩa là ứng dụng có thể theo dõi hoặc xóa tin nhắn được gửi đến thiết bị của bạn mà không hiển thị chúng cho bạn."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"nhận tin nhắn văn bản (MMS)"</string>
@@ -318,28 +315,26 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Cho phép ứng dụng truy xuất nội dung của cửa sổ hiện hành. Ứng dụng độc hại có thể truy xuất toàn bộ nội dung của cửa sổ cũng như xem xét toàn bộ văn bản của cửa sổ ngoại trừ mật khẩu."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"tạm thời bật trợ năng"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Cho phép ứng dụng tạm thời bật trợ năng trên thiết bị. Các ứng dụng độc hại có thể bật trợ năng mà không có sự đồng ý của người dùng."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"truy xuất mã thông báo cửa sổ"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Cho phép một ứng dụng truy xuất mã thông báo cửa sổ. Các ứng dụng độc hại có thể thực hiện hoạt động tương tác trái phép với cửa sổ ứng dụng mạo danh hệ thống."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"truy xuất số liệu thống kê về khung"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Cho phép một ứng dụng thu thập số liệu thống kê về khung. Ứng dụng độc hại có thể quan sát số liệu thống kê về khung của cửa sổ từ ứng dụng khác."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"truy xuất thông tin cửa sổ"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Cho phép ứng dụng truy xuất thông tin về các cửa sổ từ trình quản lý cửa sổ. Các ứng dụng độc hại có thể truy xuất thông tin được dành để sử dụng trong hệ thống nội bộ."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"lọc sự kiện"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Cho phép ứng dụng đăng ký bộ lọc dữ liệu nhập để lọc luồng tất cả các sự kiện người dùng trước khi chúng được gửi đi. Ứng dụng độc hại có thể kiểm soát Giao diện người dùng hệ thống mà không cần sự can thiệp của người dùng."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"thu phóng màn hình"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Cho phép ứng dụng thu phóng nội dung trên màn hình. Ứng dụng độc hại có thể biến đổi nội dung trên màn hình theo cách kết xuất thiết bị không thể sử dụng được."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"tắt từng phần"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Đặt trình quản lý hoạt động sang trạng thái tắt. Không thực hiện tắt hoàn toàn."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"ngăn chuyển đổi ứng dụng"</string>
     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Ngăn người dùng chuyển sang ứng dụng khác."</string>
     <string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"truy cập thông tin ứng dụng hiện tại"</string>
     <string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Cho phép chủ sở hữu truy xuất thông tin cá nhân về ứng dụng hiện tại ở nền trước của màn hình."</string>
-    <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"giám sát và kiểm soát tất cả hoạt động chạy ứng dụng"</string>
-    <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Cho phép ứng dụng giám sát và kiểm soát cách hệ thống chạy các hoạt động. Ứng dụng độc hại hoàn toàn có thể làm tổn hại hệ thống. Quyền này chỉ cần cho mục đích phát triển, không dành cho mục đích sử dụng thông thường."</string>
+    <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"giám sát và kiểm soát tất cả hoạt động khởi chạy ứng dụng"</string>
+    <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Cho phép ứng dụng giám sát và kiểm soát cách hệ thống khởi chạy các hoạt động. Ứng dụng độc hại hoàn toàn có thể làm tổn hại hệ thống. Quyền này chỉ cần cho mục đích phát triển, không dành cho mục đích sử dụng thông thường."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"gửi truyền phát đã xóa của gói"</string>
     <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"Cho phép ứng dụng truyền phát thông báo cho biết rằng gói ứng dụng đã bị xóa. Ứng dụng độc hại có thể sử dụng quyền này để loại bỏ bất kỳ ứng dụng nào khác đang chạy."</string>
     <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"gửi truyền phát SMS nhận được"</string>
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Cho phép ứng dụng truyền phát thông báo cho biết đã nhận được tin nhắn SMS. Ứng dụng độc hại có thể sử dụng quyền này để giả mạo tin nhắn SMS đến."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"gửi truyền phát WAP-PUSH nhận được"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Cho phép ứng dụng truyền phát thông báo cho biết rằng đã nhận được tin nhắn WAP PUSH. Ứng dụng độc hại có thể sử dụng quyền này để giả mạo xác nhận đã nhận được tin nhắn MMS hoặc ngầm thay thế nội dung của bất kỳ trang web nào bằng các biến thể độc hại."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"gửi chương trình phát mạng điểm số"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Cho phép ứng dụng truyền thông báo rằng các mạng cần để được tính điểm. Không bao giờ cần cho ứng dụng thông thường."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"giới hạn số quá trình đang chạy"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Cho phép ứng dụng kiểm soát số quy trình tối đa sẽ chạy. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"buộc ứng dụng nền đóng"</string>
@@ -355,7 +350,7 @@
     <string name="permlab_backup" msgid="470013022865453920">"kiểm soát sao lưu và khôi phục hệ thống"</string>
     <string name="permdesc_backup" msgid="6912230525140589891">"Cho phép ứng dụng kiểm soát cơ chế sao lưu và khôi phục của hệ thống. Không dành cho các ứng dụng thông thường."</string>
     <string name="permlab_confirm_full_backup" msgid="5557071325804469102">"xác nhận bản sao lưu đầy đủ hoặc khôi phục hoạt động"</string>
-    <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Cho phép ứng dụng chạy UI xác nhận sao lưu toàn bộ. Không dành cho bất kỳ ứng dụng nào."</string>
+    <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Cho phép ứng dụng khởi chạy UI xác nhận sao lưu toàn bộ. Không dành cho bất kỳ ứng dụng nào."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"hiển thị các cửa sổ trái phép"</string>
     <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Cho phép ứng dụng tạo các cửa sổ dùng cho giao diện người dùng hệ thống nội bộ. Không dành cho các ứng dụng thông thường."</string>
     <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"vẽ trên ứng dụng khác"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"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ụ Vpn. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"liên kết với hình nền"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của hình nền. Không cần thiết cho các ứng dụng thông thường."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"liên kết với màn hình từ xa"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của màn hình từ xa. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"liên kết với dịch vụ tiện ích con"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của đầu vào TV. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"thêm hoặc xóa quản trị viên thiết bị"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Cho phép chủ sở hữu thêm hoặc xóa quản trị viên thiết bị đang hoạt động. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"thay đổi hướng màn hình"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Cho phép ứng dụng sử dụng bất kỳ trình giải mã phương tiện nào đã cài đặt nhằm giải mã để phát lại."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"quản lý thông tin xác thực đáng tin cậy"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Cho phép ứng dụng cài đặt và gỡ cài đặt chứng chỉ CA dưới dạng thông tin xác thực đáng tin cậy."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"chạy ứng dụng trong thời gian rảnh"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Quyền này cho phép hệ thống Android chạy ứng dụng trong nền khi thiết bị không được sử dụng."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"liên kết với dịch vụ không dùng đến"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Quyền này cho phép hệ thống Android liên kết với các dịch vụ ở trạng thái rảnh của ứng dụng."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"đọc/ghi vào tài nguyên do chẩn đoán sở hữu"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Cho phép ứng dụng đọc và ghi vào bất kỳ tài nguyên nào do nhóm chẩn đoán sở hữu; ví dụ: các tệp trong /dev. Quyền này có thể ảnh hưởng đến sự ổn định và tính bảo mật của hệ thống. CHỈ nên sử dụng quyền này cho các chẩn đoán phần cứng cụ thể của nhà sản xuất hoặc nhà cung cấp."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"bật hoặc tắt cấu phần ứng dụng"</string>
@@ -454,8 +441,8 @@
     <string name="permlab_writeGservices" msgid="2149426664226152185">"sửa đổi bản đồ dịch vụ của Google"</string>
     <string name="permdesc_writeGservices" msgid="1287309437638380229">"Cho phép ứng dụng sửa đổi bản đồ dịch vụ của Google. Không dành cho ứng dụng thông thường."</string>
     <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"chạy khi khởi động"</string>
-    <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Cho phép ứng dụng tự chạy ngay khi hệ thống khởi động xong. Quyền này có thể khiến máy tính bảng mất nhiều thời gian khởi động hơn và cho phép ứng dụng làm chậm toàn bộ máy tính bảng do ứng dụng luôn chạy."</string>
-    <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Cho phép ứng dụng tự chạy ngay khi hệ thống khởi động xong. Quyền này có thể khiến điện thoại mất nhiều thời gian khởi động hơn và cho phép ứng dụng làm chậm toàn bộ điện thoại do ứng dụng luôn chạy."</string>
+    <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Cho phép ứng dụng tự khởi chạy ngay khi hệ thống khởi động xong. Quyền này có thể khiến máy tính bảng mất nhiều thời gian khởi động hơn và cho phép ứng dụng làm chậm toàn bộ máy tính bảng do ứng dụng luôn chạy."</string>
+    <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Cho phép ứng dụng tự khởi chạy ngay khi hệ thống khởi động xong. Quyền này có thể khiến điện thoại mất nhiều thời gian khởi động hơn và cho phép ứng dụng làm chậm toàn bộ điện thoại do ứng dụng luôn chạy."</string>
     <string name="permlab_broadcastSticky" msgid="7919126372606881614">"gửi truyền phát hấp dẫn người xem"</string>
     <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"Cho phép ứng dụng gửi nội dung truyền phát hấp dẫn người xem. Nội dung này sẽ vẫn còn sau khi quá trình truyền phát kết thúc. Việc sử dụng quá mức có thể làm cho máy tính bảng bị chậm hoặc không ổn định do khiến máy tính bảng sử dụng quá nhiều bộ nhớ."</string>
     <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Cho phép ứng dụng gửi nội dung truyền phát hấp dẫn người xem. Nội dung này sẽ vẫn còn sau khi quá trình truyền phát kết thúc. Việc sử dụng quá mức có thể làm cho điện thoại bị chậm hoặc không ổn định do khiến điện thoại sử dụng quá nhiều bộ nhớ."</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Cho phép ứng dụng đọc thông tin tiểu sử cá nhân được lưu trữ trên thiết bị, chẳng hạn như tên và thông tin liên hệ của bạn. Điều này có nghĩa là ứng dụng có thể xác định danh tính của bạn và gửi thông tin tiểu sử của bạn cho người khác."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"sửa đổi thẻ liên hệ của riêng bạn"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Cho phép ứng dụng thay đổi hoặc thêm vào thông tin tiểu sử cá nhân được lưu trữ trên thiết bị, chẳng hạn như tên và thông tin liên hệ của bạn. Điều này có nghĩa là ứng dụng có thể xác định danh tính của bạn và gửi thông tin tiểu sử của bạn cho người khác."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"cảm biến cơ thể (như máy đo nhịp tim)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Cho phép ứng dụng truy cập dữ liệu từ cảm biến mà bạn sử dụng để đo những gì đang diễn ra bên trong cơ thể của bạn, chẳng hạn như nhịp tim."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"đọc luồng xã hội của bạn"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Cho phép ứng dụng truy cập và đồng bộ hóa các cập nhật xã hội của bạn và bạn bè bạn. Hãy cẩn trọng khi chia sẻ thông tin -- việc này có thể cho phép ứng dụng đọc thông tin liên lạc giữa bạn và bạn bè bạn trên các mạng xã hội, bất kể tính bí mật là gì. Lưu ý: quyền này có thể không được thực thi trên tất cả các mạng xã hội."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"ghi luồng xã hội của bạn"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Cho phép ứng dụng kiểm soát các tính năng điện thoại của thiết bị. Ứng dụng có quyền này có thể chuyển đổi mạng, bật và tắt radio điện thoại cũng như thực hiện các tác vụ tương tự mà không cần thông báo cho bạn."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"đọc trạng thái và nhận dạng của điện thoại"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Cho phép ứng dụng truy cập vào các tính năng điện thoại của thiết bị. Quyền này cho phép ứng dụng xác định số điện thoại và ID thiết bị, cho dù cuộc gọi có hiện hoạt hay không và số từ xa có được kết nối bằng một cuộc gọi hay không."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"đọc trạng thái điện thoại chính xác"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Cho phép ứng dụng truy cập trạng thái điện thoại chính xác. Quyền này cho phép ứng dụng xác định trạng thái cuộc gọi thực, cuộc gọi đang hoạt động hay trong nền, cuộc gọi không thành công, trạng thái kết nối dữ liệu chính xác và kết nối dữ liệu không thành công."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ngăn máy tính bảng chuyển sang chế độ ngủ"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ngăn điện thoại chuyển sang chế độ ngủ"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Cho phép ứng dụng ngăn máy tính bảng chuyển sang chế độ ngủ."</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Thay đổi trạng thái WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Cho phép ứng dụng kết nối máy tính bảng và ngắt kết nối máy tính bảng khỏi mạng WiMAX."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Cho phép ứng dụng kết nối điện thoại và ngắt kết nối điện thoại khỏi mạng WiMAX."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"mạng điểm số"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Cho phép ứng dụng xếp hạng mạng và ảnh hưởng đến việc máy tính bảng nên ưu tiên mạng nào."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Cho phép ứng dụng xếp hạng các mạng và ảnh hưởng đến việc điện thoại nên ưu tiên mạng nào."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"ghép nối với thiết bị Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Cho phép ứng dụng xem cấu hình của Bluetooth trên máy tính bảng và tạo và chấp nhận các kết nối với các thiết bị được ghép nối."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Cho phép ứng dụng xem cấu hình của Bluetooth trên điện thoại, tạo và chấp nhận các kết nối với các thiết bị được ghép nối."</string>
@@ -703,18 +683,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <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>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Cho phép chủ sở hữu gọi ra ứng dụng cấu hình do nhà cung cấp dịch vụ cung cấp. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"quan sát các điều kiện mạng"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Cho phép ứng dụng quan sát các điều kiện mạng. Không bao giờ cần cho ứng dụng thông thường."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"thay đổi hiệu chỉnh thiết bị đầu vào"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Cho phép ứng dụng sửa đổi các thông số hiệu chỉnh của màn hình cảm ứng. Không cần cho ứng dụng thông thường."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"truy cập chứng chỉ DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Cho phép ứng dụng cung cấp và sử dụng chứng chỉ DRM. 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="policylab_watchLogin" msgid="914130646942199503">"Giám sát những lần thử mở khóa màn hình"</string>
@@ -1177,7 +1149,7 @@
     <string name="webpage_unresponsive" msgid="3272758351138122503">"Trang không phản hồi.\n\nBạn có muốn đóng trang không?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Đã chuyển hướng ứng dụng"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> hiện đang chạy."</string>
-    <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> được chạy trước tiên."</string>
+    <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> được khởi chạy trước tiên."</string>
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Tỷ lệ"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Luôn hiển thị"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Bật lại chế độ này trong cài đặt Hệ thống &gt; Ứng dụng &gt; Đã tải xuống."</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Cho phép ứng dụng truy cập bộ nhớ an toàn khóa"</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Kiểm soát việc hiển thị và ẩn tính năng bảo vệ phím"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Cho phép ứng dụng kiểm soát tính năng bảo vệ phím."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Quan sát các thay đổi ở trạng thái đáng tin cậy."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Cho phép ứng dụng quan sát các thay đổi ở trạng thái đáng tin cậy."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Liên kết với một dịch vụ của đại lý đáng tin cậy"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Cho phép ứng dụng liên kết với một dịch vụ của đại lý đáng tin cậy."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Tương tác với hệ thống khôi phục và bản cập nhật"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Cho phép ứng dụng tương tác với hệ thống khôi phục và bản cập nhật hệ thống."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Chạm hai lần để kiểm soát thu phóng"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Hình nền"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Thay đổi hình nền"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Trình xử lý thông báo"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"Đã kích hoạt VPN"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN được <xliff:g id="APP">%s</xliff:g> kích hoạt"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Chạm để quản lý mạng."</string>
@@ -1464,7 +1430,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Chọn một ứng dụng"</string>
-    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Không thể chạy <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Không thể khởi chạy <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Chia sẻ với"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Chia sẻ với <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Tay trượt. Chạm &amp; giữ."</string>
@@ -1513,7 +1479,7 @@
     <string name="share_action_provider_share_with" msgid="5247684435979149216">"Chia sẻ với"</string>
     <string name="list_delimeter" msgid="3975117572185494152">", "</string>
     <string name="sending" msgid="3245653681008218030">"Đang gửi…"</string>
-    <string name="launchBrowserDefault" msgid="2057951947297614725">"Chạy trình duyệt?"</string>
+    <string name="launchBrowserDefault" msgid="2057951947297614725">"Khởi chạy trình duyệt?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Chấp nhận cuộc gọi?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Luôn chọn"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Chỉ một lần"</string>
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index 4c4d0ce..44e258d 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -27,4 +27,14 @@
         <item>settings</item>
     </string-array>
 
-</resources>
\ No newline at end of file
+    <!-- Base "touch slop" value used by ViewConfiguration as a
+         movement threshold where scrolling should begin. -->
+    <dimen name="config_viewConfigurationTouchSlop">4dp</dimen>
+
+    <!-- Minimum velocity to initiate a fling, as measured in dips per second. -->
+    <dimen name="config_viewMinFlingVelocity">500dp</dimen>
+
+    <!-- Maximum velocity to initiate a fling, as measured in dips per second. -->
+    <dimen name="config_viewMaxFlingVelocity">8000dp</dimen>
+
+</resources>
diff --git a/core/res/res/values-watch/themes.xml b/core/res/res/values-watch/themes.xml
new file mode 100644
index 0000000..9447d9cb
--- /dev/null
+++ b/core/res/res/values-watch/themes.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <style name="Theme.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
+    <style name="Theme.Dialog.AppError" parent="Theme.Micro.Dialog.AppError" />
+    <style name="Theme.Holo.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
+    <style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
+</resources>
diff --git a/core/res/res/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml
new file mode 100644
index 0000000..705143c
--- /dev/null
+++ b/core/res/res/values-watch/themes_device_defaults.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <style name="Theme.DeviceDefault" parent="Theme.Micro" />
+    <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Micro" />
+    <style name="Theme.DeviceDefault.Dialog" parent="Theme.Micro.Dialog" />
+    <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
+    <style name="Theme.DeviceDefault.Light" parent="Theme.Micro.Light" />
+    <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Micro.Light" />
+    <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Micro.Light" />
+    <style name="Theme.DeviceDefault.Light.Dialog" parent="Theme.Micro.Dialog" />
+    <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
+
+</resources>
+
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 95ec384..035c5b6 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -76,15 +76,15 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"默认显示本机号码,在下一次通话中也显示"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"未提供服务。"</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"您无法更改来电显示设置。"</string>
-    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"网络可用情况发生变化"</string>
-    <string name="RestrictedOnData" msgid="8653794784690065540">"数据网络服务已停用。"</string>
-    <string name="RestrictedOnEmergency" msgid="6581163779072833665">"紧急服务已停用。"</string>
-    <string name="RestrictedOnNormal" msgid="4953867011389750673">"语音服务已停用。"</string>
-    <string name="RestrictedOnAllVoice" msgid="3396963652108151260">"所有语音服务都已停用。"</string>
-    <string name="RestrictedOnSms" msgid="8314352327461638897">"短信服务已停用。"</string>
-    <string name="RestrictedOnVoiceData" msgid="996636487106171320">"语音/数据服务已停用。"</string>
-    <string name="RestrictedOnVoiceSms" msgid="1888588152792023873">"语音/短信服务已停用。"</string>
-    <string name="RestrictedOnAll" msgid="5643028264466092821">"所有语音/数据/短信服务都已停用。"</string>
+    <string name="RestrictedChangedTitle" msgid="5592189398956187498">"访问受限情况已发生变化"</string>
+    <string name="RestrictedOnData" msgid="8653794784690065540">"数据服务已禁用。"</string>
+    <string name="RestrictedOnEmergency" msgid="6581163779072833665">"紧急服务已禁用。"</string>
+    <string name="RestrictedOnNormal" msgid="4953867011389750673">"已禁用语音服务。"</string>
+    <string name="RestrictedOnAllVoice" msgid="3396963652108151260">"已停用所有语音服务。"</string>
+    <string name="RestrictedOnSms" msgid="8314352327461638897">"已禁用短信服务。"</string>
+    <string name="RestrictedOnVoiceData" msgid="996636487106171320">"已停用语音/数据服务。"</string>
+    <string name="RestrictedOnVoiceSms" msgid="1888588152792023873">"已禁用语音/短信服务。"</string>
+    <string name="RestrictedOnAll" msgid="5643028264466092821">"已停用所有语音/数据/短信服务。"</string>
     <string name="serviceClassVoice" msgid="1258393812335258019">"语音"</string>
     <string name="serviceClassData" msgid="872456782077937893">"数据"</string>
     <string name="serviceClassFAX" msgid="5566624998840486475">"传真"</string>
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"同步"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"太多<xliff:g id="CONTENT_TYPE">%s</xliff:g>删除项。"</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"平板电脑存储空间已满。请删除一些文件以腾出空间。"</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"手表存储空间已满。请删除一些文件以腾出空间。"</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"手机存储空间已满。请删除一些文件以腾出空间。"</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"网络可能会受到监控"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"受到不明第三方的监控"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"振铃器开启"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"正在关机..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"您的平板电脑会关闭。"</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"您的手表即将关机。"</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"您的手机将会关机。"</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"您要关机吗?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"重新启动并进入安全模式"</string>
@@ -172,8 +170,7 @@
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"声音已开启"</string>
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"飞行模式"</string>
     <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_actions_airplane_mode_off_status" msgid="5075070442854490296">"已关闭飞行模式"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"卸载快捷方式"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"允许应用自行删除主屏幕快捷方式。"</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"重新设置外拨电话的路径"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"允许应用在拨出电话时查看拨打的电话号码,并选择改为拨打其他号码或完全中止通话。"</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"允许该应用处理外拨电话以及更改要拨打的号码。此权限可让该应用监视、重定向或阻止外拨电话。"</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"接收讯息(短信)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"允许该应用接收和处理短信。这就意味着,该应用可能会监视发送到您设备的短信,或删除发送到您设备的短信而不向您显示。"</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"接收讯息(彩信)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"允许应用检索活动窗口的内容。恶意应用可能会检索整个窗口的内容,并检查其中除密码以外的所有文字。"</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"暂时启用辅助功能"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"允许应用在设备上暂时启用辅助功能。恶意应用可能会在未经用户同意的情况下擅自启用辅助功能。"</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"检索窗口令牌"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"允许应用检索窗口令牌。恶意软件可能会借此在未经授权的情况下冒充系统与应用窗口进行互动。"</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"检索框架统计信息"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"允许应用收集框架统计信息。恶意应用可能会借此监测其他应用的窗口框架统计信息。"</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"检索窗口信息"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"允许应用通过窗口管理器检索窗口信息。恶意应用可能会检索供内部系统使用的信息。"</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"过滤事件"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"允许应用注册输入过滤器,这类过滤器会在所有用户事件分派之前对用户事件流进行过滤。恶意应用可能会在没有用户干预的情况下控制系统用户界面。"</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"放大显示内容"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"允许应用放大显示内容。恶意应用可能会以特定方式改变显示内容,使得设备无法使用。"</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"部分关机"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"使活动管理器进入关闭状态。不执行彻底关机。"</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"禁止切换应用"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"允许应用广播一条有关已收到短信的通知。恶意应用可能借此伪造接到的短信。"</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"发送 WAP-PUSH 收到的广播"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"允许应用广播一条有关已收到 WAP PUSH 短信的通知。恶意应用可能借此伪造短信接收,或在后台将任意网页的内容替换为恶意内容。"</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"发送网络评分广播通知"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"允许应用广播“需要为网络评分”的通知。普通应用绝不需要此权限。"</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"限制运行的进程个数"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"允许应用控制将运行的进程数上限。普通应用绝不需要此权限。"</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"强制关闭后台应用"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"允许用户绑定到 VPN 服务的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"绑定到壁纸"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允许用户绑定到壁纸的顶级接口。普通应用绝不需要此权限。"</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"绑定至远程显示屏"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"允许应用绑定至电视输入设备的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"添加或删除设备管理员"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"允许应用添加或删除有效的设备管理员。普通应用绝不需要此权限。"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"更改屏幕显示方向"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允许该应用使用任何已安装的媒体解码器进行解码,以便播放媒体。"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理受信任的凭据"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允许应用安装和卸载 CA 证书(作为受信任的凭据)。"</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"在设备处于闲置状态时运行应用"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"当设备处于闲置状态时,此权限允许Android系统在后台运行该应用。"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"绑定到闲置服务"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"此权限允许Android系统绑定至应用的闲置服务。"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"读取/写入诊断所拥有的资源"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"允许应用读取/写入诊断组拥有的所有资源(例如 /dev 中的文件)。这可能会影响系统的稳定性和安全性。此权限仅供制造商或运营商诊断硬件方面的问题时使用。"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"启用或停用应用组件"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"允许该应用读取您设备上存储的个人资料信息,例如您的姓名和联系信息。这意味着该应用可以识别您的身份,并可能将您的个人资料信息发送给他人。"</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"修改您自己的名片"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"允许该应用更改或添加您设备上存储的个人资料信息,例如您的姓名和联系信息。这意味着该应用可以识别您的身份,并可能将您的个人资料信息发送给他人。"</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"人体传感器(如心跳速率检测器)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"允许应用访问您用于测量身体状况(如心跳速率)的传感器中的数据。"</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"读取您的社交信息流"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"允许该应用访问并同步您和朋友的社交动态信息。在分享信息时一定要小心,因为此权限可让该应用读取您与社交网络上的朋友之间的交流信息。"</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"写入您的社交信息流"</string>
@@ -494,9 +479,9 @@
     <string name="permlab_installLocationProvider" msgid="6578101199825193873">"允许安装位置信息提供程序"</string>
     <string name="permdesc_installLocationProvider" msgid="9066146120470591509">"创建用于测试的模拟位置源或安装新的位置提供程序。此权限可让该应用覆盖由其他位置源(如 GPS)或位置提供程序返回的位置和/或状态信息。"</string>
     <string name="permlab_accessFineLocation" msgid="1191898061965273372">"精确位置(基于 GPS 和网络)"</string>
-    <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"允许该应用通过全球定位系统(GPS)或网络位置信息源(例如基站和WLAN)获取您的精确位置信息。您必须在设备上开启这些位置信息服务,应用才能获得位置信息。应用会使用此类服务确定您的位置,这可能会消耗更多电量。"</string>
+    <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"允许该应用通过全球定位系统 (GPS) 或网络位置信息源(例如基站和 WLAN)获取您的精确位置信息。您必须在设备上开启这些位置服务,应用才能获得位置信息。应用会使用此类服务确定您的位置,这可能会消耗更多电量。"</string>
     <string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"大致位置(基于网络)"</string>
-    <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"允许该应用获取您的大致位置信息。这类位置信息来自于使用网络位置信息源(例如基站和WLAN)的位置信息服务。您必须在设备上开启这些位置信息服务,应用才能获得位置信息。应用会使用此类服务确定您的大概位置。"</string>
+    <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"允许该应用获取您的大致位置信息。这类位置信息来自于使用网络位置信息源(例如基站和 WLAN)的位置服务。您必须在设备上开启这些位置服务,应用才能获得位置信息。应用会使用此类服务确定您的大概位置。"</string>
     <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"访问 SurfaceFlinger"</string>
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"允许应用使用 SurfaceFlinger 低级功能。"</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"读取帧缓冲区"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"允许应用控制设备的电话功能。拥有此权限的应用可在不通知您的情况下执行切换网络、开关手机无线装置等此类操作。"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"读取手机状态和身份"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"允许该应用访问设备的电话功能。此权限可让该应用确定本机号码和设备 ID、是否正处于通话状态以及拨打的号码。"</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"读取确切的手机状态"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"允许应用获取确切的手机状态。此权限可让应用确定实际通话状态、通话是在界面上进行还是在后台进行、通话未接通情况、确切的数据网络连接状态,以及数据网络连接失败情况。"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"阻止平板电脑进入休眠状态"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"防止手机休眠"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"允许应用阻止平板电脑进入休眠状态。"</string>
@@ -613,8 +596,8 @@
     <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"允许该应用获取手机已知的帐户列表,其中可能包括由已安装的应用创建的所有帐户。"</string>
     <string name="permlab_authenticateAccounts" msgid="5265908481172736933">"创建帐户并设置密码"</string>
     <string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"允许应用使用 AccountManager 的帐户身份验证程序功能,包括创建帐户以及获取和设置其密码。"</string>
-    <string name="permlab_manageAccounts" msgid="4983126304757177305">"添加或移除帐户"</string>
-    <string name="permdesc_manageAccounts" msgid="8698295625488292506">"允许应用执行添加帐户、移除帐户、删除帐户密码等操作。"</string>
+    <string name="permlab_manageAccounts" msgid="4983126304757177305">"添加或删除帐户"</string>
+    <string name="permdesc_manageAccounts" msgid="8698295625488292506">"允许应用执行添加帐户、删除帐户、删除帐户密码等操作。"</string>
     <string name="permlab_useCredentials" msgid="235481396163877642">"使用设备上的帐户"</string>
     <string name="permdesc_useCredentials" msgid="7984227147403346422">"允许应用请求身份验证令牌。"</string>
     <string name="permlab_accessNetworkState" msgid="4951027964348974773">"查看网络连接"</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"更改 WiMAX 状态"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"允许该应用建立和断开平板电脑与 WiMAX 网络之间的连接。"</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"允许该应用建立和断开手机与 WiMAX 网络之间的连接。"</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"为网络评分"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"允许应用为网络评分,并控制平板电脑应优先使用的网络。"</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"允许应用为网络评分,并控制手机应优先使用的网络。"</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"与蓝牙设备配对"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"允许该应用查看平板电脑上的蓝牙配置,以及建立和接受与配对设备的连接。"</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"允许该应用查看手机上的蓝牙配置,以及建立和接受与配对设备的连接。"</string>
@@ -703,18 +683,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"允许该应用检索、检查并清除通知,包括其他应用发布的通知。"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"绑定到通知侦听器服务"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允许应用绑定到通知侦听器服务的顶级接口(普通应用绝不需要此权限)。"</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"调用运营商提供的配置应用"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允许应用调用运营商提供的配置应用。普通应用绝不需要此权限。"</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"监听网络状况的观测信息"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"允许应用监听网络状况的观测信息。普通应用绝不需要此权限。"</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"更改输入设备校准设置"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"允许应用修改触摸屏的校准参数。普通应用绝不需要此权限。"</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"访问DRM证书"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"允许应用配置和使用DRM证书。普通应用绝不需要此权限。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"设置密码规则"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制屏幕解锁密码所允许的长度和字符。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"监视屏幕解锁尝试次数"</string>
@@ -1154,7 +1126,7 @@
     <string name="no" msgid="5141531044935541497">"取消"</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_on" msgid="1544682755514494298">"打开"</string>
     <string name="capital_off" msgid="6815870386972805832">"关闭"</string>
     <string name="whichApplication" msgid="4533185947064773386">"选择要使用的应用:"</string>
     <string name="whichHomeApplication" msgid="4616420172727326782">"选择主屏幕应用"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"允许应用访问密钥保护安全存储空间。"</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>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"绑定至信任的代理服务"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"允许应用绑定至信任的代理服务。"</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"与更新和恢复系统互动"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"允许应用与恢复系统和系统更新互动。"</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"触摸两次可进行缩放控制"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"壁纸"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"更改壁纸"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"通知侦听器"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN 已激活"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"“<xliff:g id="APP">%s</xliff:g>”已激活 VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"触摸可管理网络。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index d78f298..90632f0 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Google Sync"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"同時刪除太多 <xliff:g id="CONTENT_TYPE">%s</xliff:g>。"</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"平板電腦的儲存空間已滿。請刪除一些檔案,以騰出可用空間。"</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"手錶的儲存空間已滿。請刪除一些檔案,以騰出可用空間。"</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"手機的儲存空間已滿。請刪除一些檔案,以騰出可用空間。"</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"網絡可能會受到監控"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"由不明的第三方監管"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"鈴聲開啟"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"正在關機..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"您的平板電腦將會關機。"</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"您的手錶即將關機。"</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"您的手機即將關機。"</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"您要關機嗎?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"重新啟動進入安全模式"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"飛行模式"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"解除安裝捷徑"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"允許應用程式繞過用戶授權直接移除主畫面捷徑。"</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"重新設定撥出電話的路徑"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"允許應用程式在撥出電話時查看所撥打的電話號碼,並選擇將電話重新導向至另一個號碼或完全中斷通話。"</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"允許應用程式處理撥出電話及更改撥打的號碼。這項權限允許應用程式監控、轉接或阻止撥出的電話。"</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"接收短訊 (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"允許應用程式接收和處理短訊。這表示應用程式可監控傳送至您裝置的訊息,或在您閱讀訊息前擅自刪除訊息。"</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"接收短訊 (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"允許應用程式擷取使用中的視窗內容。惡意應用程式可能會擷取整個視窗的內容,以及檢視密碼除外的所有文字。"</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"暫時啟用協助工具"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"允許應用程式在裝置上暫時啟用協助工具。惡意應用程式可能藉此在未經用戶同意的情況下擅自啟用協助工具。"</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"擷取視窗憑證"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"允許應用程式擷取視窗憑證。惡意應用程式可能會在未經授權的情況下,與冒充系統的應用程式視窗互動。"</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"擷取畫格統計資料"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"允許應用程式收集畫格統計資料。惡意應用程式可能會透過其他應用程式監察視窗畫格統計資料。"</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"擷取視窗資訊"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"允許應用程式從視窗管理程式擷取視窗的相關資訊。惡意應用程式可能會擷取專供內部系統使用的資訊。"</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"篩選活動"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"允許應用程式註冊輸入篩選器,在分派所有用戶活動的串流前先行篩選。惡意應用程式可能會繞過用戶操作,直接控制系統用戶介面。"</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"放大畫面"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"允許應用程式放大畫面內容。惡意應用程式可能會改變顯示內容,導致裝置失靈。"</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"部分關機"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"讓活動管理員進入關機狀態,而不執行完整的關機程序。"</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"防止切換應用程式"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"允許應用程式在收到短訊時發出通知。惡意應用程式可能會藉此偽造外來短訊。"</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"傳送可由 WAP PUSH 接收的廣播"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"允許應用程式在收到 WAP PUSH 訊息時發送通知。惡意應用程式可能會藉此偽造 MMS 訊息回條或私自以惡意內容更換網頁。"</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"傳送網絡計分廣播"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"允許應用程式廣播網絡需要計分的通知,但一般應用程式並不需要使用。"</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"執行程序數目上限"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"允許應用程式控制可執行程序的數量上限 (不建議一般應用程式使用)。"</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"強制關閉背景應用程式"</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"允許應用程式繫結至 VPN 服務的頂層介面 (不建議一般應用程式使用)。"</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"繫結至桌布"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允許應用程式繫結至桌布的頂層介面 (不建議一般應用程式使用)。"</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"繫結至遠端螢幕"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允許應用程式使用任何已安裝的媒體解碼器為播放解碼。"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理信任的憑證"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允許應用程式安裝 CA 憑證為信任的憑證及解除安裝 CA 憑證。"</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"當裝置閒置時執行應用程式"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"當您不使用裝置時,此權限允許 Android 系統在背景執行應用程式。"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"繫結至閒置服務"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"此權限允許 Android 系統繫結至應用程式的閒置服務。"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"讀取/寫入由診斷應用程式擁有的資源"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"允許應用程式讀取及寫入診斷群組所擁有的任何資源 (例如:位於 /dev 中的檔案)。這可能會影響系統的穩定性及安全性,只應對製造商或網絡供應商所使用的硬件專用診斷程式開放這項權限。"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"啟用或停用應用程式元件"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"允許應用程式讀取裝置上儲存的個人資料,例如您的姓名和聯絡資訊。這表示應用程式可以識別您的身份,並將您的個人資料傳送給他人。"</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"修改自己的聯絡資料"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"允許應用程式新增或更改裝置上儲存的個人資料,例如您的姓名和聯絡資訊。這表示應用程式可以識別您的身份,並將您的個人資料傳送給他人。"</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"身體感應器 (例如心跳監視器)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"允許應用程式存取用於測量身體狀況感應器的資料,例如心跳。"</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"讀取您的社交串流"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"允許應用程式存取並同步處理您和好友的最新動態。當您分享資訊時,請務必小心,因為這項權限允許應用程式讀取您和好友在社交網絡上的私人通訊,不論是否機密。注意:這項權限可能不適用於所有社交網絡。"</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"寫入您的社交串流"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"允許應用程式控制裝置上的電話功能。具備此權限的應用程式可在未通知您的情況下,進行切換網絡以及開關手機無線電之類的操作。"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"讀取手機狀態和識別碼"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"允許應用程式使用裝置的電話功能。這項權限允許應用程式確定手機號碼和裝置編號、是否正在通話中,以及所撥打的對方號碼。"</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"讀取精確的手機狀態"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"允許應用程式存取精確的手機狀態。此權限可讓應用程式判斷實際的通話狀態、是否正在通話或在背景中運作、無法通話次數、精確的數據連線狀態和數據連線失敗次數。"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"防止平板電腦進入休眠狀態"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"防止手機進入休眠狀態"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"允許應用程式防止平板電腦進入休眠狀態。"</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"更改 WiMAX 狀態"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"允許應用程式建立或中斷平板電腦與 WiMAX 網絡的連線。"</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"允許應用程式建立或中斷手機與 WiMAX 網絡的連線。"</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"為網絡計分"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"允許應用程式為網絡排名,及決定平板電腦偏好使用的網絡。"</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"允許應用程式為網絡排名,及決定手機偏好使用的網絡。"</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"與藍牙裝置配對"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"允許應用程式查看平板電腦的藍牙設定,以及建立和接受與其他配對裝置的連線。"</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"允許應用程式查看手機的藍牙設定,以及建立和接受與其他配對裝置的連線。"</string>
@@ -703,18 +685,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"允許應用程式擷取、檢查及清除通知 (包括由其他應用程式發佈的通知)。"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"繫結至通知接聽器服務"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允許應用程式繫結至通知接聽器服務的頂層介面 (不建議一般應用程式使用)。"</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"調用流動網絡供應商提供的設定應用程式"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允許應用程式調用流動網絡供應商提供的設定應用程式 (不建議一般應用程式使用)。"</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"監聽對網絡狀況的觀察"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"允許應用程式監聽對網絡狀況的觀察 (不建議一般應用程式使用)。"</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"變更輸入裝置校正設定"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"允許應用程式修改觸控式螢幕的校正參數,而一般應用程式並不需要作出類似修改。"</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"存取 DRM 憑證"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"允許應用程式準備和使用 DRM 憑證,但一般應用程式並不需要使用。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制屏幕解鎖密碼所允許的長度和字元。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"監控屏幕解鎖嘗試次數"</string>
@@ -989,7 +963,7 @@
     <string name="permlab_setAlarm" msgid="1379294556362091814">"設定鬧鐘"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"允許應用程式在安裝的鬧鐘應用程式中設定鬧鐘,某些鬧鐘應用程式可能沒有這項功能。"</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"新增留言"</string>
-    <string name="permdesc_addVoicemail" msgid="6604508651428252437">"允許應用程式將訊息加到您的留言信箱收件箱。"</string>
+    <string name="permdesc_addVoicemail" msgid="6604508651428252437">"允許應用程式將訊息加到您的留言信箱收件匣。"</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"修改瀏覽器地理資訊的權限"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"允許應用程式修改瀏覽器的地理資訊權限。惡意應用程式可能會藉此允許將您的位置資訊任意傳送給某些網站。"</string>
     <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"驗證套件"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"允許應用程式存取 Keyguard 安全儲存空間。"</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>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"繫結至信任的代理程式服務"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"允許應用程式繫結至信任的代理程式服務。"</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"與更新和復原系統互動"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"允許應用程式與復原系統和系統更新互動。"</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"輕觸兩下即可控制縮放"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"桌布"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"變更桌布"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"通知接聽器"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN 已啟用。"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> 已啟用 VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"輕觸即可管理網絡。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 38a487b..6c3f1c4 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"同步處理"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"同時刪除太多 <xliff:g id="CONTENT_TYPE">%s</xliff:g>。"</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"平板電腦的儲存空間已滿。請刪除一些檔案,以釋放出可用空間。"</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"手錶儲存空間已用盡,請刪除一些檔案以釋出可用空間。"</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"手機儲存空間已滿。請刪除一些檔案,以釋放可用空間。"</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"網路可能會受到監控"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"受到不明的第三方監控"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"鈴聲開啟"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"關機中…"</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"您的平板電腦將會關機。"</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"您的手錶即將關機。"</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"手機即將關機。"</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"您要關機嗎?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"重新啟動進入安全模式"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"飛航模式"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"超過 999"</string>
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"解除安裝捷徑"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"允許應用程式自動移除主螢幕捷徑。"</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"重設撥號路徑"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"允許應用程式在撥打電話期間查看撥出的電話號碼,並可選擇改撥其他號碼或中斷通話。"</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"允許應用程式處理撥出電話及更改撥打的號碼。這項權限可讓應用程式監控、轉接或阻止撥出的電話。"</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"接收簡訊 (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"允許應用程式接收和處理簡訊。這項設定可讓應用程式監控傳送至您裝置的訊息,或在您閱讀訊息前擅自刪除訊息。"</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"接收簡訊 (MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"允許應用程式擷取使用中的視窗內容。請注意,惡意應用程式可能利用此功能擷取完整視窗內容,並檢視密碼之外的所有文字。"</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"暫時啟用協助工具"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"允許應用程式在裝置上暫時啟用協助工具。惡意應用程式可能藉此在未經使用者同意的情況下擅自啟用協助工具。"</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"擷取視窗符記"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"允許應用程式擷取視窗符記。惡意應用程式可能會藉此在未經授權的情況下與模擬系統的應用程式視窗互動。"</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"擷取畫格統計資料"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"允許應用程式收集畫格統計資料。惡意應用程式可能會藉此得知其他應用程式的視窗畫格統計資料。"</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"擷取視窗資訊"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"允許應用程式透過視窗管理程式擷取視窗的相關資訊。請注意,惡意應用程式可能藉此擷取僅限內部系統使用的資訊。"</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"篩選活動"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"允許應用程式註冊輸入篩選器,在分派所有使用者活動的串流前先行篩選。請注意,惡意應用程式可能藉此擅自控制系統使用者介面。"</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"放大畫面"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"允許應用程式放大畫面內容。請注意,惡意應用程式可能會藉此利用不正常的方式改變顯示內容,導致裝置失靈。"</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"部分關機"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"讓活動管理員進入關機狀態,而不執行完整的關機程序。"</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"防止切換應用程式"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"允許應用程式在收到 SMS 簡訊時發出通知。請注意,惡意應用程式可能利用此功能偽造外來的 SMS 簡訊。"</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"送出「WAP PUSH 已接收」廣播"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"允許應用程式在收到 WAP PUSH 訊息時發送通知。請注意,惡意應用程式可能利用此功能偽造 MMS 簡訊回條,或私自將網頁內容更換為惡意陷阱。"</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"傳送網路計分廣播通知"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"允許應用程式廣播「網路需計分」的通知訊息 (一般應用程式並不需要)。"</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"執行程序限制數"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"允許應用程式控制可執行程序的數量上限 (一般應用程式不需使用)。"</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"強制關閉背景應用程式"</string>
@@ -387,20 +382,12 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"允許應用程式聯繫至 VPN 服務的頂層介面 (一般應用程式不需使用)。"</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"連結至桌布"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允許應用程式繫結至桌布的頂層介面 (一般應用程式不需使用)。"</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"繫結至遠端螢幕"</string>
     <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>
-    <string name="permdesc_bindTvInput" msgid="2371008331852001924">"允許應用程式繫結至電視訊號輸入裝置的頂層介面 (一般應用程式並不需要)。"</string>
     <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"新增或移除裝置管理員"</string>
     <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"允許應用程式新增或移除有效的裝置管理員 (一般應用程式並不需要)。"</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"變更螢幕顯示方向"</string>
@@ -436,8 +423,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允許應用程式使用任何已安裝的媒體解碼器進行解碼以播放影片。"</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理信任的憑證"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允許應用程式安裝 CA 憑證 (做為信任的憑證) 及解除安裝 CA 憑證。"</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"當裝置閒置時執行應用程式"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"當裝置處於未使用狀態時,此權限允許 Android 系統在背景執行應用程式。"</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"繫結至閒置服務"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"此權限允許 Android 系統繫結至應用程式的閒置服務。"</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"讀寫 diag 擁有的資源"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"允許應用程式讀取或寫入診斷群組擁有的任何資源,例如 /dev 底下的檔案。這可能會影響系統的穩定性和安全性,因此應由製造商或電信業者操作,且只用在特定硬體診斷。"</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"啟用或停用應用程式元件"</string>
@@ -475,8 +462,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"允許應用程式讀取裝置上儲存的個人資料,例如您的姓名和聯絡資訊。這表示應用程式可以識別您的身分,並將您的個人資料傳送給他人。"</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"修改自己的聯絡資訊"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"允許應用程式新增或變更裝置上儲存的個人資料,例如您的姓名和聯絡資訊。這項設定可讓應用程式識別您的身分,並可能將您的個人資料傳送給他人。"</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"身體感應器 (例如心律監測器)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"允許應用程式存取感應器從您的身體測得的資料,例如心跳頻率。"</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"讀取您的社交串流"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"允許應用程式存取並同步處理您和好友的最新動態。因此,當您分享資訊時請小心,因為這項權限可讓應用程式讀取您和好友在社交網路上的私人通訊,包括機密通訊。注意:並非所有社交網路皆適用於這項權限。"</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"寫入您的社交串流"</string>
@@ -578,8 +563,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"允許應用程式控制裝置的電話功能。擁有這項權限的應用程式可在未通知您的情況下,任意切換網路、開啟或關閉手機無線電等。"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"讀取手機狀態和識別碼"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"允許應用程式使用裝置的電話功能。這項權限可讓應用程式判讀手機號碼和裝置 ID、是否正在通話中,以及所撥打的對方號碼。"</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"讀取手機精確狀態"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"允許應用程式存取手機的精確狀態。這項權限可讓應用程式判別實際通話狀態,包括通話正在進行中或是在背景運作、通話失敗次數、精確數據連線狀態和數據連線失敗次數。"</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"防止平板電腦進入休眠狀態"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"防止手機進入待命狀態"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"允許應用程式防止平板電腦進入休眠狀態。"</string>
@@ -647,9 +630,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"變更 WiMAX 狀態"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"允許應用程式建立或中斷平板電腦與 WiMAX 網路的連線。"</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"允許應用程式建立或中斷手機與 WiMAX 網路的連線。"</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"為網路計分"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"允許應用程式建立網路排名,決定平板電腦偏好使用的網路。"</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"允許應用程式建立網路排名,決定手機偏好使用的網路。"</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"與藍牙裝置配對"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"允許應用程式查看平板電腦的藍牙設定,以及建立和接受與其他配對裝置的連線。"</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"允許應用程式查看手機的藍牙設定,以及建立和接受與其他配對裝置的連線。"</string>
@@ -703,18 +683,10 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"允許應用程式擷取、檢查及清除通知 (包括由其他應用程式發佈的通知)。"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"繫結至通知接聽器服務"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允許應用程式繫結至通知接聽器服務的頂層介面 (一般應用程式不需使用)。"</string>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"叫用行動通訊業者提供的設定應用程式"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允許應用程式叫用行動通訊業者提供的設定應用程式 (一般應用程式並不需要)。"</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"監聽網路狀況觀察資訊"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"允許應用程式監聽網路狀況觀察資訊 (一般應用程式並不需要)。"</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"變更輸入裝置校正設定"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"允許應用程式修改觸控螢幕的校正參數 (一般應用程式並不需要)。"</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"存取 DRM 憑證"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"允許應用程式佈建及使用 DRM 憑證 (一般應用程式並不需要)。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制螢幕解鎖密碼所允許的長度和字元。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"監視螢幕解鎖嘗試次數"</string>
@@ -1164,7 +1136,7 @@
     <string name="chooseUsbActivity" msgid="6894748416073583509">"選取要以 USB 裝置存取的應用程式"</string>
     <string name="noApplications" msgid="2991814273936504689">"沒有應用程式可執行這項操作。"</string>
     <string name="aerr_title" msgid="1905800560317137752"></string>
-    <string name="aerr_application" msgid="932628488013092776">"很抱歉,<xliff:g id="APPLICATION">%1$s</xliff:g>已停止運作。"</string>
+    <string name="aerr_application" msgid="932628488013092776">"很抱歉,<xliff:g id="APPLICATION">%1$s</xliff:g> 已停止。"</string>
     <string name="aerr_process" msgid="4507058997035697579">"很抱歉,處理程序 <xliff:g id="PROCESS">%1$s</xliff:g> 已停止。"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
     <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> 沒有回應。\n\n您要結束嗎?"</string>
@@ -1347,10 +1319,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"允許應用程式存取 Keyguard 安全儲存空間。"</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>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"繫結至信任的代理程式服務"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"允許應用程式繫結至信任的代理程式服務。"</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"與更新和還原系統互動"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"允許應用程式與還原系統及系統更新互動。"</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"輕觸兩下即可控制縮放"</string>
@@ -1377,8 +1345,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"桌布"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"變更桌布"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"通知接聽器"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN 已啟用"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> 已啟用 VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"輕觸即可管理網路。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index ede3d3c..342d7c1 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -135,7 +135,6 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Vumelanisa"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Kunokususa <xliff:g id="CONTENT_TYPE">%s</xliff:g> okuningi kakhulu."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Isilondolozi sethebhulethi sigcwele! Susa amanye amafayela ukukhulula isikhala."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Isitoreji sokubuka sigcwele. Susa amanye amafayela ukukhulula isikhala."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Isilondolozi sefoni sigcwele! Susa amanye amafayela ukukhulula isikhala."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Inethiwekhi ingase inganyelwe"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Ngenkampani yangaphandle engaziwa"</string>
@@ -153,7 +152,6 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Iringa iyasebenza"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Ivala shaqa..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Ithebhulethi yakho izocima."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Ukubuka kwakho kuzocima."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Ifoni yakho izocima."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Ingabe ufuna ukucisha?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Qala kabusha emodini ephephile"</string>
@@ -173,7 +171,6 @@
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Imodi yendiza"</string>
     <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="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Imodi ephephile"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Uhlelo lwe-Android"</string>
@@ -259,7 +256,7 @@
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"khipha izinqamuleli"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Ivumela uhlelo lokusebenza ukususa izinqamuleli zesikrini sasekhaya ngaphandle kokungenela komsebenzisi."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"thumela amakholi aphumayo kabusha"</string>
-    <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Ivumela uhlelo lokusebenza ukubona inombolo eshayelwayo ngesikhathi sekholi ephumayo ngenketho yokuqondisa kabusha ikholi kwinombolo ehlukile noma ukuyekisa ikholi yonke."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Ivumela uhlelo lokusebenza ukucubungula amakholi aphumayo futhi ishintshe inombolo ezoshayelwa. Le mvume ivumela uhlelo lokusebenza ukwengamela, liqondise kabusha, noma livikele amakholi aphumayo."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"thola imiyalezo ebhaliwe (i-SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Ivumela uhlelo lokusebenza ukuthola nokucubungula imilayezo ye-SMS. Loku kuchaza ukuthi uhlelo lokusebenza lungangamela noma lesuse imilayezo ethunyelwe kudivayisi yakho ngaphandle kokukubonisa yona."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"thola imiyalezo ebhaliwe (i-MMS)"</string>
@@ -318,12 +315,12 @@
     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Ivumela uhlelo lokusebenza ukuthi ithole okuqukethe kwi-Window. Izuhlelo lokusebenza ezinobungozi zingathola kabush iwindi eliphelele bese ibheka konke okuqukethwe ngaphandle kwaaaphasiwedi."</string>
     <string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"nika amandla okwesikhashana ukufinyelela"</string>
     <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Ivumela uhlelo lokusebenza ukunika amandla ukufinyelela kwesikhashana kuvidayisi. Izinhlelo zokusebenza ezingalungile zinganika amandla ukufinyelela ngaphandle kwemvume yomsebenzisi."</string>
-    <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"buyisa ithokheni yewindi"</string>
-    <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Ivumela uhlelo lokusebenza ukuletha ithokheni yewindi. Izinhlelo zokusebenza ezinonya zingenza izenzo ezingagunyaziwe ngewindi lohlelo lokusebenza lizenze isistimu."</string>
-    <string name="permlab_frameStats" msgid="7056374987314361639">"buyisa izibalo zefreyimu"</string>
-    <string name="permdesc_frameStats" msgid="4758001089491284919">"Ivumela uhlelo lokusebenza ukuthi luqoqe izibalo zefreyimu. Izinhlelo zokusebenza ezinonya zingabona izibalo zefreyimu zamawindi kusuka kwezinye izinhlelo zokusebenza."</string>
+    <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"buyisa ulwazi lewindi"</string>
+    <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Ivumela uhlelo lokusebenza ukubuyisa ulwazi mayelana namawindi avela kumphathi wewindi. Izinhlelo zokusebenza zingabuyisa ulwazi olubhekiswe ukusetshenziselwa kohlelo lwangaphakathi."</string>
     <string name="permlab_filter_events" msgid="8675535648807427389">"hlunga imicimbi"</string>
     <string name="permdesc_filter_events" msgid="8006236315888347680">"Ivumela uhlelo lokusebenza ukubhalisa isihlungi sokufaka ukusakaza kwazo zonke izehlakalo zomsebenzisi ngaphambi kokuthunyelwa. Izinhlelo zokusebenza zingalawula i-UI yohlelo ngaphandle kokungena komsebenzisi."</string>
+    <string name="permlab_magnify_display" msgid="5973626738170618775">"lungisa ukubuka"</string>
+    <string name="permdesc_magnify_display" msgid="7121235684515003792">"Ivumela uhlelo lokusebenza ukusondeza okuqukethwe kokubukwa. Izinhlelo zokusebenza ezingalungile zidlulisela okuqukethwe kokubuka ngendlela eyenza idivayisi ingasebenziseki."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"ukuvala shaqa kwengxenye"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Ibeka imeneja yomsebenzi kwisimo sokuvala shaqa. Ayenzi ukuvala shaqa okuphelele."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"gwema ukushintsha kohlelo lokusebenza"</string>
@@ -338,8 +335,6 @@
     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Ivumela uhlelo lokusebenza ukuthi isakaze isaziso sokuthi umyalezo we-SMS utholakele. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukufoja imiyalezo ye-SMS engenayo."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"thumela umsakazo otholwe nge-WAP-PUSH"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Ivumela uhlelo lokusebenza ukuthi isakaze isaziso sokuthi umyalezo we-WAP PUSH utholakele. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukufoja ukutholakala kwemiyalezo ye-S noma zisuse okuqukethwe kwanoma iliphi ikhasi lewebhu eliqukethe okunobungozi."</string>
-    <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"thumela ukusakaza kwamanethiwekhi ayisikolo"</string>
-    <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Ivumela uhlelo lokusebenza ukusakaza isaziso sokuthi amanethiwekhi adinga isikolo. Awadingeki kuzinhlelo zokusebenza ezivamile."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"khawula inani lezinqubo ezisebenzayo"</string>
     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Ivumela uhlelo lokusebenza ukuthi ilawule isibalo esikhulu sezinto eziqhubekayo eziyosebenza. Ayidingakeli izinhlelo zokusebenza ezijwayelekile."</string>
     <string name="permlab_setAlwaysFinish" msgid="550958507798796965">"phoqa izinhlelo zokusebenza ezingemuva ukuthi zivaleke"</string>
@@ -387,16 +382,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Ivumela umnini ukuthi abophele kwissekelo esingaphezulu sesevisi ye-Vpm. Ayidingakeli izinhlelo zokusebenza ezejwayelekile."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"hlanganisa kwiphephadonga"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lwephephadonga. Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
-    <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
-    <skip />
-    <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
-    <skip />
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bophezela kusibonisi sesilawuli kude"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ivumela umbambi ukuhlanganisa isixhumi esibonakalayo esisezingeni eliphezulu sesibonisi sesilawuli kude. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bophezela kube isevisi yesinqunjana"</string>
     <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>
@@ -436,8 +425,8 @@
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ivumela uhlelo lokusebenza ukusebenzisa noma isiphi isiqophi semidiya esifakiwe ukuqopha ukudlala."</string>
     <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"phatha ukuqinisekisa okuthenjiwe"</string>
     <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ivumela uhlelo lokusebenza ukuthi lifake liphinde likhiphe izitifiketi ze-CA njengokuqinisekiswa okuthenjiwe."</string>
-    <string name="permlab_bindIdleService" msgid="816311765497613780">"qalisa uhlelo lokusebenza ngesikhathi sokungenzi lutho"</string>
-    <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Le mvume ivumela isistimu ye-Android ukuthi iqalise uhlelo lokusebenza ngemuva ngenkathi idivayisi ingasebenzi."</string>
+    <string name="permlab_bindIdleService" msgid="7521398788076342815">"bophezela kumasevisi angenzi lutho"</string>
+    <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Le mvume ivumela isistimu ye-Android ukuthi ibophezeleke kumasevisi angenzi lutho wohlelo lokusebenza."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"funda/bhalela emithombweni ephethwe idayegi"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Ivumela uhlelo lokusebenza ukufunda nokubhala kunoma yimuphi umthombo weqembu ledayegi; ngokwesibonelo, amafayela akwi/dev. Lokhu kungase kuthinte kakhulu ukuba nokuphepha kohlelo. Lokhu kumele kusebenziselwe KUPHELA ukuhlola ihadiwe okucacile ngumkhiqizi noma u-opheretha."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"vumela noma vimbela izingxenye zensiza"</string>
@@ -475,8 +464,6 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Ivumela uhlelo lokusebenza ukuthi lifunde ulwazi lephrofayela lomuntu siqu olugcinwe kudivayisi yakho njengegama lakho kanye nolwazi lokuxhumana. Lokhu kuchaza ukuthi uhlelo lokusebenza lingakuhlonza bese lithumelela abanye ulwazi lakho lephrofayela."</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"guqula ikhadi lakho lokuxhumana"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Ivumela uhlelo lokusebenza ukushintsha noma ingeze ulwazi lomuntu siqu lwephrofayela olulondolozwe kudivayisi yakho, njengegama lakho kanye nolwazi lokuxhumana. Lokhu kuchaza ukuthi ezinye izinhlelo zokusebenza zingakuhlonza bese zithumelela abanye ulwazi lephrofayela yakho."</string>
-    <string name="permlab_bodySensors" msgid="4871091374767171066">"izinzwa zomzimba (njengeziqaphi zokulinganisela inhliziyo)"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Ivumela uhlelo lokusebenza ukuze lufinyelele kudatha esuka kuzinzwa ozisebenzisayo ukuze lulinganise ukuthi kwenzakalani phakathi komzimba wakho, njengokulinganisela kwenhliziyo."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"funda ngezindlela zakho zokuxhumana nabanye abantu"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Ivumela uhlelo lokusebenza ukufinyelela nokuvumelanisa izibuyekezo zomphakathi ezivela kuwe nakubangani bakho. Qaphela uma waba ulwazi -- lokhu kuvumela uhlelo lokusebenza ukufunda ukuxhumana phakathi kwakho nabangani bakho kumanethiwekhi omphakathi, ngaphandle kokugcinwa kuyimfihlo. Qaphela: le mvume ingaphoqelelwa kuwo onke amanethiwekhi omphakathi."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"bhala indlela yakho yokuxhumana nabantu"</string>
@@ -578,8 +565,6 @@
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Ivumela ukuthi uhlelo lokusebenza ilawule okuqukethwe ocingweni edivayisini. Insiza enalemvume ingaguquguqula amanethwekhi, ivule umsakazo wocingo iphinde iwucishe kanye nokunye okufana nalokho ngaphandle kokukwazisa."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"funda isimo sefoni kanye nesazisi"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Ivumela uhlelo lokusebenza ukufinyelela izici zefoni zedivayisi. Le mvume ivumela uhlelo lokusebenza ukucacisa inombolo yefoni nobunikazi bedivayisi, ukuthi noma ikholi iyasebenza, futhi nenombolo yesilawuli kude zixhunywe ngekholi."</string>
-    <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"funda izimo zefoni ezinembile"</string>
-    <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Ivumelanisa uhlelo lokusebenza ukuthi lufinyelele kuzimo ezinembile zefoni. Le mvume ivumela uhlelo lokusebenza ukuthi linqume isimo sekholi sangempela, noma ikholi isebenza noma ingemuva, ikholi ihluleka, isimo esinembile sokuxhumeka kwedatha nokuhluleka kokuxhumeka kwedatha."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"gwema ithebhulethi ukuba ingalali"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"gwema ifoni ukuba ingalali"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Ivumela uhlelo lokusebenza ukuthi linqande ithebulethi yakho ukuthi ilale."</string>
@@ -647,9 +632,6 @@
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Shintsha isimo se-WiMAX"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Ivumela uhlelo lokusebenza ukuxhuma ithebhulethi nokunqamula ithebhulethi kumanethiwekhi e-WiMAX."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Ivumela uhlelo lokusebenza ukuxhuma ifoni nokuyinqamula kumanethiwekhi e-WiMAX."</string>
-    <string name="permlab_scoreNetworks" msgid="6445777779383587181">"amanethiwekhi ayisikolo"</string>
-    <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Ivumela uhlelo lokusebenza ukuthi lilinganise amanethiwekhi futhi lithuthukise ukuthi imaphi amanethiwekhi ithebhulethi okufanele iwakhethe."</string>
-    <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Ivumela uhlelo lokusebenza ukuthi lilinganise amanethiwekhi futhi lithuthukise ukuthi imaphi amanethiwekhi ifoni okufanele iwakhethe."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"matanisa namadivayisi e-Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Ivumela uhlelo lokusebenza ukubuka ukucushwa kwe-Bluetooth kuthebhulethi, nokwenza futhi nokwamukela uxhumo namadivayisi amatanisiwe."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Ivumela uhlelo lokusebenza ukubuka ukucushwa kwe-Bluetooth efonini, ukwenza futhi nokwamukela uxhumo namadivayisi amatanisiwe."</string>
@@ -703,18 +685,10 @@
     <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>
-    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
-    <skip />
-    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
-    <skip />
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"buyisela uhlelo lokusebenza lokulungiselelwa okunikezwe yinkampani yenethiwekhi"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ivumela umnikazi ukuthi abuyisele uhlelo lokusebenza lokulungiselelwa. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Lalela okubonwayo kuzimo zenethiwekhi"</string>
     <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Ivumela uhlelo lokusebenza ukuthi lulalele okubonwa kuzimo zenethiwekhi. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
-    <string name="permlab_setInputCalibration" msgid="4902620118878467615">"guqula ukulinganisa kokufaka kwedivayisi"</string>
-    <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Ivumela uhlelo lokusebenza ukuthi lushintshe imingcele yokulinganisa yesikrini esithintwayo. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
-    <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"finyelela izitifiketi ze-DRM"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Ivumela uhlelo lokusebenza ekunikezweni nokusetshenziswa kwezitifiketi ze-DRM. Akufanele kudingeke 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="policylab_watchLogin" msgid="914130646942199503">"Gaka imizamo yokuvula isikrini"</string>
@@ -824,7 +798,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"i-Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"i-Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Ama-Hangout"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"i-ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"i-Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"Umhlangano we-Net"</string>
@@ -1347,10 +1321,6 @@
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Ivumela uhlelo lokusebenza ukuthi lufinyelele kusitoreji esiqashwa ngesikhiya esiphephile."</string>
     <string name="permlab_control_keyguard" msgid="172195184207828387">"Lawula ukubonisa nokufihla ukhiye wokuqapha"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"Ivumela uhlelo lokusebenza ukuthi lulawule ukhiye wokuqapha."</string>
-    <string name="permlab_trust_listener" msgid="1765718054003704476">"Lalela izinguquko zesimo sokuthemba."</string>
-    <string name="permdesc_trust_listener" msgid="8233895334214716864">"Ivumela uhlelo lokusebenza ukuthi lilalelele izinguquko kusimo sethemba."</string>
-    <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Bophezela kusevisi yomenzeli wethemba"</string>
-    <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ivumela uhlelo lokusebenza ukuthi libophezeleke kusevisi yomenzeli wethemba."</string>
     <string name="permlab_recovery" msgid="3157024487744125846">"Ixhumana nesibuyekezo nesistimu yokutakula"</string>
     <string name="permdesc_recovery" msgid="8511774533266359571">"Ivumela uhlelo lokusebenza ukuthi lixhumane nesistimu yokutakula nezibuyekezo zesistimu."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Thinta kabili ukulawula ukusondeza"</string>
@@ -1377,8 +1347,6 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Iphephadonga"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Shintsha iphephadonga"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Umlaleli wesaziso"</string>
-    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
-    <skip />
     <string name="vpn_title" msgid="19615213552042827">"I-VPN isiyasebenza"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"i-VPN ivuswe ngu <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Thinta ukuze wengamele inethiwekhi."</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index efc1b55..327f6cf 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -721,6 +721,7 @@
         <attr name="actionBarTabBarStyle" format="reference" />
         <attr name="actionBarTabTextStyle" format="reference" />
         <attr name="actionOverflowButtonStyle" format="reference" />
+        <attr name="actionOverflowMenuStyle" format="reference" />
         <!-- Reference to a style for the Action Bar -->
         <attr name="actionBarStyle" format="reference" />
         <!-- Reference to a style for the split Action Bar. This style
@@ -954,19 +955,33 @@
         <!-- ============= -->
         <!-- Color palette -->
         <!-- ============= -->
-        <attr name="colorPrimaryDark" format="color" />
+        <eat-comment />
+
+        <!-- The primary branding color for the app. By default, this is the color applied to the
+             action bar background and framework controls (via colorControlActivated). -->
         <attr name="colorPrimary" format="color" />
+
+        <!-- Dark variant of the primary branding color. By default, this is the color applied to
+             the status bar (via statusBarColor) and navigation bar (via navigationBarColor). -->
+        <attr name="colorPrimaryDark" format="color" />
+
+        <!-- Light variant of the primary branding color. TODO: Not used? -->
         <attr name="colorPrimaryLight" format="color" />
+
+        <!-- Bright complement to the primary branding color. TODO: Not used? -->
         <attr name="colorAccent" format="color" />
 
+        <!-- The color applied to framework controls in their normal state. -->
         <attr name="colorControlNormal" format="color" />
+
+        <!-- The color applied to framework controls in their activated (ex. checked) state. -->
         <attr name="colorControlActivated" format="color" />
 
+        <!-- The color applied to framework buttons in their normal state. -->
         <attr name="colorButtonNormal" format="color" />
-        <attr name="colorButtonPressed" format="color" />
-        <attr name="colorButtonNormalColored" format="color" />
-        <attr name="colorButtonPressedColored" format="color" />
 
+        <!-- The color applied to framework buttons in their pressed state. -->
+        <attr name="colorButtonPressed" format="color" />
     </declare-styleable>
 
     <!-- **************************************************************** -->
@@ -1775,6 +1790,7 @@
         <attr name="bottomMedium" format="reference|color" />
         <attr name="centerMedium" format="reference|color" />
         <attr name="layout" />
+        <attr name="buttonPanelSideLayout" format="reference" />
         <attr name="listLayout" format="reference" />
         <attr name="multiChoiceItemLayout" format="reference" />
         <attr name="singleChoiceItemLayout" format="reference" />
@@ -2355,15 +2371,16 @@
              view with a theme override will inherit the themed context. -->
         <attr name="theme" />
 
-        <!-- Specifies that the shared name of the View to be shared with another Activity.
-             When transitioning between Activities, the name links a UI element in the starting
-             Activity to UI element in the called Activity. Names should be unique in the
-             View hierarchy. -->
-        <attr name="sharedElementName" format="string" />
+        <!-- Names a View such that it can be identified for Transitions. Names should be
+             unique in the View hierarchy. -->
+        <attr name="viewName" format="string" />
 
         <!-- Specifies that this view should permit nested scrolling within a compatible
              ancestor view. -->
         <attr name="nestedScrollingEnabled" format="boolean" />
+
+        <!-- Sets the state-based animator for the View. -->
+        <attr name="stateListAnimator" format="reference"/>
     </declare-styleable>
 
     <!-- Attributes that can be assigned to a tag for a particular View. -->
@@ -3340,6 +3357,8 @@
         <attr name="thumb" format="reference" />
         <!-- An offset for the thumb that allows it to extend out of the range of the track. -->
         <attr name="thumbOffset" format="dimension" />
+        <!-- Whether to split the track and leave a gap for the thumb drawable. -->
+        <attr name="splitTrack" format="boolean" />
     </declare-styleable>
 
     <declare-styleable name="StackView">
@@ -3804,6 +3823,7 @@
     <declare-styleable name="PopupWindow">
         <attr name="popupBackground" format="reference|color" />
         <attr name="popupAnimationStyle" format="reference" />
+        <attr name="overlapAnchor" format="boolean" />
     </declare-styleable>
     <declare-styleable name="ViewAnimator">
         <!-- Identifier for the animation to use when a view is shown. -->
@@ -4235,6 +4255,58 @@
         <attr name="autoMirrored"/>
     </declare-styleable>
 
+    <!-- Drawable used to render several states with animated transitions. Each state
+         is represented by a child drawable with an optional keyframe ID. -->
+    <declare-styleable name="AnimatedStateListDrawable">
+        <!-- Indicates whether the drawable should be initially visible. -->
+        <attr name="visible" />
+        <!-- If true, allows the drawable's padding to change based on the
+             current state that is selected.  If false, the padding will
+             stay the same (based on the maximum padding of all the states).
+             Enabling this feature requires that the owner of the drawable
+             deal with performing layout when the state changes, which is
+             often not supported. -->
+        <attr name="variablePadding" />
+        <!-- If true, the drawable's reported internal size will remain
+             constant as the state changes; the size is the maximum of all
+             of the states.  If false, the size will vary based on the
+             current state. -->
+        <attr name="constantSize" />
+        <!-- Enables or disables dithering of the bitmap if the bitmap does not have the
+             same pixel configuration as the screen (for instance: a ARGB 8888 bitmap with
+             an RGB 565 screen). -->
+        <attr name="dither" />
+        <!-- Amount of time (in milliseconds) to fade in a new state drawable. -->
+        <attr name="enterFadeDuration" />
+        <!-- Amount of time (in milliseconds) to fade out an old state drawable. -->
+        <attr name="exitFadeDuration" />
+        <!-- Indicates if the drawable needs to be mirrored when its layout direction is
+             RTL (right-to-left). -->
+        <attr name="autoMirrored"/>
+    </declare-styleable>
+
+    <!-- Transition used to animate between states with keyframe IDs. -->
+    <declare-styleable name="AnimatedStateListDrawableItem">
+        <!-- Reference to a drawable resource to use for the frame.  If not
+             given, the drawable must be defined by the first child tag. -->
+        <attr name="drawable" />
+        <!-- Keyframe identifier for use in specifying transitions. -->
+        <attr name="id" />
+    </declare-styleable>
+
+    <!-- Transition used to animate between states with keyframe IDs. -->
+    <declare-styleable name="AnimatedStateListDrawableTransition">
+        <!-- Keyframe identifier for the starting state. -->
+        <attr name="fromId" format="reference" />
+        <!-- Keyframe identifier for the ending state. -->
+        <attr name="toId" format="reference" />
+        <!-- Reference to a animation drawable resource to use for the frame.  If not
+             given, the animation drawable must be defined by the first child tag. -->
+        <attr name="drawable" />
+        <!-- Whether this transition is reversible. -->
+        <attr name="reversible" format="boolean" />
+    </declare-styleable>
+
     <!-- Drawable used to render several animated frames. -->
     <declare-styleable name="AnimationDrawable">
         <attr name="visible" />
@@ -4254,6 +4326,11 @@
         <attr name="drawable" format="reference" />
     </declare-styleable>
 
+    <!-- Attributes that can be assigned to a StateListAnimator item. -->
+    <declare-styleable name="StateListAnimatorItem">
+        <attr name="animation"/>
+    </declare-styleable>
+
     <!-- Drawable used to render a geometric shape, with a gradient or a solid color. -->
     <declare-styleable name="GradientDrawable">
         <!-- Indicates whether the drawable should intially be visible. -->
@@ -4651,18 +4728,6 @@
 
     <!-- Drawable used to draw Vector Drawables. -->
     <declare-styleable name="VectorDrawable">
-           <!-- What event triggers the animation -->
-        <attr name="trigger" format="enum">
-            <enum name="state_pressed" value="1" />
-            <enum name="state_focused" value="2" />
-            <enum name="state_hovered" value="3" />
-            <enum name="state_selected" value="4" />
-            <enum name="state_checkable" value="5" />
-            <enum name="state_checked" value="6" />
-            <enum name="state_enabled" value="7" />
-            <enum name="state_activated" value="8" />
-            <enum name="state_window_focused" value="9" />
-        </attr>
         <attr name="versionCode" />
     </declare-styleable>
 
@@ -4682,42 +4747,6 @@
         <attr name="height" />
     </declare-styleable>
 
-    <!-- Define the animations of drawable -->
-    <declare-styleable name="VectorDrawableAnimation">
-        <!-- Configures this animation sequence between the named paths  -->
-        <attr name="sequence" format="string"/>
-        <!-- Limits an animation to only interpolate the selected variable  -->
-        <attr name="limitTo" format="enum">
-            <enum name="unlimited" value="0"/>
-            <enum name="path" value="1"/>
-            <enum name="rotation" value="2"/>
-            <enum name="trimPathStart" value="3"/>
-            <enum name="trimPathEnd" value="4"/>
-            <enum name="trimPathOffset" value="5"/>
-        </attr>
-        <!-- Number of times to loop this aspect of the animation -->
-        <attr name="repeatCount"/>
-        <!-- A list of times in milliseconds to transision from on path to another.
-         List must contain one less than the number of named paths
-         e.g. given sequence="A,B,C,D" durations="100,0,100" implies 100ms for the
-         "A" to "B" transision instantanious switch to "C" and 100ms for "C" to "D". -->
-        <attr name="durations" format="string" />
-        <!-- The delay before stating this aspect of the animation in milli seconds -->
-        <attr name="startDelay" />
-        <!-- when repeating how does it repeat back and forth or a to b -->
-        <attr name="repeatStyle" format="enum">
-            <enum name="forward"  value="0"/>
-            <enum name="reverse"  value="1"/>[]
-        </attr>
-        <!-- how does the animation progress from start to finish -->
-        <attr name="animate" format="enum">
-            <enum name="linear"  value="0"/>
-            <enum name="easeIn"  value="1"/>
-            <enum name="easeOut"  value="2"/>
-            <enum name="easeInOut"  value="3"/>
-        </attr>
-    </declare-styleable>
-
     <!-- Defines the path used in Vector Drawables. -->
     <declare-styleable name="VectorDrawablePath">
         <!-- The Name of this path -->
@@ -4762,26 +4791,6 @@
         </attr>
         <!-- sets the Miter limit for a stroked path -->
         <attr name="strokeMiterLimit" format="float"/>
-        <!-- sets a condition to be met to draw path -->
-        <attr name="state_pressed" />
-        <!-- sets a condition to be met to draw path -->
-        <attr name="state_focused" />
-        <!-- sets a condition to be met to draw path -->
-        <attr name="state_selected" />
-        <!-- sets a condition to be met to draw path -->
-        <attr name="state_window_focused" />
-        <!-- sets a condition to be met to draw path -->
-        <attr name="state_enabled" />
-        <!-- sets a condition to be met to draw path -->
-        <attr name="state_activated" />
-        <!-- sets a condition to be met to draw path -->
-        <attr name="state_accelerated" />
-        <!-- sets a condition to be met to draw path -->
-        <attr name="state_hovered" />
-        <!-- sets a condition to be met to draw path -->
-        <attr name="state_checked" />
-        <!-- sets a condition to be met to draw path -->
-        <attr name="state_checkable" />
     </declare-styleable>
 
     <!-- ========================== -->
@@ -5027,10 +5036,14 @@
         <attr name="targetId" format="reference" />
         <!-- The id of a target to exclude from this transition. -->
         <attr name="excludeId" format="reference" />
-        <!-- The fully-qualified name of the Class to exclude from this transition. -->
-        <attr name="excludeClass" format="string" />
         <!-- The fully-qualified name of the Class to include in this transition. -->
         <attr name="targetClass" />
+        <!-- The fully-qualified name of the Class to exclude from this transition. -->
+        <attr name="excludeClass" format="string" />
+        <!-- The viewName of the target on which this transition will animation changes. -->
+        <attr name="targetViewName" format="string" />
+        <!-- The viewName of the target to exclude from this transition. -->
+        <attr name="excludeViewName" format="string" />
     </declare-styleable>
 
     <!-- Use <code>set</code> as the root tag of the XML resource that
@@ -5811,6 +5824,9 @@
         <attr name="imeExtractExitAnimation" format="reference" />
     </declare-styleable>
 
+    <declare-styleable name="VoiceInteractionSession">
+    </declare-styleable>
+
     <declare-styleable name="KeyboardView">
         <!-- Default KeyboardView style. -->
         <attr name="keyboardViewStyle" format="reference" />
@@ -5952,11 +5968,12 @@
             <flag name="vertical" value="0x2" />
         </attr>
         <!-- Optional parameter which indicates where this widget can be shown,
-             ie. home screen, keyguard or both.
-             resized. Supports combined values using | operator. -->
+             ie. home screen, keyguard, recents or any combination thereof.
+             Supports combined values using | operator. -->
         <attr name="widgetCategory" format="integer">
             <flag name="home_screen" value="0x1" />
             <flag name="keyguard" value="0x2" />
+            <flag name="recents" value="0x4" />
         </attr>
     </declare-styleable>
 
@@ -6348,6 +6365,8 @@
         <!-- Specifies padding that should be applied to the left and right sides of
              system-provided items in the bar. -->
         <attr name="itemPadding" format="dimension" />
+        <!-- Set true to hide the action bar on a vertical nested scroll of content. -->
+        <attr name="hideOnContentScroll" format="boolean" />
     </declare-styleable>
 
     <declare-styleable name="ActionMode">
@@ -6394,6 +6413,8 @@
         <attr name="switchMinWidth" format="dimension" />
         <!-- Minimum space between the switch and caption text -->
         <attr name="switchPadding" format="dimension" />
+        <!-- Whether to split the track and leave a gap for the thumb drawable. -->
+        <attr name="splitTrack" />
     </declare-styleable>
 
     <declare-styleable name="Pointer">
@@ -6606,4 +6627,8 @@
         <attr name="layout_gravity" />
     </declare-styleable>
 
+    <!-- Used as a filter array on the theme to pull out only the EdgeEffect-relevant bits. -->
+    <declare-styleable name="EdgeEffect">
+        <attr name="colorPrimaryLight" />
+    </declare-styleable>
 </resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index cce4dbd..b1f256e 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -885,6 +885,47 @@
          be passed a persistable Bundle in their Intent.extras. -->
     <attr name="persistable" format="boolean" />
 
+    <!-- Specify whether this activity should always be launched in doc-centric mode. For
+         values other than <code>none</code> the activity must be defined with
+         {@link android.R.attr#launchMode} <code>standard</code> or <code>singleTop</code>.
+         This attribute can be overridden by {@link
+         android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}.
+
+         <p>If this attribute is not specified, <code>none</code> will be used.
+         Note that this launch behavior can be changed in some ways at runtime
+         through the {@link android.content.Intent} flags
+         {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}. -->
+    <attr name="documentLaunchMode">
+        <!-- The default mode, which will create a new task only when
+             {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK
+             Intent.FLAG_ACTIVITY_NEW_TASK} is set. -->
+        <enum name="none" value="0" />
+        <!-- All tasks will be searched for a matching Intent. If one is found
+             That task will cleared and restarted with the root activity receiving a call
+             to {@link android.app.Activity#onNewIntent Activity.onNewIntent}. If no
+             such task is found a new task will be created.
+             This is the equivalent of with {@link
+             android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT Intent.FLAG_ACTIVITY_NEW_DOCUMENT}
+             without {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
+             Intent.FLAG_ACTIVITY_MULTIPLE_TASK}. -->
+        <enum name="intoExisting" value="1" />
+        <!-- A new task rooted at this activity will be created.
+             This is the equivalent of with {@link
+             android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT Intent.FLAG_ACTIVITY_NEW_DOCUMENT}
+             paired with {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
+             Intent.FLAG_ACTIVITY_MULTIPLE_TASK}. -->
+        <enum name="always" value="2" />
+    </attr>
+
+    <!-- Tasks launched by activities with this attribute will remain in the recent task
+         list until the last activity in the task is completed. When that happens the task
+         will be automatically removed from the recent task list.
+
+         This attribute is the equivalent of {@link
+         android.content.Intent#FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS
+         Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS} -->
+    <attr name="autoRemoveFromRecents" 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
@@ -1549,6 +1590,8 @@
         <attr name="primaryUserOnly" format="boolean" />
         <attr name="persistable" />
         <attr name="allowEmbedded" />
+        <attr name="documentLaunchMode" />
+        <attr name="autoRemoveFromRecents" />
     </declare-styleable>
     
     <!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index d0c455b..ad29505 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -71,11 +71,7 @@
     <drawable name="editbox_dropdown_dark_frame">@drawable/editbox_dropdown_background_dark</drawable>
     <drawable name="editbox_dropdown_light_frame">@drawable/editbox_dropdown_background</drawable>
 
-    <drawable name="dialog_holo_dark_frame">@drawable/dialog_full_holo_dark</drawable>
-    <drawable name="dialog_holo_light_frame">@drawable/dialog_full_holo_light</drawable>
-
     <drawable name="input_method_fullscreen_background">#fff9f9f9</drawable>
-    <drawable name="input_method_fullscreen_background_holo">@drawable/screen_background_holo_dark</drawable>
     <color name="input_method_navigation_guard">#ff000000</color>
 
     <!-- For date picker widget -->
@@ -122,78 +118,15 @@
     <!-- FaceLock -->
     <color name="facelock_spotlight_mask">#CC000000</color>
 
-    <!-- For holo theme -->
-    <drawable name="screen_background_holo_light">#fff3f3f3</drawable>
-    <drawable name="screen_background_holo_dark">#ff000000</drawable>
-    <color name="background_holo_dark">#ff000000</color>
-    <color name="background_holo_light">#fff3f3f3</color>
-    <color name="bright_foreground_holo_dark">@android:color/background_holo_light</color>
-    <color name="bright_foreground_holo_light">@android:color/background_holo_dark</color>
-    <color name="bright_foreground_disabled_holo_dark">#ff4c4c4c</color>
-    <color name="bright_foreground_disabled_holo_light">#ffb2b2b2</color>
-    <color name="bright_foreground_inverse_holo_dark">@android:color/bright_foreground_holo_light</color>
-    <color name="bright_foreground_inverse_holo_light">@android:color/bright_foreground_holo_dark</color>
-    <color name="dim_foreground_holo_dark">#bebebe</color>
-    <color name="dim_foreground_disabled_holo_dark">#80bebebe</color>
-    <color name="dim_foreground_inverse_holo_dark">#323232</color>
-    <color name="dim_foreground_inverse_disabled_holo_dark">#80323232</color>
-    <color name="hint_foreground_holo_dark">#808080</color>
-    <color name="dim_foreground_holo_light">#323232</color>
-    <color name="dim_foreground_disabled_holo_light">#80323232</color>
-    <color name="dim_foreground_inverse_holo_light">#bebebe</color>
-    <color name="dim_foreground_inverse_disabled_holo_light">#80bebebe</color>
-    <color name="hint_foreground_holo_light">#808080</color>
-    <color name="highlighted_text_holo_dark">#6633b5e5</color>
-    <color name="highlighted_text_holo_light">#6633b5e5</color>
-    <color name="link_text_holo_dark">#5c5cff</color>
-    <color name="link_text_holo_light">#0000ee</color>
+    <color name="micro_text_light">#434343</color>
 
-    <!-- Group buttons -->
-    <eat-comment />
-    <color name="group_button_dialog_pressed_holo_dark">#46c5c1ff</color>
-    <color name="group_button_dialog_focused_holo_dark">#2699cc00</color>
-
-    <color name="group_button_dialog_pressed_holo_light">#ffffffff</color>
-    <color name="group_button_dialog_focused_holo_light">#4699cc00</color>
-
-    <!-- Highlight colors for the legacy themes -->
-    <eat-comment />
-    <color name="legacy_pressed_highlight">#fffeaa0c</color>
-    <color name="legacy_selected_highlight">#fff17a0a</color>
-    <color name="legacy_long_pressed_highlight">#ffffffff</color>
-
-    <!-- General purpose colors for Holo-themed elements -->
-    <eat-comment />
-
-    <!-- A light Holo shade of blue -->
-    <color name="holo_blue_light">#ff33b5e5</color>
-    <!-- A light Holo shade of gray -->
-    <color name="holo_gray_light">#33999999</color>
-    <!-- A light Holo shade of green -->
-    <color name="holo_green_light">#ff99cc00</color>
-    <!-- A light Holo shade of red -->
-    <color name="holo_red_light">#ffff4444</color>
-    <!-- A dark Holo shade of blue -->
-    <color name="holo_blue_dark">#ff0099cc</color>
-    <!-- A dark Holo shade of green -->
-    <color name="holo_green_dark">#ff669900</color>
-    <!-- A dark Holo shade of red -->
-    <color name="holo_red_dark">#ffcc0000</color>
-    <!-- A Holo shade of purple -->
-    <color name="holo_purple">#ffaa66cc</color>
-    <!-- A light Holo shade of orange -->
-    <color name="holo_orange_light">#ffffbb33</color>
-    <!-- A dark Holo shade of orange -->
-    <color name="holo_orange_dark">#ffff8800</color>
-    <!-- A really bright Holo shade of blue -->
-    <color name="holo_blue_bright">#ff00ddff</color>
-    <!-- A really bright Holo shade of gray -->
-    <color name="holo_gray_bright">#33CCCCCC</color>
+    <color name="leanback_dark_gray">#ff333333</color>
+    <color name="leanback_light_gray">#ff888888</color>
 
     <drawable name="notification_template_icon_bg">#3333B5E5</drawable>
     <drawable name="notification_template_icon_low_bg">#0cffffff</drawable>
 
-    <color name="notification_icon_legacy_bg_color">#ff4285F4</color>
+    <color name="notification_icon_bg_color">#ffa3a3a3</color>
     <color name="notification_action_legacy_color_filter">#ff555555</color>
 
     <!-- Keyguard colors -->
@@ -204,21 +137,5 @@
 
     <color name="accessibility_focus_highlight">#80ffff00</color>
 
-    <!-- New TimePicker colors -->
-    <color name="timepicker_default_background_holo_light">@android: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">@android:color/white</color>
-
-    <color name="timepicker_default_disabled_color_holo_light">#7f000000</color>
-    <color name="timepicker_default_disabled_color_holo_dark">#7f08c8c8</color>
-
-    <color name="timepicker_default_ampm_selected_background_color_holo_light">@android:color/holo_blue_light</color>
-    <color name="timepicker_default_ampm_selected_background_color_holo_dark">@android:color/holo_blue_light</color>
-
-    <color name="timepicker_default_ampm_unselected_background_color_holo_light">@android:color/white</color>
-    <color name="timepicker_default_ampm_unselected_background_color_holo_dark">@android:color/transparent</color>
-
 </resources>
 
diff --git a/core/res/res/values/colors_holo.xml b/core/res/res/values/colors_holo.xml
new file mode 100644
index 0000000..d1f4e38
--- /dev/null
+++ b/core/res/res/values/colors_holo.xml
@@ -0,0 +1,123 @@
+<?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.
+-->
+
+<!-- Colors specific to Holo themes. -->
+<resources>
+
+    <drawable name="dialog_holo_dark_frame">@drawable/dialog_full_holo_dark</drawable>
+    <drawable name="dialog_holo_light_frame">@drawable/dialog_full_holo_light</drawable>
+    <drawable name="input_method_fullscreen_background_holo">@drawable/screen_background_holo_dark</drawable>
+
+    <drawable name="screen_background_holo_light">#fff3f3f3</drawable>
+    <drawable name="screen_background_holo_dark">#ff000000</drawable>
+
+    <color name="background_holo_dark">#ff000000</color>
+    <color name="background_holo_light">#fff3f3f3</color>
+    <color name="bright_foreground_holo_dark">@color/background_holo_light</color>
+    <color name="bright_foreground_holo_light">@color/background_holo_dark</color>
+    <color name="bright_foreground_disabled_holo_dark">#ff4c4c4c</color>
+    <color name="bright_foreground_disabled_holo_light">#ffb2b2b2</color>
+    <color name="bright_foreground_inverse_holo_dark">@color/bright_foreground_holo_light</color>
+    <color name="bright_foreground_inverse_holo_light">@color/bright_foreground_holo_dark</color>
+    <color name="dim_foreground_holo_dark">#bebebe</color>
+    <color name="dim_foreground_disabled_holo_dark">#80bebebe</color>
+    <color name="dim_foreground_inverse_holo_dark">#323232</color>
+    <color name="dim_foreground_inverse_disabled_holo_dark">#80323232</color>
+    <color name="hint_foreground_holo_dark">#808080</color>
+    <color name="dim_foreground_holo_light">#323232</color>
+    <color name="dim_foreground_disabled_holo_light">#80323232</color>
+    <color name="dim_foreground_inverse_holo_light">#bebebe</color>
+    <color name="dim_foreground_inverse_disabled_holo_light">#80bebebe</color>
+    <color name="hint_foreground_holo_light">#808080</color>
+    <color name="highlighted_text_holo_dark">#6633b5e5</color>
+    <color name="highlighted_text_holo_light">#6633b5e5</color>
+    <color name="link_text_holo_dark">#5c5cff</color>
+    <color name="link_text_holo_light">#0000ee</color>
+
+    <!-- General purpose colors for Holo-themed elements -->
+    <eat-comment />
+
+    <!-- A light Holo shade of blue -->
+    <color name="holo_blue_light">#ff33b5e5</color>
+    <!-- A light Holo shade of gray -->
+    <color name="holo_gray_light">#33999999</color>
+    <!-- A light Holo shade of green -->
+    <color name="holo_green_light">#ff99cc00</color>
+    <!-- A light Holo shade of red -->
+    <color name="holo_red_light">#ffff4444</color>
+    <!-- A dark Holo shade of blue -->
+    <color name="holo_blue_dark">#ff0099cc</color>
+    <!-- A dark Holo shade of green -->
+    <color name="holo_green_dark">#ff669900</color>
+    <!-- A dark Holo shade of red -->
+    <color name="holo_red_dark">#ffcc0000</color>
+    <!-- A Holo shade of purple -->
+    <color name="holo_purple">#ffaa66cc</color>
+    <!-- A light Holo shade of orange -->
+    <color name="holo_orange_light">#ffffbb33</color>
+    <!-- A dark Holo shade of orange -->
+    <color name="holo_orange_dark">#ffff8800</color>
+    <!-- A really bright Holo shade of blue -->
+    <color name="holo_blue_bright">#ff00ddff</color>
+    <!-- A really bright Holo shade of gray -->
+    <color name="holo_gray_bright">#33CCCCCC</color>
+
+    <!-- Forward compatibility for Quantum-style theme colors -->
+    <eat-comment />
+
+    <color name="holo_primary_dark">#ff000000</color>
+    <color name="holo_primary">#ffe6e6e6</color>
+    <color name="holo_primary_light">#ffffffff</color>
+    <color name="holo_control_activated">@color/holo_blue_light</color>
+    <color name="holo_control_normal">#39cccccc</color>
+    <color name="holo_button_pressed">#59f0f0f0</color>
+    <color name="holo_button_normal">#bd292f34</color>
+
+    <color name="holo_light_primary_dark">#ff000000</color>
+    <color name="holo_light_primary">#ffe6e6e6</color>
+    <color name="holo_light_primary_light">#ffffffff</color>
+    <color name="holo_light_control_activated">@color/holo_control_activated</color>
+    <color name="holo_light_control_normal">#dacccccc</color>
+    <color name="holo_light_button_pressed">#66666666</color>
+    <color name="holo_light_button_normal">#b3cccccc</color>
+
+    <!-- Group buttons -->
+    <eat-comment />
+
+    <color name="group_button_dialog_pressed_holo_dark">#46c5c1ff</color>
+    <color name="group_button_dialog_focused_holo_dark">#2699cc00</color>
+
+    <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_disabled_color_holo_light">#7f000000</color>
+    <color name="timepicker_default_disabled_color_holo_dark">#7f08c8c8</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>
+</resources>
diff --git a/core/res/res/values/colors_legacy.xml b/core/res/res/values/colors_legacy.xml
new file mode 100644
index 0000000..48d4b42
--- /dev/null
+++ b/core/res/res/values/colors_legacy.xml
@@ -0,0 +1,45 @@
+<?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.
+-->
+
+<!-- Colors specific to pre-Holo themes. -->
+<resources>
+
+    <!-- Highlight colors for the legacy themes -->
+    <eat-comment />
+
+    <color name="legacy_pressed_highlight">#fffeaa0c</color>
+    <color name="legacy_selected_highlight">#fff17a0a</color>
+    <color name="legacy_long_pressed_highlight">#ffffffff</color>
+
+    <!-- Forward compatibility for Quantum-style theme colors -->
+    <eat-comment />
+
+    <color name="legacy_primary_dark">#ff000000</color>
+    <color name="legacy_primary">#ffe6e6e6</color>
+    <color name="legacy_primary_light">#ffffffff</color>
+    <color name="legacy_control_activated">#ff90df25</color>
+    <color name="legacy_control_normal">#99ffffff</color>
+    <color name="legacy_button_pressed">#fffea50b</color>
+    <color name="legacy_button_normal">#f3dbdbdb</color>
+
+    <color name="legacy_light_primary_dark">@color/legacy_primary_dark</color>
+    <color name="legacy_light_primary">@color/legacy_primary</color>
+    <color name="legacy_light_primary_light">@color/legacy_primary_light</color>
+    <color name="legacy_light_control_activated">@color/legacy_control_activated</color>
+    <color name="legacy_light_control_normal">#99000000</color>
+    <color name="legacy_light_button_pressed">@color/legacy_button_pressed</color>
+    <color name="legacy_light_button_normal">@color/legacy_button_normal</color>
+</resources>
diff --git a/core/res/res/values/colors_quantum.xml b/core/res/res/values/colors_quantum.xml
index f8f192f..7171450 100644
--- a/core/res/res/values/colors_quantum.xml
+++ b/core/res/res/values/colors_quantum.xml
@@ -14,6 +14,7 @@
      limitations under the License.
 -->
 
+<!-- Colors specific to Quantum themes. -->
 <resources>
     <color name="background_quantum_dark">@color/black</color>
     <color name="background_quantum_light">@color/white</color>
@@ -40,6 +41,7 @@
     <color name="highlighted_text_quantum_light">#660097a7</color>
 
     <!-- Primary & accent colors -->
+    <eat-comment />
 
     <color name="quantum_red_100">#fff4c7c3</color>
     <color name="quantum_red_300">#ffe67c73</color>
@@ -98,6 +100,7 @@
     <color name="quantum_deep_orange_A400">#ffff1744</color>
 
     <!-- Neutral colors -->
+    <eat-comment />
 
     <color name="quantum_grey_50">#fffafafa</color>
     <color name="quantum_grey_100">#fff5f5f5</color>
@@ -117,6 +120,7 @@
     <color name="quantum_brown_700">#ff5d4037</color>
 
     <!-- Text & foreground colors -->
+    <eat-comment />
 
     <color name="primary_text_default_quantum_light">#de000000</color>
     <color name="secondary_text_quantum_light">#8a000000</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f919c9f..463dda2 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -462,6 +462,19 @@
          provide full support for multiple displays.  -->
     <integer name="config_undockedHdmiRotation">-1</integer>
 
+    <!-- HDMI-CEC logical device types allowed on the system. Logical device types
+         are defined in HDMI-CEC standard 1.4 as follows:
+           0 TV
+           1 Recording Device
+           2 Reserved
+           3 Tuner
+           4 Playback
+           5 Audio System
+           6 Pure CEC Switch
+           7 Video Processor    -->
+    <integer-array name="config_hdmiCecLogicalDeviceType">
+    </integer-array>
+
     <!-- Control the default UI mode type to use when there is no other type override
          happening.  One of the following values (See Configuration.java):
              1  UI_MODE_TYPE_NORMAL
@@ -1206,6 +1219,15 @@
          movement threshold where scrolling should begin. -->
     <dimen name="config_viewConfigurationTouchSlop">8dp</dimen>
 
+    <!-- Minimum velocity to initiate a fling, as measured in dips per second. -->
+    <dimen name="config_viewMinFlingVelocity">50dp</dimen>
+
+    <!-- Maximum velocity to initiate a fling, as measured in dips per second. -->
+    <dimen name="config_viewMaxFlingVelocity">8000dp</dimen>
+
+    <!-- Amount of time in ms the user needs to press the relevant key to bring up the global actions dialog -->
+    <integer name="config_globalActionsKeyTimeout">500</integer>
+
     <!-- Maximum number of grid columns permitted in the ResolverActivity
          used for picking activities to handle an intent. -->
     <integer name="config_maxResolverActivityColumns">2</integer>
@@ -1384,8 +1406,11 @@
         <item>com.android.inputmethod.latin</item>
     </string-array>
 
-    <string-array name="config_notificationScorers">
-        <item>com.android.internal.notification.PeopleNotificationScorer</item>
+    <!-- The list of classes that should be added to the notification ranking pipline.
+     See {@link com.android.server.notification.NotificationSignalExtractor} -->
+    <string-array name="config_notificationSignalExtractors">
+        <item>com.android.server.notification.ValidateNotificationPeople</item>
+        <item>com.android.server.notification.NotificationIntrusivenessExtractor</item>
     </string-array>
 
     <!-- Flag indicating that this device does not rotate and will always remain in its default
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 6b2c788..69b11cd 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -143,10 +143,16 @@
     <!-- Preferred width of the search view. -->
     <dimen name="search_view_preferred_width">320dip</dimen>
 
+    <!-- Dialog padding for round display -->
+    <dimen name="alert_dialog_round_padding">27dip</dimen>
     <!-- Dialog title height -->
     <dimen name="alert_dialog_title_height">64dip</dimen>
     <!-- Dialog button bar height -->
     <dimen name="alert_dialog_button_bar_height">48dip</dimen>
+    <!-- Leanback dialog vertical margin -->
+    <dimen name="leanback_alert_dialog_vertical_margin">27dip</dimen>
+    <!-- Leanback dialog horizontal margin -->
+    <dimen name="leanback_alert_dialog_horizontal_margin">54dip</dimen>
 
     <!-- Default height of an action bar. -->
     <dimen name="action_bar_default_height">48dip</dimen>
diff --git a/core/res/res/values/dimens_quantum.xml b/core/res/res/values/dimens_quantum.xml
index cebee12..53e97fd 100644
--- a/core/res/res/values/dimens_quantum.xml
+++ b/core/res/res/values/dimens_quantum.xml
@@ -49,4 +49,7 @@
 
     <dimen name="floating_window_z">16dp</dimen>
     <dimen name="floating_window_margin">32dp</dimen>
+
+    <!-- the amount of elevation for pressed button state-->
+    <dimen name="button_pressed_z">2dp</dimen>
 </resources>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 889c368..6ea0fae 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -82,7 +82,6 @@
   <item type="id" name="action_bar_spinner" />
   <item type="id" name="current_scene" />
   <item type="id" name="scene_layoutid_cache" />
-  <item type="id" name="shared_element_name" />
   <item type="id" name="mask" />
   <item type="id" name="shared_element" />
 </resources>
diff --git a/core/res/res/values/integers.xml b/core/res/res/values/integers.xml
index dc90bbf..e6748c4 100644
--- a/core/res/res/values/integers.xml
+++ b/core/res/res/values/integers.xml
@@ -19,4 +19,5 @@
 <resources>
     <integer name="kg_carousel_angle">75</integer>
     <integer name="kg_glowpad_rotation_offset">0</integer>
+    <integer name="button_pressed_animation_duration">100</integer>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 5ccb05b..3ef4ab6 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2114,9 +2114,8 @@
   <public type="attr" name="controlY1" />
   <public type="attr" name="controlX2" />
   <public type="attr" name="controlY2" />
-  <public type="attr" name="sharedElementName" />
+  <public type="attr" name="viewName" />
   <public type="attr" name="transitionGroup" />
-  <public type="attr" name="trigger" />
   <public type="attr" name="viewportWidth" />
   <public type="attr" name="viewportHeight" />
   <public type="attr" name="fillOpacity" />
@@ -2125,25 +2124,18 @@
   <public type="attr" name="stroke" />
   <public type="attr" name="strokeOpacity" />
   <public type="attr" name="strokeWidth" />
-  <public type="attr" name="durations" />
-  <public type="attr" name="sequence" />
-  <public type="attr" name="repeatStyle" />
   <public type="attr" name="trimPathStart" />
   <public type="attr" name="trimPathEnd" />
   <public type="attr" name="trimPathOffset" />
   <public type="attr" name="strokeLineCap" />
   <public type="attr" name="strokeLineJoin" />
   <public type="attr" name="clipToPath" />
-  <public type="attr" name="animate" />
-  <public type="attr" name="limitTo" />
   <public type="attr" name="requiredForProfile"/>
   <public type="attr" name="pinned" />
   <public type="attr" name="colorControlNormal" />
   <public type="attr" name="colorControlActivated" />
   <public type="attr" name="colorButtonNormal" />
   <public type="attr" name="colorButtonPressed" />
-  <public type="attr" name="colorButtonNormalColored" />
-  <public type="attr" name="colorButtonPressedColored" />
   <public type="attr" name="persistable" />
   <public type="attr" name="titleTextAppearance" />
   <public type="attr" name="subtitleTextAppearance" />
@@ -2162,10 +2154,22 @@
   <public type="attr" name="windowAllowExitTransitionOverlap" />
   <public type="attr" name="windowAllowEnterTransitionOverlap" />
   <public type="attr" name="sessionService" />
+  <public type="attr" name="stackViewStyle" />
   <public type="attr" name="switchStyle" />
   <public type="attr" name="elevation" />
   <public type="attr" name="excludeId" />
   <public type="attr" name="excludeClass" />
+  <public type="attr" name="hideOnContentScroll" />
+  <public type="attr" name="actionOverflowMenuStyle" />
+  <public type="attr" name="documentLaunchMode" />
+  <public type="attr" name="autoRemoveFromRecents" />
+  <public type="attr" name="stateListAnimator" />
+  <public type="attr" name="toId" />
+  <public type="attr" name="fromId" />
+  <public type="attr" name="reversible" />
+  <public type="attr" name="splitTrack" />
+  <public type="attr" name="targetViewName" />
+  <public type="attr" name="excludeViewName" />
 
   <public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
 
@@ -2174,21 +2178,30 @@
 
   <public-padding type="id" name="l_resource_pad" end="0x01020040" />
 
-  <public type="id" name="shared_element_name" />
   <public type="id" name="mask" />
   <public type="id" name="shared_element" />
 
   <public-padding type="style" name="l_resource_pad" end="0x01030200" />
 
-  <public type="style" name="Widget.Holo.FragmentBreadCrumbs" />
-  <public type="style" name="Widget.Holo.Light.FragmentBreadCrumbs" />
-  <public type="style" name="Widget.DeviceDefault.FragmentBreadCrumbs" />
-  <public type="style" name="Widget.DeviceDefault.Light.FragmentBreadCrumbs" />
   <public type="style" name="Widget.FastScroll" />
+  <public type="style" name="Widget.StackView" />
+
   <public type="style" name="Widget.Holo.FastScroll" />
+  <public type="style" name="Widget.Holo.FragmentBreadCrumbs" />
+  <public type="style" name="Widget.Holo.StackView" />
+
+  <public type="style" name="Widget.Holo.Light.Button.Borderless" />
   <public type="style" name="Widget.Holo.Light.FastScroll" />
+  <public type="style" name="Widget.Holo.Light.FragmentBreadCrumbs" />
+  <public type="style" name="Widget.Holo.Light.StackView" />
+
   <public type="style" name="Widget.DeviceDefault.FastScroll" />
+  <public type="style" name="Widget.DeviceDefault.FragmentBreadCrumbs" />
+  <public type="style" name="Widget.DeviceDefault.StackView" />
+
   <public type="style" name="Widget.DeviceDefault.Light.FastScroll" />
+  <public type="style" name="Widget.DeviceDefault.Light.FragmentBreadCrumbs" />
+  <public type="style" name="Widget.DeviceDefault.Light.StackView" />
 
   <public type="style" name="TextAppearance.Quantum" />
   <public type="style" name="TextAppearance.Quantum.DialogWindowTitle" />
@@ -2265,7 +2278,6 @@
   <public type="style" name="Widget.Quantum.ActionButton" />
   <public type="style" name="Widget.Quantum.ActionButton.CloseMode" />
   <public type="style" name="Widget.Quantum.ActionButton.Overflow" />
-  <public type="style" name="Widget.Quantum.ActionButton.TextButton" />
   <public type="style" name="Widget.Quantum.ActionMode" />
   <public type="style" name="Widget.Quantum.AutoCompleteTextView" />
   <public type="style" name="Widget.Quantum.Button" />
@@ -2296,6 +2308,7 @@
   <public type="style" name="Widget.Quantum.ListView.DropDown" />
   <public type="style" name="Widget.Quantum.MediaRouteButton" />
   <public type="style" name="Widget.Quantum.PopupMenu" />
+  <public type="style" name="Widget.Quantum.PopupMenu.Overflow" />
   <public type="style" name="Widget.Quantum.PopupWindow" />
   <public type="style" name="Widget.Quantum.ProgressBar" />
   <public type="style" name="Widget.Quantum.ProgressBar.Horizontal" />
@@ -2308,6 +2321,7 @@
   <public type="style" name="Widget.Quantum.ScrollView" />
   <public type="style" name="Widget.Quantum.SeekBar" />
   <public type="style" name="Widget.Quantum.SegmentedButton" />
+  <public type="style" name="Widget.Quantum.StackView" />
   <public type="style" name="Widget.Quantum.Spinner" />
   <public type="style" name="Widget.Quantum.Tab" />
   <public type="style" name="Widget.Quantum.TabWidget" />
@@ -2328,6 +2342,7 @@
   <public type="style" name="Widget.Quantum.Light.ActionMode" />
   <public type="style" name="Widget.Quantum.Light.AutoCompleteTextView" />
   <public type="style" name="Widget.Quantum.Light.Button" />
+  <public type="style" name="Widget.Quantum.Light.Button.Borderless" />
   <public type="style" name="Widget.Quantum.Light.Button.Borderless.Small" />
   <public type="style" name="Widget.Quantum.Light.Button.Inset" />
   <public type="style" name="Widget.Quantum.Light.Button.Small" />
@@ -2353,6 +2368,7 @@
   <public type="style" name="Widget.Quantum.Light.ListView.DropDown" />
   <public type="style" name="Widget.Quantum.Light.MediaRouteButton" />
   <public type="style" name="Widget.Quantum.Light.PopupMenu" />
+  <public type="style" name="Widget.Quantum.Light.PopupMenu.Overflow" />
   <public type="style" name="Widget.Quantum.Light.PopupWindow" />
   <public type="style" name="Widget.Quantum.Light.ProgressBar" />
   <public type="style" name="Widget.Quantum.Light.ProgressBar.Horizontal" />
@@ -2368,6 +2384,7 @@
   <public type="style" name="Widget.Quantum.Light.ScrollView" />
   <public type="style" name="Widget.Quantum.Light.SeekBar" />
   <public type="style" name="Widget.Quantum.Light.SegmentedButton" />
+  <public type="style" name="Widget.Quantum.Light.StackView" />
   <public type="style" name="Widget.Quantum.Light.Spinner" />
   <public type="style" name="Widget.Quantum.Light.Tab" />
   <public type="style" name="Widget.Quantum.Light.TabWidget" />
@@ -2376,12 +2393,6 @@
   <public type="style" name="Widget.Quantum.Light.WebTextView" />
   <public type="style" name="Widget.Quantum.Light.WebView" />
 
-  <public type="style" name="Widget.Quantum.Button.Paper" />
-  <public type="style" name="Widget.Quantum.Button.Paper.Color" />
-
-  <public type="style" name="Widget.Quantum.Light.Button.Paper" />
-  <public type="style" name="Widget.Quantum.Light.Button.Paper.Color" />
-
   <public type="style" name="TextAppearance.Quantum.Display4" />
   <public type="style" name="TextAppearance.Quantum.Display3" />
   <public type="style" name="TextAppearance.Quantum.Display2" />
@@ -2395,8 +2406,6 @@
   <public type="style" name="TextAppearance.Quantum.Menu" />
   <public type="style" name="TextAppearance.Quantum.Button" />
 
-  <public type="style" name="Widget.Holo.Light.Button.Borderless" />
-
   <public-padding type="interpolator" name="l_resource_pad" end="0x010c0010" />
 
   <!-- An interpolator which accelerates fast but decelerates slowly. -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 57b2c01..8286ef9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -454,6 +454,12 @@
     <!-- Label for the Android system components when they are shown to the user. -->
     <string name="android_system_label">Android System</string>
 
+    <!-- Label for the user owner in the intent forwarding app. -->
+    <string name="user_owner_label">Personal</string>
+
+    <!-- Label for a corporate profile in the intent forwarding app. -->
+    <string name="managed_profile_label">Work</string>
+
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_costMoney">Services that cost you money</string>
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
@@ -947,10 +953,11 @@
         Malicious apps may use this to forge MMS message receipt or to
         silently replace the content of any webpage with malicious variants.</string>
 
+    <!-- TODO: Mark these as translatable when API is finalized. -->
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_broadcastScoreNetworks">send score networks broadcast</string>
+    <string name="permlab_broadcastScoreNetworks" translatable="false">send score networks broadcast</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_broadcastScoreNetworks">Allows the app
+    <string name="permdesc_broadcastScoreNetworks" translatable="false">Allows the app
         to broadcast a notification that networks need to be scored.
         Never needed for normal apps.
     </string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index fc0fccc..891265f 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -169,6 +169,12 @@
         <item name="windowExitAnimation">@anim/input_method_exit</item>
     </style>
 
+    <!-- Window animations that are applied to voice interaction overlay windows. -->
+    <style name="Animation.VoiceInteractionSession">
+        <item name="windowEnterAnimation">@anim/input_method_enter</item>
+        <item name="windowExitAnimation">@anim/input_method_exit</item>
+    </style>
+
     <!-- Special optional fancy IM animations. @hide -->
     <style name="Animation.InputMethodFancy">
         <item name="windowEnterAnimation">@anim/input_method_fancy_enter</item>
@@ -397,6 +403,11 @@
         <item name="android:disabledAlpha">?android:attr/disabledAlpha</item>
     </style>
 
+    <style name="Widget.StackView">
+        <item name="android:resOutColor">@android:color/holo_blue_light</item>
+        <item name="android:clickColor">@android:color/holo_blue_light</item>
+    </style>
+
     <style name="Widget.ProgressBar">
         <item name="android:indeterminateOnly">true</item>
         <item name="android:indeterminateDrawable">@android:drawable/progress_medium_white</item>
@@ -1609,11 +1620,6 @@
         <item name="android:minWidth">64dip</item>
     </style>
 
-    <style name="Widget.Holo.StackView">
-        <item name="android:resOutColor">@android:color/holo_blue_light</item>
-        <item name="android:clickColor">@android:color/holo_blue_light</item>
-    </style>
-
     <style name="Widget.Holo.Button.Borderless">
         <item name="android:background">?android:attr/selectableItemBackground</item>
         <item name="android:paddingStart">4dip</item>
@@ -1645,6 +1651,11 @@
         <item name="android:minHeight">48dip</item>
     </style>
 
+    <style name="Widget.Holo.StackView">
+        <item name="android:resOutColor">@android:color/holo_blue_light</item>
+        <item name="android:clickColor">@android:color/holo_blue_light</item>
+    </style>
+
     <style name="Holo.ButtonBar" parent="ButtonBar">
         <item name="android:paddingTop">0dip</item>
         <item name="android:paddingStart">0dip</item>
@@ -2099,6 +2110,11 @@
         <item name="android:minHeight">48dip</item>
     </style>
 
+    <style name="Widget.Holo.Light.StackView">
+        <item name="android:resOutColor">@android:color/holo_blue_light</item>
+        <item name="android:clickColor">@android:color/holo_blue_light</item>
+    </style>
+
     <style name="Holo.Light.ButtonBar" parent="Holo.ButtonBar">
     </style>
 
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 629b2b7..60e06ce 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -72,7 +72,7 @@
     <style name="Widget.DeviceDefault.PopupMenu" parent="Widget.Quantum.PopupMenu"/>
     <style name="Widget.DeviceDefault.ActionButton" parent="Widget.Quantum.ActionButton"/>
     <style name="Widget.DeviceDefault.ActionButton.Overflow" parent="Widget.Quantum.ActionButton.Overflow"/>
-    <style name="Widget.DeviceDefault.ActionButton.TextButton" parent="Widget.Quantum.ActionButton.TextButton"/>
+    <style name="Widget.DeviceDefault.ActionButton.TextButton" parent="Widget.Quantum.ActionButton"/>
     <style name="Widget.DeviceDefault.ActionMode" parent="Widget.Quantum.ActionMode"/>
     <style name="Widget.DeviceDefault.ActionButton.CloseMode" parent="Widget.Quantum.ActionButton.CloseMode"/>
     <style name="Widget.DeviceDefault.ActionBar" parent="Widget.Quantum.ActionBar"/>
@@ -97,6 +97,7 @@
     <style name="Widget.DeviceDefault.ImageWell" parent="Widget.Quantum.ImageWell"/>
     <style name="Widget.DeviceDefault.KeyboardView" parent="Widget.Quantum.KeyboardView"/>
     <style name="Widget.DeviceDefault.ListView.White" parent="Widget.Quantum.ListView.White"/>
+    <style name="Widget.DeviceDefault.MediaRouteButton" parent="Widget.Quantum.MediaRouteButton" />
     <style name="Widget.DeviceDefault.NumberPicker" parent="Widget.Quantum.NumberPicker"/>
     <style name="Widget.DeviceDefault.PreferenceFrameLayout" parent="Widget.Quantum.PreferenceFrameLayout"/>
     <style name="Widget.DeviceDefault.ProgressBar.Inverse" parent="Widget.Quantum.ProgressBar.Inverse"/>
@@ -114,11 +115,13 @@
     <style name="Widget.DeviceDefault.TextSuggestionsPopupWindow" parent="Widget.Quantum.TextSuggestionsPopupWindow"/>
     <style name="Widget.DeviceDefault.TextView.ListSeparator" parent="Widget.Quantum.TextView.ListSeparator"/>
     <style name="Widget.DeviceDefault.TimePicker" parent="Widget.Quantum.TimePicker"/>
+
     <style name="Widget.DeviceDefault.Light" parent="Widget.Quantum.Light"/>
     <style name="Widget.DeviceDefault.Light.Button" parent="Widget.Quantum.Light.Button"/>
     <style name="Widget.DeviceDefault.Light.Button.Small" parent="Widget.Quantum.Light.Button.Small"/>
     <style name="Widget.DeviceDefault.Light.Button.Inset" parent="Widget.Quantum.Light.Button.Inset"/>
     <style name="Widget.DeviceDefault.Light.Button.Toggle" parent="Widget.Quantum.Light.Button.Toggle"/>
+    <style name="Widget.DeviceDefault.Light.StackView" parent="Widget.Quantum.Light.StackView"/>
     <style name="Widget.DeviceDefault.Light.TextView" parent="Widget.Quantum.Light.TextView"/>
     <style name="Widget.DeviceDefault.Light.CheckedTextView" parent="Widget.Quantum.Light.CheckedTextView"/>
     <style name="Widget.DeviceDefault.Light.AutoCompleteTextView" parent="Widget.Quantum.Light.AutoCompleteTextView"/>
@@ -131,6 +134,7 @@
     <style name="Widget.DeviceDefault.Light.GridView" parent="Widget.Quantum.Light.GridView"/>
     <style name="Widget.DeviceDefault.Light.ImageButton" parent="Widget.Quantum.Light.ImageButton"/>
     <style name="Widget.DeviceDefault.Light.ListView" parent="Widget.Quantum.Light.ListView"/>
+    <style name="Widget.DeviceDefault.Light.MediaRouteButton" parent="Widget.Quantum.Light.MediaRouteButton" />
     <style name="Widget.DeviceDefault.Light.PopupWindow" parent="Widget.Quantum.Light.PopupWindow"/>
     <style name="Widget.DeviceDefault.Light.ProgressBar" parent="Widget.Quantum.Light.ProgressBar"/>
     <style name="Widget.DeviceDefault.Light.ProgressBar.Horizontal" parent="Widget.Quantum.Light.ProgressBar.Horizontal"/>
@@ -195,7 +199,6 @@
     <style name="Widget.DeviceDefault.Light.TimePicker" parent="Widget.Quantum.Light.TimePicker"/>
     <style name="Widget.DeviceDefault.Light.TextSuggestionsPopupWindow" parent="Widget.Quantum.Light.TextSuggestionsPopupWindow"/>
 
-
     <!-- Text Appearance Styles -->
     <style name="TextAppearance.DeviceDefault" parent="TextAppearance.Quantum"/>
     <style name="TextAppearance.DeviceDefault.Inverse" parent="TextAppearance.Quantum.Inverse"/>
@@ -207,6 +210,8 @@
     <style name="TextAppearance.DeviceDefault.Small.Inverse" parent="TextAppearance.Quantum.Small.Inverse"/>
     <style name="TextAppearance.DeviceDefault.SearchResult.Title" parent="TextAppearance.Quantum.SearchResult.Title"/>
     <style name="TextAppearance.DeviceDefault.SearchResult.Subtitle" parent="TextAppearance.Quantum.SearchResult.Subtitle"/>
+    <style name="TextAppearance.DeviceDefault.TimePicker.TimeLabel" parent="TextAppearance.Quantum.TimePicker.TimeLabel"/>
+    <style name="TextAppearance.DeviceDefault.TimePicker.AmPmLabel" parent="TextAppearance.Quantum.TimePicker.AmPmLabel"/>
     <style name="TextAppearance.DeviceDefault.Widget" parent="TextAppearance.Quantum.Widget"/>
     <style name="TextAppearance.DeviceDefault.Widget.Button" parent="TextAppearance.Quantum.Widget.Button"/>
     <style name="TextAppearance.DeviceDefault.Widget.IconMenu.Item" parent="TextAppearance.Quantum.Widget.IconMenu.Item"/>
@@ -235,20 +240,6 @@
     <!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
     <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle.Inverse" parent="TextAppearance.Quantum.Widget.ActionMode.Subtitle.Inverse"/>
     <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Menu" parent="TextAppearance.Quantum.Widget.ActionBar.Menu"/>
-    <style name="TextAppearance.DeviceDefault.Light" parent="TextAppearance.Quantum.Light"/>
-    <style name="TextAppearance.DeviceDefault.Light.Inverse" parent="TextAppearance.Quantum.Light.Inverse"/>
-    <style name="TextAppearance.DeviceDefault.Light.Large" parent="TextAppearance.Quantum.Light.Large"/>
-    <style name="TextAppearance.DeviceDefault.Light.Large.Inverse" parent="TextAppearance.Quantum.Light.Large.Inverse"/>
-    <style name="TextAppearance.DeviceDefault.Light.Medium" parent="TextAppearance.Quantum.Light.Medium"/>
-    <style name="TextAppearance.DeviceDefault.Light.Medium.Inverse" parent="TextAppearance.Quantum.Light.Medium.Inverse"/>
-    <style name="TextAppearance.DeviceDefault.Light.SearchResult.Subtitle" parent="TextAppearance.Quantum.Light.SearchResult.Subtitle"/>
-    <style name="TextAppearance.DeviceDefault.Light.SearchResult.Title" parent="TextAppearance.Quantum.Light.SearchResult.Title"/>
-    <style name="TextAppearance.DeviceDefault.Light.Small" parent="TextAppearance.Quantum.Light.Small"/>
-    <style name="TextAppearance.DeviceDefault.Light.Small.Inverse" parent="TextAppearance.Quantum.Light.Small.Inverse"/>
-    <style name="TextAppearance.DeviceDefault.Light.Widget.Button" parent="TextAppearance.Quantum.Light.Widget.Button"/>
-    <style name="TextAppearance.DeviceDefault.Light.Widget.PopupMenu.Large" parent="TextAppearance.Quantum.Light.Widget.PopupMenu.Large"/>
-    <style name="TextAppearance.DeviceDefault.Light.Widget.PopupMenu.Small" parent="TextAppearance.Quantum.Light.Widget.PopupMenu.Small"/>
-
 
     <!-- Preference Styles -->
     <style name="Preference.DeviceDefault" parent="Preference.Quantum"/>
@@ -262,7 +253,6 @@
     <style name="Preference.DeviceDefault.RingtonePreference" parent="Preference.Quantum.RingtonePreference"/>
     <style name="Preference.DeviceDefault.SwitchPreference" parent="Preference.Quantum.SwitchPreference"/>
 
-
     <!-- AlertDialog Styles -->
     <style name="AlertDialog.DeviceDefault" parent="AlertDialog.Quantum"/>
     <style name="AlertDialog.DeviceDefault.Light" parent="AlertDialog.Quantum.Light"/>
@@ -271,32 +261,20 @@
     <style name="Animation.DeviceDefault.Activity" parent="Animation.Quantum.Activity"/>
     <style name="Animation.DeviceDefault.Dialog" parent="Animation.Quantum.Dialog"/>
 
-
     <!-- DialogWindowTitle Styles -->
     <style name="DialogWindowTitle.DeviceDefault" parent="DialogWindowTitle.Quantum"/>
     <style name="DialogWindowTitle.DeviceDefault.Light" parent="DialogWindowTitle.Quantum.Light"/>
 
-
     <!-- WindowTitle Styles -->
     <style name="WindowTitle.DeviceDefault" parent="WindowTitle.Quantum"/>
     <style name="WindowTitleBackground.DeviceDefault" parent="WindowTitleBackground.Quantum"/>
 
-
     <!-- Other Styles -->
     <style name="DeviceDefault.ButtonBar" parent="Widget.Quantum.ButtonBar"/>
     <style name="DeviceDefault.ButtonBar.AlertDialog" parent="Widget.Quantum.ButtonBar.AlertDialog"/>
     <style name="DeviceDefault.SegmentedButton" parent="Widget.Quantum.SegmentedButton"/>
+
     <style name="DeviceDefault.Light.ButtonBar" parent="Widget.Quantum.Light.ButtonBar"/>
     <style name="DeviceDefault.Light.ButtonBar.AlertDialog" parent="Widget.Quantum.Light.ButtonBar.AlertDialog"/>
     <style name="DeviceDefault.Light.SegmentedButton" parent="Widget.Quantum.Light.SegmentedButton"/>
-
-    <style name="Widget.DeviceDefault.MediaRouteButton" parent="Widget.Quantum.MediaRouteButton" />
-    <style name="Widget.DeviceDefault.Light.MediaRouteButton" parent="Widget.Quantum.Light.MediaRouteButton" />
-
-    <style name="TextAppearance.DeviceDefault.TimePicker.TimeLabel" parent="TextAppearance.Quantum.TimePicker.TimeLabel"/>
-    <style name="TextAppearance.DeviceDefault.Light.TimePicker.TimeLabel" parent="TextAppearance.Quantum.Light.TimePicker.TimeLabel"/>
-    <style name="TextAppearance.DeviceDefault.TimePicker.AmPmLabel" parent="TextAppearance.Quantum.TimePicker.AmPmLabel"/>
-    <style name="TextAppearance.DeviceDefault.Light.TimePicker.AmPmLabel" parent="TextAppearance.Quantum.Light.TimePicker.AmPmLabel"/>
-    <style name="Theme.DeviceDefault.Dialog.TimePicker" parent="Theme.Quantum.Dialog.TimePicker"/>
-    <style name="Theme.DeviceDefault.Light.Dialog.TimePicker" parent="Theme.Quantum.Light.Dialog.TimePicker"/>
 </resources>
diff --git a/core/res/res/values/styles_leanback.xml b/core/res/res/values/styles_leanback.xml
new file mode 100644
index 0000000..a37da4e
--- /dev/null
+++ b/core/res/res/values/styles_leanback.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <style name="DialogWindowTitle.Leanback" parent="DialogWindowTitle.Holo">
+        <item name="android:textAppearance">@style/TextAppearance.Leanback.DialogWindowTitle</item>
+    </style>
+
+    <style name="TextAppearance.Leanback.DialogWindowTitle" parent="TextAppearance.Holo.DialogWindowTitle">
+        <item name="android:fontFamily">sans-serif-condensed</item>
+        <item name="android:textColor">?attr/textColorPrimary</item>
+    </style>
+
+    <style name="Leanback.ButtonBar" parent="Holo.ButtonBar">
+        <item name="showDividers">none</item>
+    </style>
+
+    <style name="AlertDialog.Leanback" parent="AlertDialog.Holo">
+        <item name="layout">@android:layout/alert_dialog_leanback</item>
+        <item name="buttonPanelSideLayout">@android:layout/alert_dialog_leanback_button_panel_right</item>
+        <item name="progressLayout">@android:layout/progress_dialog_leanback</item>
+        <item name="fullDark">@android:color/background_dark</item>
+        <item name="topDark">@android:color/background_dark</item>
+        <item name="centerDark">@android:color/background_dark</item>
+        <item name="bottomDark">@android:color/background_dark</item>
+        <item name="fullBright">@android:color/background_dark</item>
+        <item name="topBright">@android:color/background_dark</item>
+        <item name="centerBright">@android:color/background_dark</item>
+        <item name="bottomBright">@android:color/background_dark</item>
+        <item name="bottomMedium">@android:color/background_dark</item>
+        <item name="centerMedium">@android:color/background_dark</item>
+    </style>
+
+    <style name="AlertDialog.Leanback.Light">
+        <item name="fullDark">@android:color/leanback_light_gray</item>
+        <item name="topDark">@android:color/leanback_light_gray</item>
+        <item name="centerDark">@android:color/leanback_light_gray</item>
+        <item name="bottomDark">@android:color/leanback_light_gray</item>
+        <item name="fullBright">@android:color/leanback_light_gray</item>
+        <item name="topBright">@android:color/leanback_light_gray</item>
+        <item name="centerBright">@android:color/leanback_light_gray</item>
+        <item name="bottomBright">@android:color/leanback_light_gray</item>
+        <item name="bottomMedium">@android:color/leanback_light_gray</item>
+        <item name="centerMedium">@android:color/leanback_light_gray</item>
+    </style>
+
+</resources>
diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml
index 52d90bc..5bac1f9 100644
--- a/core/res/res/values/styles_micro.xml
+++ b/core/res/res/values/styles_micro.xml
@@ -14,21 +14,54 @@
      limitations under the License.
 -->
 <resources>
+    <style name="AlertDialog.Micro" parent="AlertDialog.Holo.Light">
+        <item name="fullDark">@null</item>
+        <item name="topDark">@null</item>
+        <item name="centerDark">@null</item>
+        <item name="bottomDark">@null</item>
+        <item name="fullBright">@null</item>
+        <item name="topBright">@null</item>
+        <item name="centerBright">@null</item>
+        <item name="bottomBright">@null</item>
+        <item name="bottomMedium">@null</item>
+        <item name="centerMedium">@null</item>
+        <item name="layout">@layout/alert_dialog_micro</item>
+    </style>
+
+    <style name="DialogWindowTitle.Micro">
+        <item name="maxLines">1</item>
+        <item name="scrollHorizontally">true</item>
+        <item name="textAppearance">@style/TextAppearance.Micro.DialogWindowTitle</item>
+    </style>
+
+    <style name="TextAppearance.Micro" parent="TextAppearance.Holo">
+        <item name="textSize">20sp</item>
+        <item name="fontFamily">sans-serif-condensed-light</item>
+        <item name="textColor">@color/micro_text_light</item>
+    </style>
+
+    <style name="TextAppearance.Micro.DialogWindowTitle" parent="TextAppearance.Holo.DialogWindowTitle">
+        <item name="textSize">20sp</item>
+        <item name="fontFamily">sans-serif-condensed-light</item>
+        <item name="textColor">@color/micro_text_light</item>
+    </style>
+
     <style name="Widget.Micro" parent="Widget.Holo" />
 
     <style name="Widget.Micro.TextView">
-        <item name="android:fontFamily">sans-serif-condensed</item>
+        <item name="fontFamily">sans-serif-condensed</item>
     </style>
 
     <style name="Widget.Micro.NumberPicker">
-        <item name="android:internalLayout">@android:layout/number_picker_with_selector_wheel_micro</item>
-        <item name="android:solidColor">@android:color/transparent</item>
-        <item name="android:selectionDivider">@android:drawable/numberpicker_selection_divider</item>
-        <item name="android:selectionDividerHeight">0dip</item>
-        <item name="android:selectionDividersDistance">104dip</item>
-        <item name="android:internalMinWidth">64dip</item>
-        <item name="android:internalMaxHeight">180dip</item>
-        <item name="virtualButtonPressedDrawable">?android:attr/selectableItemBackground</item>
-        <item name="android:descendantFocusability">blocksDescendants</item>
+        <item name="internalLayout">@layout/number_picker_with_selector_wheel_micro</item>
+        <item name="solidColor">@color/transparent</item>
+        <item name="selectionDivider">@drawable/numberpicker_selection_divider</item>
+        <item name="selectionDividerHeight">0dip</item>
+        <item name="selectionDividersDistance">104dip</item>
+        <item name="internalMinWidth">64dip</item>
+        <item name="internalMaxHeight">180dip</item>
+        <item name="virtualButtonPressedDrawable">?attr/selectableItemBackground</item>
+        <item name="descendantFocusability">blocksDescendants</item>
     </style>
+
 </resources>
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index 57f2443..e693673 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -351,40 +351,6 @@
         <item name="textStyle">bold</item>
     </style>
 
-    <!-- Light text styles -->
-    <style name="TextAppearance.Quantum.Light" parent="TextAppearance.Quantum"/>
-    <style name="TextAppearance.Quantum.Light.Inverse" parent="TextAppearance.Quantum.Inverse"/>
-    <style name="TextAppearance.Quantum.Light.Large" parent="TextAppearance.Quantum.Large"/>
-    <style name="TextAppearance.Quantum.Light.Large.Inverse" parent="TextAppearance.Quantum.Large.Inverse"/>
-    <style name="TextAppearance.Quantum.Light.Medium" parent="TextAppearance.Quantum.Medium"/>
-    <style name="TextAppearance.Quantum.Light.Medium.Inverse" parent="TextAppearance.Quantum.Medium.Inverse"/>
-    <style name="TextAppearance.Quantum.Light.Small" parent="TextAppearance.Quantum.Small"/>
-    <style name="TextAppearance.Quantum.Light.Small.Inverse" parent="TextAppearance.Quantum.Small.Inverse"/>
-    <style name="TextAppearance.Quantum.Light.SearchResult" parent="TextAppearance.Quantum.SearchResult"/>
-    <style name="TextAppearance.Quantum.Light.SearchResult.Title" parent="TextAppearance.Quantum.SearchResult.Title"/>
-    <style name="TextAppearance.Quantum.Light.SearchResult.Subtitle" parent="TextAppearance.Quantum.SearchResult.Subtitle"/>
-    <style name="TextAppearance.Quantum.Light.Widget" parent="TextAppearance.Quantum.Widget"/>
-    <style name="TextAppearance.Quantum.Light.Widget.Button" parent="TextAppearance.Quantum.Widget.Button"/>
-    <style name="TextAppearance.Quantum.Light.Widget.EditText" parent="TextAppearance.Quantum.Widget.EditText"/>
-    <style name="TextAppearance.Quantum.Light.Widget.Switch" parent="TextAppearance.Quantum.Widget.Switch"/>
-    <style name="TextAppearance.Quantum.Light.Widget.PopupMenu" parent="TextAppearance.Quantum.Widget.PopupMenu"/>
-    <style name="TextAppearance.Quantum.Light.Widget.PopupMenu.Large" parent="TextAppearance.Quantum.Widget.PopupMenu.Large"/>
-    <style name="TextAppearance.Quantum.Light.Widget.PopupMenu.Small" parent="TextAppearance.Quantum.Widget.PopupMenu.Small"/>
-    <style name="TextAppearance.Quantum.Light.Widget.DropDownHint" parent="TextAppearance.Quantum.Widget.DropDownHint"/>
-    <style name="TextAppearance.Quantum.Light.Widget.ActionMode.Title" parent="TextAppearance.Quantum.Widget.ActionMode.Title"/>
-    <style name="TextAppearance.Quantum.Light.Widget.ActionMode.Subtitle" parent="TextAppearance.Quantum.Widget.ActionMode.Subtitle"/>
-    <style name="TextAppearance.Quantum.Light.WindowTitle" parent="TextAppearance.Quantum.WindowTitle"/>
-    <style name="TextAppearance.Quantum.Light.DialogWindowTitle" parent="TextAppearance.Quantum.DialogWindowTitle"/>
-    <style name="TextAppearance.Quantum.Light.CalendarViewWeekDayView" parent="TextAppearance.Quantum.CalendarViewWeekDayView"/>
-
-    <style name="TextAppearance.Quantum.Light.TimePicker.TimeLabel" parent="TextAppearance.Quantum.TimePicker.TimeLabel">
-        <item name="textColor">?attr/textColorSecondary</item>
-    </style>
-
-    <style name="TextAppearance.Quantum.Light.TimePicker.AmPmLabel" parent="TextAppearance.Quantum.TimePicker.AmPmLabel">
-        <item name="textColor">?attr/textColorSecondary</item>
-    </style>
-
     <!-- Widget Styles -->
 
     <style name="Quantum"/>
@@ -398,6 +364,7 @@
         <item name="textColor">?attr/textColorPrimary</item>
         <item name="minHeight">48dip</item>
         <item name="minWidth">96dip</item>
+        <item name="stateListAnimator">@anim/button_state_list_anim_quantum</item>
     </style>
 
     <!-- Small bordered ink button -->
@@ -406,19 +373,10 @@
         <item name="minWidth">48dip</item>
     </style>
 
-    <!-- Bordered paper button -->
-    <style name="Widget.Quantum.Button.Paper">
-        <!-- TODO: Specify pressed state animation. -->
-    </style>
-
-    <!-- Bordered paper button with color -->
-    <style name="Widget.Quantum.Button.Paper.Color">
-        <item name="background">@drawable/btn_color_quantum</item>
-    </style>
-
     <!-- Borderless ink button -->
     <style name="Widget.Quantum.Button.Borderless">
         <item name="background">@drawable/btn_borderless_quantum</item>
+        <item name="stateListAnimator">@null</item>
     </style>
 
     <!-- Small borderless ink button -->
@@ -427,11 +385,6 @@
         <item name="minWidth">48dip</item>
     </style>
 
-    <!-- Borderless paper button -->
-    <style name="Widget.Quantum.Button.Borderless.Paper">
-        <!-- TODO: Specify pressed state animation. -->
-    </style>
-
     <style name="Widget.Quantum.Button.Inset">
         <item name="background">@drawable/button_inset</item>
     </style>
@@ -502,10 +455,10 @@
     <style name="Widget.Quantum.CompoundButton.Switch">
         <item name="track">@drawable/switch_track_quantum</item>
         <item name="thumb">@drawable/switch_inner_quantum</item>
+        <item name="splitTrack">true</item>
         <item name="switchTextAppearance">@style/TextAppearance.Quantum.Widget.Switch</item>
         <item name="textOn"></item>
         <item name="textOff"></item>
-        <item name="thumbTextPadding">12dip</item>
         <item name="switchMinWidth">72dip</item>
         <item name="switchPadding">16dip</item>
         <item name="background">?attr/selectableItemBackground</item>
@@ -619,10 +572,8 @@
         <item name="indeterminateOnly">false</item>
         <item name="progressDrawable">@drawable/scrubber_progress_horizontal_quantum</item>
         <item name="indeterminateDrawable">@drawable/scrubber_progress_horizontal_quantum</item>
-        <item name="minHeight">13dip</item>
-        <item name="maxHeight">13dip</item>
         <item name="thumb">@drawable/scrubber_control_selector_quantum</item>
-        <item name="thumbOffset">16dip</item>
+        <item name="splitTrack">true</item>
         <item name="focusable">true</item>
         <item name="paddingStart">16dip</item>
         <item name="paddingEnd">16dip</item>
@@ -714,7 +665,8 @@
 
     <style name="Widget.Quantum.ListPopupWindow" parent="Widget.ListPopupWindow">
         <item name="dropDownSelector">@drawable/list_selector_quantum</item>
-        <item name="popupBackground">?attr/colorBackground</item>
+        <item name="popupBackground">@drawable/popup_background_quantum</item>
+        <item name="popupAnimationStyle">@style/Animation.Quantum.Popup</item>
         <item name="dropDownVerticalOffset">0dip</item>
         <item name="dropDownHorizontalOffset">0dip</item>
         <item name="dropDownWidth">wrap_content</item>
@@ -722,6 +674,10 @@
 
     <style name="Widget.Quantum.PopupMenu" parent="Widget.Quantum.ListPopupWindow"/>
 
+    <style name="Widget.Quantum.PopupMenu.Overflow">
+        <item name="overlapAnchor">true</item>
+    </style>
+
     <style name="Widget.Quantum.ActionButton" parent="Widget.ActionButton">
         <item name="minWidth">@dimen/action_button_min_width_quantum</item>
         <item name="minHeight">@dimen/action_button_min_height_quantum</item>
@@ -743,8 +699,6 @@
         <item name="scaleType">center</item>
     </style>
 
-    <style name="Widget.Quantum.ActionButton.TextButton" parent="Widget.Quantum.ButtonBar"/>
-
     <style name="Widget.Quantum.ActionBar.TabView" parent="Widget.ActionBar.TabView">
         <item name="background">@drawable/tab_indicator_quantum</item>
         <item name="paddingStart">16dip</item>
@@ -820,11 +774,8 @@
     <style name="Widget.Quantum.Light" parent="Widget.Quantum"/>
     <style name="Widget.Quantum.Light.Button" parent="Widget.Quantum.Button"/>
     <style name="Widget.Quantum.Light.Button.Small" parent="Widget.Quantum.Button.Small"/>
-    <style name="Widget.Quantum.Light.Button.Paper" parent="Widget.Quantum.Button.Paper"/>
-    <style name="Widget.Quantum.Light.Button.Paper.Color" parent="Widget.Quantum.Button.Paper.Color"/>
     <style name="Widget.Quantum.Light.Button.Borderless" parent="Widget.Quantum.Button.Borderless"/>
     <style name="Widget.Quantum.Light.Button.Borderless.Small" parent="Widget.Quantum.Button.Borderless.Small"/>
-    <style name="Widget.Quantum.Light.Button.Borderless.Paper" parent="Widget.Quantum.Button.Borderless.Paper"/>
     <style name="Widget.Quantum.Light.Button.Inset" parent="Widget.Quantum.Button.Inset"/>
 
     <style name="Widget.Quantum.Light.Button.Toggle">
@@ -842,6 +793,7 @@
         <item name="background">@drawable/btn_group_holo_light</item>
     </style>
 
+    <style name="Widget.Quantum.Light.StackView" parent="Widget.Quantum.StackView"/>
     <style name="Widget.Quantum.Light.TextView" parent="Widget.Quantum.TextView"/>
     <style name="Widget.Quantum.Light.TextView.ListSeparator" parent="Widget.Quantum.TextView.ListSeparator"/>
     <style name="Widget.Quantum.Light.TextView.SpinnerItem" parent="Widget.Quantum.TextView.SpinnerItem"/>
@@ -861,7 +813,7 @@
     <style name="Widget.Quantum.Light.CompoundButton.Star" parent="Widget.Quantum.CompoundButton.Star"/>
 
     <style name="Widget.Quantum.Light.CompoundButton.Switch" parent="Widget.Quantum.CompoundButton.Switch">
-        <item name="switchTextAppearance">@style/TextAppearance.Quantum.Light.Widget.Switch</item>
+        <item name="switchTextAppearance">@style/TextAppearance.Quantum.Widget.Switch</item>
     </style>
 
     <style name="Widget.Quantum.Light.ListView.DropDown" parent="Widget.Quantum.ListView.DropDown"/>
@@ -880,7 +832,7 @@
         <item name="unfocusedMonthDateColor">#7F08002B</item>
         <item name="weekNumberColor">#7F080021</item>
         <item name="weekSeparatorLineColor">#7F08002A</item>
-        <item name="weekDayTextAppearance">@style/TextAppearance.Quantum.Light.CalendarViewWeekDayView</item>
+        <item name="weekDayTextAppearance">@style/TextAppearance.Quantum.CalendarViewWeekDayView</item>
     </style>
 
     <style name="Widget.Quantum.Light.NumberPicker" parent="Widget.Quantum.NumberPicker"/>
@@ -960,17 +912,9 @@
     <style name="Widget.Quantum.Light.QuickContactBadgeSmall.WindowSmall" parent="Widget.Quantum.QuickContactBadgeSmall.WindowSmall"/>
     <style name="Widget.Quantum.Light.QuickContactBadgeSmall.WindowMedium" parent="Widget.Quantum.QuickContactBadgeSmall.WindowMedium"/>
     <style name="Widget.Quantum.Light.QuickContactBadgeSmall.WindowLarge" parent="Widget.Quantum.QuickContactBadgeSmall.WindowLarge"/>
-
-    <style name="Widget.Quantum.Light.ListPopupWindow" parent="Widget.ListPopupWindow">
-        <item name="dropDownSelector">@drawable/list_selector_quantum</item>
-        <item name="popupBackground">?attr/colorBackground</item>
-        <item name="dropDownVerticalOffset">0dip</item>
-        <item name="dropDownHorizontalOffset">0dip</item>
-        <item name="dropDownWidth">wrap_content</item>
-    </style>
-
-    <style name="Widget.Quantum.Light.PopupMenu" parent="Widget.Quantum.Light.ListPopupWindow"/>
-
+    <style name="Widget.Quantum.Light.ListPopupWindow" parent="Widget.Quantum.ListPopupWindow"/>
+    <style name="Widget.Quantum.Light.PopupMenu" parent="Widget.Quantum.ListPopupWindow"/>
+    <style name="Widget.Quantum.Light.PopupMenu.Overflow" parent="Widget.Quantum.PopupMenu.Overflow"/>
     <style name="Widget.Quantum.Light.ActionButton" parent="Widget.Quantum.ActionButton"/>
     <style name="Widget.Quantum.Light.ActionButton.Overflow" parent="Widget.Quantum.ActionButton.Overflow"/>
     <style name="Widget.Quantum.Light.Tab" parent="Widget.Quantum.Tab"/>
@@ -1014,7 +958,16 @@
 
     <style name="Animation.Quantum" parent="Animation"/>
     <style name="Animation.Quantum.Activity" parent="Animation.Activity"/>
-    <style name="Animation.Quantum.Dialog" parent="Animation.Dialog"/>
+
+    <style name="Animation.Quantum.Dialog">
+        <item name="windowEnterAnimation">@anim/popup_enter_quantum</item>
+        <item name="windowExitAnimation">@anim/popup_exit_quantum</item>
+    </style>
+
+    <style name="Animation.Quantum.Popup">
+        <item name="windowEnterAnimation">@anim/popup_enter_quantum</item>
+        <item name="windowExitAnimation">@anim/popup_exit_quantum</item>
+    </style>
 
     <!-- Dialog styles -->
 
@@ -1058,7 +1011,7 @@
     </style>
 
     <style name="DialogWindowTitle.Quantum.Light">
-        <item name="textAppearance">@style/TextAppearance.Quantum.Light.DialogWindowTitle</item>
+        <item name="textAppearance">@style/TextAppearance.Quantum.DialogWindowTitle</item>
     </style>
 
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d4ac74a..84c9023 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -120,6 +120,7 @@
   <java-symbol type="id" name="overlay_display_window_title" />
   <java-symbol type="id" name="package_label" />
   <java-symbol type="id" name="packages_list" />
+  <java-symbol type="id" name="parentPanel" />
   <java-symbol type="id" name="pause" />
   <java-symbol type="id" name="perms_list" />
   <java-symbol type="id" name="perm_icon" />
@@ -232,7 +233,6 @@
   <java-symbol type="attr" name="preferenceFrameLayoutStyle" />
   <java-symbol type="attr" name="searchDialogTheme" />
   <java-symbol type="attr" name="searchViewSearchIcon" />
-  <java-symbol type="attr" name="stackViewStyle" />
   <java-symbol type="attr" name="textAppearanceAutoCorrectionSuggestion" />
   <java-symbol type="attr" name="textAppearanceEasyCorrectSuggestion" />
   <java-symbol type="attr" name="textAppearanceMisspelledSuggestion" />
@@ -326,8 +326,11 @@
   <java-symbol type="color" name="tab_indicator_text_v4" />
 
   <java-symbol type="dimen" name="accessibility_touch_slop" />
+  <java-symbol type="dimen" name="alert_dialog_round_padding"/>
   <java-symbol type="dimen" name="config_prefDialogWidth" />
   <java-symbol type="dimen" name="config_viewConfigurationTouchSlop" />
+  <java-symbol type="dimen" name="config_viewMinFlingVelocity" />
+  <java-symbol type="dimen" name="config_viewMaxFlingVelocity" />
   <java-symbol type="dimen" name="default_app_widget_padding_bottom" />
   <java-symbol type="dimen" name="default_app_widget_padding_left" />
   <java-symbol type="dimen" name="default_app_widget_padding_right" />
@@ -1197,6 +1200,7 @@
   <java-symbol type="layout" name="transient_notification" />
   <java-symbol type="layout" name="volume_adjust" />
   <java-symbol type="layout" name="volume_adjust_item" />
+  <java-symbol type="layout" name="voice_interaction_session" />
   <java-symbol type="layout" name="web_text_view_dropdown" />
   <java-symbol type="layout" name="webview_find" />
   <java-symbol type="layout" name="webview_select_singlechoice" />
@@ -1268,6 +1272,7 @@
   <java-symbol type="style" name="TextAppearance.SlidingTabNormal" />
   <java-symbol type="style" name="Theme.DeviceDefault.Dialog.NoFrame" />
   <java-symbol type="style" name="Theme.IconMenu" />
+  <java-symbol type="style" name="Theme.DeviceDefault.VoiceInteractionSession" />
 
   <java-symbol type="attr" name="mediaRouteButtonStyle" />
   <java-symbol type="attr" name="externalRouteEnabledDrawable" />
@@ -1298,6 +1303,7 @@
   <java-symbol type="anim" name="dock_right_enter" />
   <java-symbol type="anim" name="dock_right_exit" />
 
+  <java-symbol type="array" name="config_hdmiCecLogicalDeviceType" />
   <java-symbol type="array" name="config_keyboardTapVibePattern" />
   <java-symbol type="array" name="config_longPressVibePattern" />
   <java-symbol type="array" name="config_safeModeDisabledVibePattern" />
@@ -1624,6 +1630,8 @@
   <java-symbol type="string" name="wifi_display_notification_connected_message" />
   <java-symbol type="string" name="wifi_display_notification_disconnect" />
   <java-symbol type="style" name="Theme.Dialog.AppError" />
+  <java-symbol type="style" name="Theme.Micro.Dialog.Alert" />
+  <java-symbol type="style" name="Theme.Leanback.Dialog.Alert" />
   <java-symbol type="style" name="Theme.Toast" />
   <java-symbol type="xml" name="storage_list" />
   <java-symbol type="bool" name="config_dreamsSupported" />
@@ -1647,8 +1655,9 @@
   <java-symbol type="id" name="resolver_list" />
   <java-symbol type="id" name="button_once" />
   <java-symbol type="id" name="button_always" />
+  <java-symbol type="integer" name="config_globalActionsKeyTimeout" />
   <java-symbol type="integer" name="config_maxResolverActivityColumns" />
-  <java-symbol type="array" name="config_notificationScorers" />
+  <java-symbol type="array" name="config_notificationSignalExtractors" />
 
   <java-symbol type="layout" name="notification_quantum_action" />
   <java-symbol type="layout" name="notification_quantum_action_list" />
@@ -1659,6 +1668,7 @@
   <java-symbol type="layout" name="notification_template_quantum_big_text" />
   <java-symbol type="layout" name="notification_template_quantum_inbox" />
   <java-symbol type="color" name="notification_action_legacy_color_filter" />
+  <java-symbol type="color" name="notification_icon_bg_color" />
   <java-symbol type="drawable" name="notification_icon_legacy_bg_inset" />
   <java-symbol type="drawable" name="notification_quantum_bg_dim" />
   <java-symbol type="drawable" name="notification_quantum_bg" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 7b3d5e3..1d9bbae 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -53,6 +53,14 @@
         <item name="colorMultiSelectHighlight">@color/legacy_selected_highlight</item>
         <item name="colorActivatedHighlight">@color/legacy_selected_highlight</item>
 
+        <item name="colorPrimaryDark">@color/legacy_primary_dark</item>
+        <item name="colorPrimary">@color/legacy_primary</item>
+        <item name="colorPrimaryLight">@color/legacy_primary_light</item>
+        <item name="colorControlActivated">@color/legacy_control_activated</item>
+        <item name="colorControlNormal">@color/legacy_control_normal</item>
+        <item name="colorButtonPressed">@color/legacy_button_pressed</item>
+        <item name="colorButtonNormal">@color/legacy_button_normal</item>
+
         <item name="disabledAlpha">0.5</item>
         <item name="backgroundDimAmount">0.6</item>
 
@@ -328,6 +336,7 @@
         <item name="actionDropDownStyle">@android:style/Widget.Spinner.DropDown</item>
         <item name="actionButtonStyle">@android:style/Widget.ActionButton</item>
         <item name="actionOverflowButtonStyle">@android:style/Widget.ActionButton.Overflow</item>
+        <item name="actionOverflowMenuStyle">?android:attr/popupMenuStyle</item>
         <item name="actionModeBackground">@android:drawable/cab_background_top_holo_dark</item>
         <item name="actionModeSplitBackground">@null</item>
         <item name="actionModeCloseDrawable">@android:drawable/ic_menu_close_clear_cancel</item>
@@ -437,6 +446,14 @@
         <item name="colorBackground">@android:color/background_light</item>
         <item name="colorForeground">@color/bright_foreground_light</item>
         <item name="colorForegroundInverse">@android:color/bright_foreground_light_inverse</item>
+
+        <item name="colorPrimaryDark">@color/legacy_light_primary_dark</item>
+        <item name="colorPrimary">@color/legacy_light_primary</item>
+        <item name="colorPrimaryLight">@color/legacy_light_primary_light</item>
+        <item name="colorControlActivated">@color/legacy_light_control_activated</item>
+        <item name="colorControlNormal">@color/legacy_light_control_normal</item>
+        <item name="colorButtonPressed">@color/legacy_light_button_pressed</item>
+        <item name="colorButtonNormal">@color/legacy_light_button_normal</item>
         
         <item name="textColorPrimary">@android:color/primary_text_light</item>
         <item name="textColorSecondary">@android:color/secondary_text_light</item>
@@ -789,6 +806,14 @@
         <item name="android:imeExtractExitAnimation">@android:anim/input_method_extract_exit</item>
     </style>
 
+    <!-- Default theme for voice interaction, which is used by the
+         {@link android.service.voice.VoiceInteractionSession} class.
+         this inherits from Theme.Panel, but sets up appropriate animations
+         and a few custom attributes. -->
+    <style name="Theme.VoiceInteractionSession" parent="Theme.Panel">
+        <item name="android:windowAnimationStyle">@android:style/Animation.VoiceInteractionSession</item>
+    </style>
+
     <!-- Default theme for holo style input methods, which is used by the
          {@link android.inputmethodservice.InputMethodService} class.
          this inherits from Theme.Panel, but sets up IME appropriate animations
@@ -937,6 +962,14 @@
         <item name="colorMultiSelectHighlight">@color/holo_green_light</item>
         <item name="colorActivatedHighlight">@color/holo_blue_dark</item>
 
+        <item name="colorPrimaryDark">@color/holo_primary_dark</item>
+        <item name="colorPrimary">@color/holo_primary</item>
+        <item name="colorPrimaryLight">@color/holo_primary_light</item>
+        <item name="colorControlActivated">@color/holo_control_activated</item>
+        <item name="colorControlNormal">@color/holo_control_normal</item>
+        <item name="colorButtonPressed">@color/holo_button_pressed</item>
+        <item name="colorButtonNormal">@color/holo_button_normal</item>
+
         <!-- Text styles -->
         <item name="textAppearance">@android:style/TextAppearance.Holo</item>
         <item name="textAppearanceInverse">@android:style/TextAppearance.Holo.Inverse</item>
@@ -1181,6 +1214,7 @@
         <item name="actionDropDownStyle">@android:style/Widget.Holo.Spinner.DropDown.ActionBar</item>
         <item name="actionButtonStyle">@android:style/Widget.Holo.ActionButton</item>
         <item name="actionOverflowButtonStyle">@android:style/Widget.Holo.ActionButton.Overflow</item>
+        <item name="actionOverflowMenuStyle">?android:attr/popupMenuStyle</item>
         <item name="actionModeBackground">@android:drawable/cab_background_top_holo_dark</item>
         <item name="actionModeSplitBackground">@android:drawable/cab_background_bottom_holo_dark</item>
         <item name="actionModeCloseDrawable">@android:drawable/ic_cab_done_holo_dark</item>
@@ -1268,6 +1302,14 @@
         <item name="colorMultiSelectHighlight">@color/holo_green_light</item>
         <item name="colorActivatedHighlight">@color/holo_blue_dark</item>
 
+        <item name="colorPrimaryDark">@color/holo_light_primary_dark</item>
+        <item name="colorPrimary">@color/holo_light_primary</item>
+        <item name="colorPrimaryLight">@color/holo_light_primary_light</item>
+        <item name="colorControlActivated">@color/holo_light_control_activated</item>
+        <item name="colorControlNormal">@color/holo_light_control_normal</item>
+        <item name="colorButtonPressed">@color/holo_light_button_pressed</item>
+        <item name="colorButtonNormal">@color/holo_light_button_normal</item>
+
         <!-- Text styles -->
         <item name="textAppearance">@android:style/TextAppearance.Holo.Light</item>
         <item name="textAppearanceInverse">@android:style/TextAppearance.Holo.Light.Inverse</item>
@@ -1769,12 +1811,7 @@
         <item name="android:windowCloseOnTouchOutside">false</item>
     </style>
 
-    <!-- Holo theme for alert dialog windows, which is used by the
-         {@link android.app.AlertDialog} class.  This is basically a dialog
-         but sets the background to empty so it can do two-tone backgrounds.
-         For applications targeting Honeycomb or newer, this is the default
-         AlertDialog theme. -->
-    <style name="Theme.Holo.Dialog.Alert">
+    <style name="Theme.Holo.Dialog.BaseAlert">
         <item name="windowBackground">@android:color/transparent</item>
         <item name="windowTitleStyle">@android:style/DialogWindowTitle.Holo</item>
         <item name="windowContentOverlay">@null</item>
@@ -1782,6 +1819,13 @@
         <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
     </style>
 
+    <!-- Holo theme for alert dialog windows, which is used by the
+         {@link android.app.AlertDialog} class.  This is basically a dialog
+         but sets the background to empty so it can do two-tone backgrounds.
+         For applications targeting Honeycomb or newer, this is the default
+         AlertDialog theme. -->
+    <style name="Theme.Holo.Dialog.Alert" parent="Theme.Holo.Dialog.BaseAlert"/>
+
     <!-- Holo theme for the TimePicker dialog windows, which is used by the
          {@link android.app.TimePickerDialog} class. -->
     <style name="Theme.Holo.Dialog.TimePicker">
@@ -1892,12 +1936,7 @@
             parent="@android:style/Theme.Holo.Light.NoActionBar">
     </style>
 
-    <!-- Holo light theme for alert dialog windows, which is used by the
-         {@link android.app.AlertDialog} class.  This is basically a dialog
-         but sets the background to empty so it can do two-tone backgrounds.
-         For applications targeting Honeycomb or newer, this is the default
-         AlertDialog theme. -->
-    <style name="Theme.Holo.Light.Dialog.Alert">
+    <style name="Theme.Holo.Light.Dialog.BaseAlert">
         <item name="windowBackground">@android:color/transparent</item>
         <item name="windowTitleStyle">@android:style/DialogWindowTitle.Holo.Light</item>
         <item name="windowContentOverlay">@null</item>
@@ -1905,6 +1944,13 @@
         <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
     </style>
 
+    <!-- Holo light theme for alert dialog windows, which is used by the
+         {@link android.app.AlertDialog} class.  This is basically a dialog
+         but sets the background to empty so it can do two-tone backgrounds.
+         For applications targeting Honeycomb or newer, this is the default
+         AlertDialog theme. -->
+    <style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Holo.Light.Dialog.BaseAlert"/>
+
     <!-- Holo Light theme for the TimePicker dialog windows, which is used by the
          {@link android.app.TimePickerDialog} class. -->
     <style name="Theme.Holo.Light.Dialog.TimePicker">
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 0ce5094..dbc3d9e 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -51,139 +51,139 @@
           -->
     <style name="Theme.DeviceDefault" parent="Theme.Quantum" >
         <!-- Text styles -->
-        <item name="textAppearance">@android:style/TextAppearance.DeviceDefault</item>
-        <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Inverse</item>
+        <item name="textAppearance">@style/TextAppearance.DeviceDefault</item>
+        <item name="textAppearanceInverse">@style/TextAppearance.DeviceDefault.Inverse</item>
 
-        <item name="textAppearanceLarge">@android:style/TextAppearance.DeviceDefault.Large</item>
-        <item name="textAppearanceMedium">@android:style/TextAppearance.DeviceDefault.Medium</item>
-        <item name="textAppearanceSmall">@android:style/TextAppearance.DeviceDefault.Small</item>
-        <item name="textAppearanceLargeInverse">@android:style/TextAppearance.DeviceDefault.Large.Inverse</item>
-        <item name="textAppearanceMediumInverse">@android:style/TextAppearance.DeviceDefault.Medium.Inverse</item>
-        <item name="textAppearanceSmallInverse">@android:style/TextAppearance.DeviceDefault.Small.Inverse</item>
-        <item name="textAppearanceSearchResultTitle">@android:style/TextAppearance.DeviceDefault.SearchResult.Title</item>
-        <item name="textAppearanceSearchResultSubtitle">@android:style/TextAppearance.DeviceDefault.SearchResult.Subtitle</item>
+        <item name="textAppearanceLarge">@style/TextAppearance.DeviceDefault.Large</item>
+        <item name="textAppearanceMedium">@style/TextAppearance.DeviceDefault.Medium</item>
+        <item name="textAppearanceSmall">@style/TextAppearance.DeviceDefault.Small</item>
+        <item name="textAppearanceLargeInverse">@style/TextAppearance.DeviceDefault.Large.Inverse</item>
+        <item name="textAppearanceMediumInverse">@style/TextAppearance.DeviceDefault.Medium.Inverse</item>
+        <item name="textAppearanceSmallInverse">@style/TextAppearance.DeviceDefault.Small.Inverse</item>
+        <item name="textAppearanceSearchResultTitle">@style/TextAppearance.DeviceDefault.SearchResult.Title</item>
+        <item name="textAppearanceSearchResultSubtitle">@style/TextAppearance.DeviceDefault.SearchResult.Subtitle</item>
 
-        <item name="textAppearanceButton">@android:style/TextAppearance.DeviceDefault.Widget.Button</item>
+        <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
 
-        <item name="textAppearanceLargePopupMenu">@android:style/TextAppearance.DeviceDefault.Widget.PopupMenu.Large</item>
-        <item name="textAppearanceSmallPopupMenu">@android:style/TextAppearance.DeviceDefault.Widget.PopupMenu.Small</item>
+        <item name="textAppearanceLargePopupMenu">@style/TextAppearance.DeviceDefault.Widget.PopupMenu.Large</item>
+        <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.DeviceDefault.Widget.PopupMenu.Small</item>
 
         <!-- Button styles -->
-        <item name="buttonStyle">@android:style/Widget.DeviceDefault.Button</item>
+        <item name="buttonStyle">@style/Widget.DeviceDefault.Button</item>
 
-        <item name="buttonStyleSmall">@android:style/Widget.DeviceDefault.Button.Small</item>
-        <item name="buttonStyleInset">@android:style/Widget.DeviceDefault.Button.Inset</item>
+        <item name="buttonStyleSmall">@style/Widget.DeviceDefault.Button.Small</item>
+        <item name="buttonStyleInset">@style/Widget.DeviceDefault.Button.Inset</item>
 
-        <item name="buttonStyleToggle">@android:style/Widget.DeviceDefault.Button.Toggle</item>
-        <item name="switchStyle">@android:style/Widget.DeviceDefault.CompoundButton.Switch</item>
+        <item name="buttonStyleToggle">@style/Widget.DeviceDefault.Button.Toggle</item>
+        <item name="switchStyle">@style/Widget.DeviceDefault.CompoundButton.Switch</item>
 
-        <item name="borderlessButtonStyle">@android:style/Widget.DeviceDefault.Button.Borderless</item>
+        <item name="borderlessButtonStyle">@style/Widget.DeviceDefault.Button.Borderless</item>
 
-        <item name="listSeparatorTextViewStyle">@android:style/Widget.DeviceDefault.TextView.ListSeparator</item>
+        <item name="listSeparatorTextViewStyle">@style/Widget.DeviceDefault.TextView.ListSeparator</item>
 
         <!-- Window attributes -->
-        <item name="windowTitleStyle">@android:style/WindowTitle.DeviceDefault</item>
-        <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground.DeviceDefault</item>
-        <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Activity</item>
+        <item name="windowTitleStyle">@style/WindowTitle.DeviceDefault</item>
+        <item name="windowTitleBackgroundStyle">@style/WindowTitleBackground.DeviceDefault</item>
+        <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Activity</item>
 
         <!-- Dialog attributes -->
-        <item name="dialogTheme">@android:style/Theme.DeviceDefault.Dialog</item>
+        <item name="dialogTheme">@style/Theme.DeviceDefault.Dialog</item>
 
         <!-- AlertDialog attributes -->
-        <item name="alertDialogTheme">@android:style/Theme.DeviceDefault.Dialog.Alert</item>
-        <item name="alertDialogStyle">@android:style/AlertDialog.DeviceDefault</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+        <item name="alertDialogStyle">@style/AlertDialog.DeviceDefault</item>
 
         <!-- Presentation attributes -->
-        <item name="presentationTheme">@android:style/Theme.DeviceDefault.Dialog.Presentation</item>
+        <item name="presentationTheme">@style/Theme.DeviceDefault.Dialog.Presentation</item>
 
         <!-- Text selection handle attributes -->
-        <item name="textSelectHandleWindowStyle">@android:style/Widget.DeviceDefault.TextSelectHandle</item>
-        <item name="textSuggestionsWindowStyle">@android:style/Widget.DeviceDefault.TextSuggestionsPopupWindow</item>
+        <item name="textSelectHandleWindowStyle">@style/Widget.DeviceDefault.TextSelectHandle</item>
+        <item name="textSuggestionsWindowStyle">@style/Widget.DeviceDefault.TextSuggestionsPopupWindow</item>
 
         <!-- Widget styles -->
-        <item name="absListViewStyle">@android:style/Widget.DeviceDefault.AbsListView</item>
-        <item name="autoCompleteTextViewStyle">@android:style/Widget.DeviceDefault.AutoCompleteTextView</item>
-        <item name="checkboxStyle">@android:style/Widget.DeviceDefault.CompoundButton.CheckBox</item>
-        <item name="checkedTextViewStyle">@android:style/Widget.DeviceDefault.CheckedTextView</item>
-        <item name="dropDownListViewStyle">@android:style/Widget.DeviceDefault.ListView.DropDown</item>
-        <item name="editTextStyle">@android:style/Widget.DeviceDefault.EditText</item>
-        <item name="expandableListViewStyle">@android:style/Widget.DeviceDefault.ExpandableListView</item>
-        <item name="expandableListViewWhiteStyle">@android:style/Widget.DeviceDefault.ExpandableListView.White</item>
-        <item name="galleryStyle">@android:style/Widget.DeviceDefault.Gallery</item>
-        <item name="gestureOverlayViewStyle">@android:style/Widget.DeviceDefault.GestureOverlayView</item>
-        <item name="gridViewStyle">@android:style/Widget.DeviceDefault.GridView</item>
-        <item name="imageButtonStyle">@android:style/Widget.DeviceDefault.ImageButton</item>
-        <item name="imageWellStyle">@android:style/Widget.DeviceDefault.ImageWell</item>
-        <item name="listViewStyle">@android:style/Widget.DeviceDefault.ListView</item>
-        <item name="listViewWhiteStyle">@android:style/Widget.DeviceDefault.ListView.White</item>
-        <item name="popupWindowStyle">@android:style/Widget.DeviceDefault.PopupWindow</item>
-        <item name="progressBarStyle">@android:style/Widget.DeviceDefault.ProgressBar</item>
-        <item name="progressBarStyleHorizontal">@android:style/Widget.DeviceDefault.ProgressBar.Horizontal</item>
-        <item name="progressBarStyleSmall">@android:style/Widget.DeviceDefault.ProgressBar.Small</item>
-        <item name="progressBarStyleSmallTitle">@android:style/Widget.DeviceDefault.ProgressBar.Small.Title</item>
-        <item name="progressBarStyleLarge">@android:style/Widget.DeviceDefault.ProgressBar.Large</item>
-        <item name="progressBarStyleInverse">@android:style/Widget.DeviceDefault.ProgressBar.Inverse</item>
-        <item name="progressBarStyleSmallInverse">@android:style/Widget.DeviceDefault.ProgressBar.Small.Inverse</item>
-        <item name="progressBarStyleLargeInverse">@android:style/Widget.DeviceDefault.ProgressBar.Large.Inverse</item>
-        <item name="seekBarStyle">@android:style/Widget.DeviceDefault.SeekBar</item>
-        <item name="ratingBarStyle">@android:style/Widget.DeviceDefault.RatingBar</item>
-        <item name="ratingBarStyleIndicator">@android:style/Widget.DeviceDefault.RatingBar.Indicator</item>
-        <item name="ratingBarStyleSmall">@android:style/Widget.DeviceDefault.RatingBar.Small</item>
-        <item name="radioButtonStyle">@android:style/Widget.DeviceDefault.CompoundButton.RadioButton</item>
-        <item name="scrollViewStyle">@android:style/Widget.DeviceDefault.ScrollView</item>
-        <item name="horizontalScrollViewStyle">@android:style/Widget.DeviceDefault.HorizontalScrollView</item>
-        <item name="dropDownSpinnerStyle">@android:style/Widget.DeviceDefault.Spinner.DropDown</item>
-        <item name="starStyle">@android:style/Widget.DeviceDefault.CompoundButton.Star</item>
-        <item name="tabWidgetStyle">@android:style/Widget.DeviceDefault.TabWidget</item>
-        <item name="textViewStyle">@android:style/Widget.DeviceDefault.TextView</item>
-        <item name="webTextViewStyle">@android:style/Widget.DeviceDefault.WebTextView</item>
-        <item name="webViewStyle">@android:style/Widget.DeviceDefault.WebView</item>
-        <item name="dropDownItemStyle">@android:style/Widget.DeviceDefault.DropDownItem</item>
-        <item name="spinnerDropDownItemStyle">@android:style/Widget.DeviceDefault.DropDownItem.Spinner</item>
-        <item name="spinnerItemStyle">@android:style/Widget.DeviceDefault.TextView.SpinnerItem</item>
-        <item name="dropDownHintAppearance">@android:style/TextAppearance.DeviceDefault.Widget.DropDownHint</item>
-        <item name="keyboardViewStyle">@android:style/Widget.DeviceDefault.KeyboardView</item>
-        <item name="quickContactBadgeStyleWindowSmall">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowSmall</item>
-        <item name="quickContactBadgeStyleWindowMedium">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowMedium</item>
-        <item name="quickContactBadgeStyleWindowLarge">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowLarge</item>
-        <item name="quickContactBadgeStyleSmallWindowSmall">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowSmall</item>
-        <item name="quickContactBadgeStyleSmallWindowMedium">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowMedium</item>
-        <item name="quickContactBadgeStyleSmallWindowLarge">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowLarge</item>
-        <item name="listPopupWindowStyle">@android:style/Widget.DeviceDefault.ListPopupWindow</item>
-        <item name="popupMenuStyle">@android:style/Widget.DeviceDefault.PopupMenu</item>
-        <item name="stackViewStyle">@android:style/Widget.DeviceDefault.StackView</item>
+        <item name="absListViewStyle">@style/Widget.DeviceDefault.AbsListView</item>
+        <item name="autoCompleteTextViewStyle">@style/Widget.DeviceDefault.AutoCompleteTextView</item>
+        <item name="checkboxStyle">@style/Widget.DeviceDefault.CompoundButton.CheckBox</item>
+        <item name="checkedTextViewStyle">@style/Widget.DeviceDefault.CheckedTextView</item>
+        <item name="dropDownListViewStyle">@style/Widget.DeviceDefault.ListView.DropDown</item>
+        <item name="editTextStyle">@style/Widget.DeviceDefault.EditText</item>
+        <item name="expandableListViewStyle">@style/Widget.DeviceDefault.ExpandableListView</item>
+        <item name="expandableListViewWhiteStyle">@style/Widget.DeviceDefault.ExpandableListView.White</item>
+        <item name="galleryStyle">@style/Widget.DeviceDefault.Gallery</item>
+        <item name="gestureOverlayViewStyle">@style/Widget.DeviceDefault.GestureOverlayView</item>
+        <item name="gridViewStyle">@style/Widget.DeviceDefault.GridView</item>
+        <item name="imageButtonStyle">@style/Widget.DeviceDefault.ImageButton</item>
+        <item name="imageWellStyle">@style/Widget.DeviceDefault.ImageWell</item>
+        <item name="listViewStyle">@style/Widget.DeviceDefault.ListView</item>
+        <item name="listViewWhiteStyle">@style/Widget.DeviceDefault.ListView.White</item>
+        <item name="popupWindowStyle">@style/Widget.DeviceDefault.PopupWindow</item>
+        <item name="progressBarStyle">@style/Widget.DeviceDefault.ProgressBar</item>
+        <item name="progressBarStyleHorizontal">@style/Widget.DeviceDefault.ProgressBar.Horizontal</item>
+        <item name="progressBarStyleSmall">@style/Widget.DeviceDefault.ProgressBar.Small</item>
+        <item name="progressBarStyleSmallTitle">@style/Widget.DeviceDefault.ProgressBar.Small.Title</item>
+        <item name="progressBarStyleLarge">@style/Widget.DeviceDefault.ProgressBar.Large</item>
+        <item name="progressBarStyleInverse">@style/Widget.DeviceDefault.ProgressBar.Inverse</item>
+        <item name="progressBarStyleSmallInverse">@style/Widget.DeviceDefault.ProgressBar.Small.Inverse</item>
+        <item name="progressBarStyleLargeInverse">@style/Widget.DeviceDefault.ProgressBar.Large.Inverse</item>
+        <item name="seekBarStyle">@style/Widget.DeviceDefault.SeekBar</item>
+        <item name="ratingBarStyle">@style/Widget.DeviceDefault.RatingBar</item>
+        <item name="ratingBarStyleIndicator">@style/Widget.DeviceDefault.RatingBar.Indicator</item>
+        <item name="ratingBarStyleSmall">@style/Widget.DeviceDefault.RatingBar.Small</item>
+        <item name="radioButtonStyle">@style/Widget.DeviceDefault.CompoundButton.RadioButton</item>
+        <item name="scrollViewStyle">@style/Widget.DeviceDefault.ScrollView</item>
+        <item name="horizontalScrollViewStyle">@style/Widget.DeviceDefault.HorizontalScrollView</item>
+        <item name="dropDownSpinnerStyle">@style/Widget.DeviceDefault.Spinner.DropDown</item>
+        <item name="starStyle">@style/Widget.DeviceDefault.CompoundButton.Star</item>
+        <item name="tabWidgetStyle">@style/Widget.DeviceDefault.TabWidget</item>
+        <item name="textViewStyle">@style/Widget.DeviceDefault.TextView</item>
+        <item name="webTextViewStyle">@style/Widget.DeviceDefault.WebTextView</item>
+        <item name="webViewStyle">@style/Widget.DeviceDefault.WebView</item>
+        <item name="dropDownItemStyle">@style/Widget.DeviceDefault.DropDownItem</item>
+        <item name="spinnerDropDownItemStyle">@style/Widget.DeviceDefault.DropDownItem.Spinner</item>
+        <item name="spinnerItemStyle">@style/Widget.DeviceDefault.TextView.SpinnerItem</item>
+        <item name="dropDownHintAppearance">@style/TextAppearance.DeviceDefault.Widget.DropDownHint</item>
+        <item name="keyboardViewStyle">@style/Widget.DeviceDefault.KeyboardView</item>
+        <item name="quickContactBadgeStyleWindowSmall">@style/Widget.DeviceDefault.QuickContactBadge.WindowSmall</item>
+        <item name="quickContactBadgeStyleWindowMedium">@style/Widget.DeviceDefault.QuickContactBadge.WindowMedium</item>
+        <item name="quickContactBadgeStyleWindowLarge">@style/Widget.DeviceDefault.QuickContactBadge.WindowLarge</item>
+        <item name="quickContactBadgeStyleSmallWindowSmall">@style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowSmall</item>
+        <item name="quickContactBadgeStyleSmallWindowMedium">@style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowMedium</item>
+        <item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowLarge</item>
+        <item name="listPopupWindowStyle">@style/Widget.DeviceDefault.ListPopupWindow</item>
+        <item name="popupMenuStyle">@style/Widget.DeviceDefault.PopupMenu</item>
+        <item name="stackViewStyle">@style/Widget.DeviceDefault.StackView</item>
 
         <!-- Preference styles -->
-        <item name="preferenceScreenStyle">@android:style/Preference.DeviceDefault.PreferenceScreen</item>
-        <item name="preferenceCategoryStyle">@android:style/Preference.DeviceDefault.Category</item>
-        <item name="preferenceStyle">@android:style/Preference.DeviceDefault</item>
-        <item name="preferenceInformationStyle">@android:style/Preference.DeviceDefault.Information</item>
-        <item name="checkBoxPreferenceStyle">@android:style/Preference.DeviceDefault.CheckBoxPreference</item>
-        <item name="switchPreferenceStyle">@android:style/Preference.DeviceDefault.SwitchPreference</item>
-        <item name="yesNoPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference.YesNoPreference</item>
-        <item name="dialogPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference</item>
-        <item name="editTextPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference.EditTextPreference</item>
-        <item name="ringtonePreferenceStyle">@android:style/Preference.DeviceDefault.RingtonePreference</item>
+        <item name="preferenceScreenStyle">@style/Preference.DeviceDefault.PreferenceScreen</item>
+        <item name="preferenceCategoryStyle">@style/Preference.DeviceDefault.Category</item>
+        <item name="preferenceStyle">@style/Preference.DeviceDefault</item>
+        <item name="preferenceInformationStyle">@style/Preference.DeviceDefault.Information</item>
+        <item name="checkBoxPreferenceStyle">@style/Preference.DeviceDefault.CheckBoxPreference</item>
+        <item name="switchPreferenceStyle">@style/Preference.DeviceDefault.SwitchPreference</item>
+        <item name="yesNoPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference.YesNoPreference</item>
+        <item name="dialogPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference</item>
+        <item name="editTextPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference.EditTextPreference</item>
+        <item name="ringtonePreferenceStyle">@style/Preference.DeviceDefault.RingtonePreference</item>
 
         <!-- Action bar styles -->
-        <item name="actionDropDownStyle">@android:style/Widget.DeviceDefault.Spinner.DropDown.ActionBar</item>
-        <item name="actionButtonStyle">@android:style/Widget.DeviceDefault.ActionButton</item>
-        <item name="actionOverflowButtonStyle">@android:style/Widget.DeviceDefault.ActionButton.Overflow</item>
+        <item name="actionDropDownStyle">@style/Widget.DeviceDefault.Spinner.DropDown.ActionBar</item>
+        <item name="actionButtonStyle">@style/Widget.DeviceDefault.ActionButton</item>
+        <item name="actionOverflowButtonStyle">@style/Widget.DeviceDefault.ActionButton.Overflow</item>
         <item name="actionBarTabStyle">@style/Widget.DeviceDefault.ActionBar.TabView</item>
         <item name="actionBarTabBarStyle">@style/Widget.DeviceDefault.ActionBar.TabBar</item>
         <item name="actionBarTabTextStyle">@style/Widget.DeviceDefault.ActionBar.TabText</item>
         <item name="actionModeStyle">@style/Widget.DeviceDefault.ActionMode</item>
         <item name="actionModeCloseButtonStyle">@style/Widget.DeviceDefault.ActionButton.CloseMode</item>
-        <item name="actionBarStyle">@android:style/Widget.DeviceDefault.ActionBar</item>
-        <item name="actionModePopupWindowStyle">@android:style/Widget.DeviceDefault.PopupWindow.ActionMode</item>
+        <item name="actionBarStyle">@style/Widget.DeviceDefault.ActionBar</item>
+        <item name="actionModePopupWindowStyle">@style/Widget.DeviceDefault.PopupWindow.ActionMode</item>
 
-        <item name="buttonBarStyle">@android:style/DeviceDefault.ButtonBar</item>
-        <item name="segmentedButtonStyle">@android:style/DeviceDefault.SegmentedButton</item>
+        <item name="buttonBarStyle">@style/DeviceDefault.ButtonBar</item>
+        <item name="segmentedButtonStyle">@style/DeviceDefault.SegmentedButton</item>
 
         <item name="searchDialogTheme">@style/Theme.DeviceDefault.SearchBar</item>
 
         <!-- PreferenceFrameLayout attributes -->
-        <item name="preferenceFrameLayoutStyle">@android:style/Widget.DeviceDefault.PreferenceFrameLayout</item>
+        <item name="preferenceFrameLayoutStyle">@style/Widget.DeviceDefault.PreferenceFrameLayout</item>
 
         <!-- NumberPicker style-->
         <item name="numberPickerStyle">@style/Widget.DeviceDefault.NumberPicker</item>
@@ -201,165 +201,245 @@
         <item name="timePickerHeaderAmPmLabelTextAppearance">@style/TextAppearance.DeviceDefault.TimePicker.AmPmLabel</item>
 
         <!-- TimePicker dialog theme -->
-        <item name="timePickerDialogTheme">@android:style/Theme.DeviceDefault.Dialog.TimePicker</item>
+        <item name="timePickerDialogTheme">@style/Theme.DeviceDefault.Dialog.TimePicker</item>
 
         <!-- DatePicker style -->
         <item name="datePickerStyle">@style/Widget.DeviceDefault.DatePicker</item>
 
-        <item name="mediaRouteButtonStyle">@android:style/Widget.DeviceDefault.MediaRouteButton</item>
+        <item name="mediaRouteButtonStyle">@style/Widget.DeviceDefault.MediaRouteButton</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar -->
-    <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Quantum.NoActionBar" >
-    </style>
+    <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Quantum.NoActionBar"  />
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar.  This theme
          sets {@link android.R.attr#windowFullscreen} to true.  -->
-    <style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Quantum.NoActionBar.Fullscreen" >
-    </style>
+    <style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Quantum.NoActionBar.Fullscreen"  />
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
     extending in to overscan region.  This theme
     sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
     to true. -->
-    <style name="Theme.DeviceDefault.NoActionBar.Overscan" parent="Theme.Quantum.NoActionBar.Overscan" >
-    </style>
+    <style name="Theme.DeviceDefault.NoActionBar.Overscan" parent="Theme.Quantum.NoActionBar.Overscan"  />
 
     <!-- Variant of {@link #Theme_DeviceDefault} 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.DeviceDefault.NoActionBar.TranslucentDecor" parent="Theme.Quantum.NoActionBar.TranslucentDecor" >
+    <style name="Theme.DeviceDefault.NoActionBar.TranslucentDecor" parent="Theme.Quantum.NoActionBar.TranslucentDecor"  />
+
+    <!-- DeviceDefault theme for dialog windows and activities. 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.DeviceDefault.Dialog" parent="Theme.Quantum.Dialog" >
+        <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
+        <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
+
+        <item name="buttonBarStyle">@style/DeviceDefault.ButtonBar.AlertDialog</item>
+        <item name="borderlessButtonStyle">@style/Widget.DeviceDefault.Button.Borderless.Small</item>
+
+        <item name="textAppearance">@style/TextAppearance.DeviceDefault</item>
+        <item name="textAppearanceInverse">@style/TextAppearance.DeviceDefault.Inverse</item>
     </style>
 
+    <!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
+    regular dialog. -->
+    <style name="Theme.DeviceDefault.Dialog.MinWidth" parent="Theme.Quantum.Dialog.MinWidth" />
+
+    <!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
+    <style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="Theme.Quantum.Dialog.NoActionBar" />
+
+    <!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
+    for a regular dialog. -->
+    <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Quantum.Dialog.NoActionBar.MinWidth" />
+
+    <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
+    <style name="Theme.DeviceDefault.Dialog.FixedSize">
+        <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
+        <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
+        <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
+        <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+    </style>
+
+    <!-- Variant of Theme.DeviceDefault.Dialog.NoActionBar that has a fixed size. -->
+    <style name="Theme.DeviceDefault.Dialog.NoActionBar.FixedSize">
+        <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
+        <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
+        <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
+        <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+    </style>
+
+    <!-- DeviceDefault 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.DeviceDefault.DialogWhenLarge" parent="Theme.Quantum.DialogWhenLarge"  />
+
+    <!-- DeviceDefault 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.DeviceDefault.DialogWhenLarge.NoActionBar" parent="Theme.Quantum.DialogWhenLarge.NoActionBar"  />
+
+    <!-- DeviceDefault theme for a presentation window on a secondary display. -->
+    <style name="Theme.DeviceDefault.Dialog.Presentation" parent="Theme.Quantum.Dialog.Presentation" />
+
+    <style name="Theme.DeviceDefault.Dialog.TimePicker" parent="Theme.Quantum.Dialog.TimePicker"/>
+
+    <!-- DeviceDefault 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.DeviceDefault.Panel" parent="Theme.Quantum.Panel"  />
+
+    <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
+    behind them. -->
+    <style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Quantum.Wallpaper"  />
+
+    <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
+    behind them and without an action bar. -->
+    <style name="Theme.DeviceDefault.Wallpaper.NoTitleBar" parent="Theme.Quantum.Wallpaper.NoTitleBar"  />
+
+    <!-- DeviceDefault style for input methods, which is used by the
+         {@link android.inputmethodservice.InputMethodService} class.-->
+    <style name="Theme.DeviceDefault.InputMethod" parent="Theme.Quantum.InputMethod"  />
+
+    <!-- DeviceDefault style for input methods, which is used by the
+         {@link android.service.voice.VoiceInteractionSession} class.-->
+    <style name="Theme.DeviceDefault.VoiceInteractionSession" parent="Theme.Quantum.VoiceInteractionSession" >
+
+    </style>
+    <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Quantum.Dialog.Alert">
+        <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
+    </style>
+
+    <style name="Theme.DeviceDefault.SearchBar" parent="Theme.Quantum.SearchBar" />
+    <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Quantum.Dialog.NoFrame" />
+
     <!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
     <style name="Theme.DeviceDefault.Light" parent="Theme.Quantum.Light" >
         <!-- Text styles -->
-        <item name="textAppearance">@android:style/TextAppearance.DeviceDefault.Light</item>
-        <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Light.Inverse</item>
+        <item name="textAppearance">@style/TextAppearance.DeviceDefault</item>
+        <item name="textAppearanceInverse">@style/TextAppearance.DeviceDefault.Inverse</item>
 
-        <item name="textAppearanceLarge">@android:style/TextAppearance.DeviceDefault.Light.Large</item>
-        <item name="textAppearanceMedium">@android:style/TextAppearance.DeviceDefault.Light.Medium</item>
-        <item name="textAppearanceSmall">@android:style/TextAppearance.DeviceDefault.Light.Small</item>
-        <item name="textAppearanceLargeInverse">@android:style/TextAppearance.DeviceDefault.Light.Large.Inverse</item>
-        <item name="textAppearanceMediumInverse">@android:style/TextAppearance.DeviceDefault.Light.Medium.Inverse</item>
-        <item name="textAppearanceSmallInverse">@android:style/TextAppearance.DeviceDefault.Light.Small.Inverse</item>
-        <item name="textAppearanceSearchResultTitle">@android:style/TextAppearance.DeviceDefault.Light.SearchResult.Title</item>
-        <item name="textAppearanceSearchResultSubtitle">@android:style/TextAppearance.DeviceDefault.Light.SearchResult.Subtitle</item>
+        <item name="textAppearanceLarge">@style/TextAppearance.DeviceDefault.Large</item>
+        <item name="textAppearanceMedium">@style/TextAppearance.DeviceDefault.Medium</item>
+        <item name="textAppearanceSmall">@style/TextAppearance.DeviceDefault.Small</item>
+        <item name="textAppearanceLargeInverse">@style/TextAppearance.DeviceDefault.Large.Inverse</item>
+        <item name="textAppearanceMediumInverse">@style/TextAppearance.DeviceDefault.Medium.Inverse</item>
+        <item name="textAppearanceSmallInverse">@style/TextAppearance.DeviceDefault.Small.Inverse</item>
+        <item name="textAppearanceSearchResultTitle">@style/TextAppearance.DeviceDefault.SearchResult.Title</item>
+        <item name="textAppearanceSearchResultSubtitle">@style/TextAppearance.DeviceDefault.SearchResult.Subtitle</item>
 
-        <item name="textAppearanceButton">@android:style/TextAppearance.DeviceDefault.Light.Widget.Button</item>
+        <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
 
-        <item name="textAppearanceLargePopupMenu">@android:style/TextAppearance.DeviceDefault.Light.Widget.PopupMenu.Large</item>
-        <item name="textAppearanceSmallPopupMenu">@android:style/TextAppearance.DeviceDefault.Light.Widget.PopupMenu.Small</item>
+        <item name="textAppearanceLargePopupMenu">@style/TextAppearance.DeviceDefault.Widget.PopupMenu.Large</item>
+        <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.DeviceDefault.Widget.PopupMenu.Small</item>
 
         <!-- Button styles -->
-        <item name="buttonStyle">@android:style/Widget.DeviceDefault.Light.Button</item>
+        <item name="buttonStyle">@style/Widget.DeviceDefault.Light.Button</item>
 
-        <item name="buttonStyleSmall">@android:style/Widget.DeviceDefault.Light.Button.Small</item>
-        <item name="buttonStyleInset">@android:style/Widget.DeviceDefault.Light.Button.Inset</item>
+        <item name="buttonStyleSmall">@style/Widget.DeviceDefault.Light.Button.Small</item>
+        <item name="buttonStyleInset">@style/Widget.DeviceDefault.Light.Button.Inset</item>
 
-        <item name="buttonStyleToggle">@android:style/Widget.DeviceDefault.Light.Button.Toggle</item>
+        <item name="buttonStyleToggle">@style/Widget.DeviceDefault.Light.Button.Toggle</item>
 
-        <item name="borderlessButtonStyle">@android:style/Widget.DeviceDefault.Light.Button.Borderless</item>
+        <item name="borderlessButtonStyle">@style/Widget.DeviceDefault.Light.Button.Borderless</item>
 
-        <item name="listSeparatorTextViewStyle">@android:style/Widget.DeviceDefault.Light.TextView.ListSeparator</item>
+        <item name="listSeparatorTextViewStyle">@style/Widget.DeviceDefault.Light.TextView.ListSeparator</item>
 
-        <item name="windowTitleStyle">@android:style/WindowTitle.DeviceDefault</item>
-        <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground.DeviceDefault</item>
-        <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Activity</item>
+        <item name="windowTitleStyle">@style/WindowTitle.DeviceDefault</item>
+        <item name="windowTitleBackgroundStyle">@style/WindowTitleBackground.DeviceDefault</item>
+        <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Activity</item>
 
         <!-- Dialog attributes -->
-        <item name="dialogTheme">@android:style/Theme.DeviceDefault.Light.Dialog</item>
+        <item name="dialogTheme">@style/Theme.DeviceDefault.Light.Dialog</item>
 
         <!-- AlertDialog attributes -->
-        <item name="alertDialogTheme">@android:style/Theme.DeviceDefault.Light.Dialog.Alert</item>
-        <item name="alertDialogStyle">@android:style/AlertDialog.DeviceDefault.Light</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+        <item name="alertDialogStyle">@style/AlertDialog.DeviceDefault.Light</item>
 
         <!-- Presentation attributes -->
-        <item name="presentationTheme">@android:style/Theme.DeviceDefault.Light.Dialog.Presentation</item>
+        <item name="presentationTheme">@style/Theme.DeviceDefault.Light.Dialog.Presentation</item>
 
         <!-- Text selection handle attributes -->
-        <item name="textSelectHandleWindowStyle">@android:style/Widget.DeviceDefault.TextSelectHandle</item>
-        <item name="textSuggestionsWindowStyle">@android:style/Widget.DeviceDefault.Light.TextSuggestionsPopupWindow</item>
+        <item name="textSelectHandleWindowStyle">@style/Widget.DeviceDefault.TextSelectHandle</item>
+        <item name="textSuggestionsWindowStyle">@style/Widget.DeviceDefault.Light.TextSuggestionsPopupWindow</item>
 
         <!-- Widget styles -->
-        <item name="absListViewStyle">@android:style/Widget.DeviceDefault.Light.AbsListView</item>
-        <item name="autoCompleteTextViewStyle">@android:style/Widget.DeviceDefault.Light.AutoCompleteTextView</item>
-        <item name="checkboxStyle">@android:style/Widget.DeviceDefault.Light.CompoundButton.CheckBox</item>
-        <item name="checkedTextViewStyle">@android:style/Widget.DeviceDefault.Light.CheckedTextView</item>
-        <item name="dropDownListViewStyle">@android:style/Widget.DeviceDefault.Light.ListView.DropDown</item>
-        <item name="editTextStyle">@android:style/Widget.DeviceDefault.Light.EditText</item>
-        <item name="expandableListViewStyle">@android:style/Widget.DeviceDefault.Light.ExpandableListView</item>
-        <item name="expandableListViewWhiteStyle">@android:style/Widget.DeviceDefault.Light.ExpandableListView.White</item>
-        <item name="galleryStyle">@android:style/Widget.DeviceDefault.Light.Gallery</item>
-        <item name="gestureOverlayViewStyle">@android:style/Widget.DeviceDefault.Light.GestureOverlayView</item>
-        <item name="gridViewStyle">@android:style/Widget.DeviceDefault.Light.GridView</item>
-        <item name="imageButtonStyle">@android:style/Widget.DeviceDefault.Light.ImageButton</item>
-        <item name="imageWellStyle">@android:style/Widget.DeviceDefault.Light.ImageWell</item>
-        <item name="listViewStyle">@android:style/Widget.DeviceDefault.Light.ListView</item>
-        <item name="listViewWhiteStyle">@android:style/Widget.DeviceDefault.Light.ListView.White</item>
-        <item name="popupWindowStyle">@android:style/Widget.DeviceDefault.Light.PopupWindow</item>
-        <item name="progressBarStyle">@android:style/Widget.DeviceDefault.Light.ProgressBar</item>
-        <item name="progressBarStyleHorizontal">@android:style/Widget.DeviceDefault.Light.ProgressBar.Horizontal</item>
-        <item name="progressBarStyleSmall">@android:style/Widget.DeviceDefault.Light.ProgressBar.Small</item>
-        <item name="progressBarStyleSmallTitle">@android:style/Widget.DeviceDefault.Light.ProgressBar.Small.Title</item>
-        <item name="progressBarStyleLarge">@android:style/Widget.DeviceDefault.Light.ProgressBar.Large</item>
-        <item name="progressBarStyleInverse">@android:style/Widget.DeviceDefault.Light.ProgressBar.Inverse</item>
-        <item name="progressBarStyleSmallInverse">@android:style/Widget.DeviceDefault.Light.ProgressBar.Small.Inverse</item>
-        <item name="progressBarStyleLargeInverse">@android:style/Widget.DeviceDefault.Light.ProgressBar.Large.Inverse</item>
-        <item name="seekBarStyle">@android:style/Widget.DeviceDefault.Light.SeekBar</item>
-        <item name="ratingBarStyle">@android:style/Widget.DeviceDefault.Light.RatingBar</item>
-        <item name="ratingBarStyleIndicator">@android:style/Widget.DeviceDefault.Light.RatingBar.Indicator</item>
-        <item name="ratingBarStyleSmall">@android:style/Widget.DeviceDefault.Light.RatingBar.Small</item>
-        <item name="radioButtonStyle">@android:style/Widget.DeviceDefault.Light.CompoundButton.RadioButton</item>
-        <item name="scrollViewStyle">@android:style/Widget.DeviceDefault.Light.ScrollView</item>
-        <item name="horizontalScrollViewStyle">@android:style/Widget.DeviceDefault.Light.HorizontalScrollView</item>
-        <item name="dropDownSpinnerStyle">@android:style/Widget.DeviceDefault.Light.Spinner.DropDown</item>
-        <item name="starStyle">@android:style/Widget.DeviceDefault.Light.CompoundButton.Star</item>
-        <item name="tabWidgetStyle">@android:style/Widget.DeviceDefault.Light.TabWidget</item>
-        <item name="textViewStyle">@android:style/Widget.DeviceDefault.Light.TextView</item>
-        <item name="webTextViewStyle">@android:style/Widget.DeviceDefault.Light.WebTextView</item>
-        <item name="webViewStyle">@android:style/Widget.DeviceDefault.Light.WebView</item>
-        <item name="dropDownItemStyle">@android:style/Widget.DeviceDefault.Light.DropDownItem</item>
-        <item name="spinnerDropDownItemStyle">@android:style/Widget.DeviceDefault.Light.DropDownItem.Spinner</item>
-        <item name="spinnerItemStyle">@android:style/Widget.DeviceDefault.Light.TextView.SpinnerItem</item>
-        <item name="dropDownHintAppearance">@android:style/TextAppearance.DeviceDefault.Widget.DropDownHint</item>
-        <item name="keyboardViewStyle">@android:style/Widget.DeviceDefault.KeyboardView</item>
-        <item name="quickContactBadgeStyleWindowSmall">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowSmall</item>
-        <item name="quickContactBadgeStyleWindowMedium">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowMedium</item>
-        <item name="quickContactBadgeStyleWindowLarge">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowLarge</item>
-        <item name="quickContactBadgeStyleSmallWindowSmall">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowSmall</item>
-        <item name="quickContactBadgeStyleSmallWindowMedium">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowMedium</item>
-        <item name="quickContactBadgeStyleSmallWindowLarge">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowLarge</item>
-        <item name="listPopupWindowStyle">@android:style/Widget.DeviceDefault.Light.ListPopupWindow</item>
-        <item name="popupMenuStyle">@android:style/Widget.DeviceDefault.Light.PopupMenu</item>
-        <item name="stackViewStyle">@android:style/Widget.DeviceDefault.StackView</item>
+        <item name="absListViewStyle">@style/Widget.DeviceDefault.Light.AbsListView</item>
+        <item name="autoCompleteTextViewStyle">@style/Widget.DeviceDefault.Light.AutoCompleteTextView</item>
+        <item name="checkboxStyle">@style/Widget.DeviceDefault.Light.CompoundButton.CheckBox</item>
+        <item name="checkedTextViewStyle">@style/Widget.DeviceDefault.Light.CheckedTextView</item>
+        <item name="dropDownListViewStyle">@style/Widget.DeviceDefault.Light.ListView.DropDown</item>
+        <item name="editTextStyle">@style/Widget.DeviceDefault.Light.EditText</item>
+        <item name="expandableListViewStyle">@style/Widget.DeviceDefault.Light.ExpandableListView</item>
+        <item name="expandableListViewWhiteStyle">@style/Widget.DeviceDefault.Light.ExpandableListView.White</item>
+        <item name="galleryStyle">@style/Widget.DeviceDefault.Light.Gallery</item>
+        <item name="gestureOverlayViewStyle">@style/Widget.DeviceDefault.Light.GestureOverlayView</item>
+        <item name="gridViewStyle">@style/Widget.DeviceDefault.Light.GridView</item>
+        <item name="imageButtonStyle">@style/Widget.DeviceDefault.Light.ImageButton</item>
+        <item name="imageWellStyle">@style/Widget.DeviceDefault.Light.ImageWell</item>
+        <item name="listViewStyle">@style/Widget.DeviceDefault.Light.ListView</item>
+        <item name="listViewWhiteStyle">@style/Widget.DeviceDefault.Light.ListView.White</item>
+        <item name="popupWindowStyle">@style/Widget.DeviceDefault.Light.PopupWindow</item>
+        <item name="progressBarStyle">@style/Widget.DeviceDefault.Light.ProgressBar</item>
+        <item name="progressBarStyleHorizontal">@style/Widget.DeviceDefault.Light.ProgressBar.Horizontal</item>
+        <item name="progressBarStyleSmall">@style/Widget.DeviceDefault.Light.ProgressBar.Small</item>
+        <item name="progressBarStyleSmallTitle">@style/Widget.DeviceDefault.Light.ProgressBar.Small.Title</item>
+        <item name="progressBarStyleLarge">@style/Widget.DeviceDefault.Light.ProgressBar.Large</item>
+        <item name="progressBarStyleInverse">@style/Widget.DeviceDefault.Light.ProgressBar.Inverse</item>
+        <item name="progressBarStyleSmallInverse">@style/Widget.DeviceDefault.Light.ProgressBar.Small.Inverse</item>
+        <item name="progressBarStyleLargeInverse">@style/Widget.DeviceDefault.Light.ProgressBar.Large.Inverse</item>
+        <item name="seekBarStyle">@style/Widget.DeviceDefault.Light.SeekBar</item>
+        <item name="ratingBarStyle">@style/Widget.DeviceDefault.Light.RatingBar</item>
+        <item name="ratingBarStyleIndicator">@style/Widget.DeviceDefault.Light.RatingBar.Indicator</item>
+        <item name="ratingBarStyleSmall">@style/Widget.DeviceDefault.Light.RatingBar.Small</item>
+        <item name="radioButtonStyle">@style/Widget.DeviceDefault.Light.CompoundButton.RadioButton</item>
+        <item name="scrollViewStyle">@style/Widget.DeviceDefault.Light.ScrollView</item>
+        <item name="horizontalScrollViewStyle">@style/Widget.DeviceDefault.Light.HorizontalScrollView</item>
+        <item name="dropDownSpinnerStyle">@style/Widget.DeviceDefault.Light.Spinner.DropDown</item>
+        <item name="starStyle">@style/Widget.DeviceDefault.Light.CompoundButton.Star</item>
+        <item name="tabWidgetStyle">@style/Widget.DeviceDefault.Light.TabWidget</item>
+        <item name="textViewStyle">@style/Widget.DeviceDefault.Light.TextView</item>
+        <item name="webTextViewStyle">@style/Widget.DeviceDefault.Light.WebTextView</item>
+        <item name="webViewStyle">@style/Widget.DeviceDefault.Light.WebView</item>
+        <item name="dropDownItemStyle">@style/Widget.DeviceDefault.Light.DropDownItem</item>
+        <item name="spinnerDropDownItemStyle">@style/Widget.DeviceDefault.Light.DropDownItem.Spinner</item>
+        <item name="spinnerItemStyle">@style/Widget.DeviceDefault.Light.TextView.SpinnerItem</item>
+        <item name="dropDownHintAppearance">@style/TextAppearance.DeviceDefault.Widget.DropDownHint</item>
+        <item name="keyboardViewStyle">@style/Widget.DeviceDefault.KeyboardView</item>
+        <item name="quickContactBadgeStyleWindowSmall">@style/Widget.DeviceDefault.QuickContactBadge.WindowSmall</item>
+        <item name="quickContactBadgeStyleWindowMedium">@style/Widget.DeviceDefault.QuickContactBadge.WindowMedium</item>
+        <item name="quickContactBadgeStyleWindowLarge">@style/Widget.DeviceDefault.QuickContactBadge.WindowLarge</item>
+        <item name="quickContactBadgeStyleSmallWindowSmall">@style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowSmall</item>
+        <item name="quickContactBadgeStyleSmallWindowMedium">@style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowMedium</item>
+        <item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowLarge</item>
+        <item name="listPopupWindowStyle">@style/Widget.DeviceDefault.Light.ListPopupWindow</item>
+        <item name="popupMenuStyle">@style/Widget.DeviceDefault.Light.PopupMenu</item>
+        <item name="stackViewStyle">@style/Widget.DeviceDefault.Light.StackView</item>
 
         <!-- Preference styles -->
-        <item name="preferenceScreenStyle">@android:style/Preference.DeviceDefault.PreferenceScreen</item>
-        <item name="preferenceCategoryStyle">@android:style/Preference.DeviceDefault.Category</item>
-        <item name="preferenceStyle">@android:style/Preference.DeviceDefault</item>
-        <item name="preferenceInformationStyle">@android:style/Preference.DeviceDefault.Information</item>
-        <item name="checkBoxPreferenceStyle">@android:style/Preference.DeviceDefault.CheckBoxPreference</item>
-        <item name="switchPreferenceStyle">@android:style/Preference.DeviceDefault.SwitchPreference</item>
-        <item name="yesNoPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference.YesNoPreference</item>
-        <item name="dialogPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference</item>
-        <item name="editTextPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference.EditTextPreference</item>
-        <item name="ringtonePreferenceStyle">@android:style/Preference.DeviceDefault.RingtonePreference</item>
+        <item name="preferenceScreenStyle">@style/Preference.DeviceDefault.PreferenceScreen</item>
+        <item name="preferenceCategoryStyle">@style/Preference.DeviceDefault.Category</item>
+        <item name="preferenceStyle">@style/Preference.DeviceDefault</item>
+        <item name="preferenceInformationStyle">@style/Preference.DeviceDefault.Information</item>
+        <item name="checkBoxPreferenceStyle">@style/Preference.DeviceDefault.CheckBoxPreference</item>
+        <item name="switchPreferenceStyle">@style/Preference.DeviceDefault.SwitchPreference</item>
+        <item name="yesNoPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference.YesNoPreference</item>
+        <item name="dialogPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference</item>
+        <item name="editTextPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference.EditTextPreference</item>
+        <item name="ringtonePreferenceStyle">@style/Preference.DeviceDefault.RingtonePreference</item>
 
         <!-- Action bar styles -->
-        <item name="actionDropDownStyle">@android:style/Widget.DeviceDefault.Light.Spinner.DropDown.ActionBar</item>
-        <item name="actionButtonStyle">@android:style/Widget.DeviceDefault.Light.ActionButton</item>
-        <item name="actionOverflowButtonStyle">@android:style/Widget.DeviceDefault.Light.ActionButton.Overflow</item>
+        <item name="actionDropDownStyle">@style/Widget.DeviceDefault.Light.Spinner.DropDown.ActionBar</item>
+        <item name="actionButtonStyle">@style/Widget.DeviceDefault.Light.ActionButton</item>
+        <item name="actionOverflowButtonStyle">@style/Widget.DeviceDefault.Light.ActionButton.Overflow</item>
         <item name="actionBarTabStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabView</item>
         <item name="actionBarTabBarStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabBar</item>
         <item name="actionBarTabTextStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabText</item>
         <item name="actionModeStyle">@style/Widget.DeviceDefault.Light.ActionMode</item>
         <item name="actionModeCloseButtonStyle">@style/Widget.DeviceDefault.Light.ActionButton.CloseMode</item>
-        <item name="actionBarStyle">@android:style/Widget.DeviceDefault.Light.ActionBar</item>
-        <item name="actionModePopupWindowStyle">@android:style/Widget.DeviceDefault.Light.PopupWindow.ActionMode</item>
+        <item name="actionBarStyle">@style/Widget.DeviceDefault.Light.ActionBar</item>
+        <item name="actionModePopupWindowStyle">@style/Widget.DeviceDefault.Light.PopupWindow.ActionMode</item>
 
-        <item name="buttonBarStyle">@android:style/DeviceDefault.Light.ButtonBar</item>
-        <item name="segmentedButtonStyle">@android:style/DeviceDefault.Light.SegmentedButton</item>
+        <item name="buttonBarStyle">@style/DeviceDefault.Light.ButtonBar</item>
+        <item name="segmentedButtonStyle">@style/DeviceDefault.Light.SegmentedButton</item>
 
         <item name="searchDialogTheme">@style/Theme.DeviceDefault.Light.SearchBar</item>
 
@@ -373,216 +453,117 @@
         <item name="timePickerStyle">@style/Widget.DeviceDefault.Light.TimePicker</item>
 
         <!-- TimePicker Header time label text appearance -->
-        <item name="timePickerHeaderTimeLabelTextAppearance">@style/TextAppearance.DeviceDefault.Light.TimePicker.TimeLabel</item>
+        <item name="timePickerHeaderTimeLabelTextAppearance">@style/TextAppearance.DeviceDefault.TimePicker.TimeLabel</item>
 
         <!-- TimePicker Header am pm label text appearance -->
-        <item name="timePickerHeaderAmPmLabelTextAppearance">@style/TextAppearance.DeviceDefault.Light.TimePicker.AmPmLabel</item>
+        <item name="timePickerHeaderAmPmLabelTextAppearance">@style/TextAppearance.DeviceDefault.TimePicker.AmPmLabel</item>
 
         <!-- TimePicker dialog theme -->
-        <item name="timePickerDialogTheme">@android:style/Theme.DeviceDefault.Light.Dialog.TimePicker</item>
+        <item name="timePickerDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.TimePicker</item>
 
         <!-- DatePicker style -->
         <item name="datePickerStyle">@style/Widget.DeviceDefault.Light.DatePicker</item>
 
-        <item name="mediaRouteButtonStyle">@android:style/Widget.DeviceDefault.Light.MediaRouteButton</item>
-    </style>
-    <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
-    <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Quantum.Light.NoActionBar" >
-    </style>
-    <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar.
-         This theme sets {@link android.R.attr#windowFullscreen} to true.  -->
-    <style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" parent="Theme.Quantum.Light.NoActionBar.Fullscreen" >
-    </style>
-    <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
-    and extending in to overscan region.  This theme
-    sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
-    to true. -->
-    <style name="Theme.DeviceDefault.Light.NoActionBar.Overscan"
-           parent="Theme.Quantum.Light.NoActionBar.Overscan" >
-    </style>
-    <!-- Variant of {@link #Theme_DeviceDefault_Light} 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.DeviceDefault.Light.NoActionBar.TranslucentDecor"
-           parent="Theme.Quantum.Light.NoActionBar.TranslucentDecor" >
-    </style>
-    <!-- DeviceDefault theme for dialog windows and activities. 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.DeviceDefault.Dialog" parent="Theme.Quantum.Dialog" >
-        <item name="android:windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault</item>
-        <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Dialog</item>
-
-        <item name="android:buttonBarStyle">@android:style/DeviceDefault.ButtonBar.AlertDialog</item>
-        <item name="borderlessButtonStyle">@android:style/Widget.DeviceDefault.Button.Borderless.Small</item>
-
-        <item name="textAppearance">@android:style/TextAppearance.DeviceDefault</item>
-        <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Inverse</item>
-    </style>
-    <!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
-    regular dialog. -->
-    <style name="Theme.DeviceDefault.Dialog.MinWidth" parent="Theme.Quantum.Dialog.MinWidth" >
-
-    </style>
-    <!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
-    <style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="Theme.Quantum.Dialog.NoActionBar" >
-
-    </style>
-    <!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
-    for a regular dialog. -->
-    <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Quantum.Dialog.NoActionBar.MinWidth" >
-
+        <item name="mediaRouteButtonStyle">@style/Widget.DeviceDefault.Light.MediaRouteButton</item>
     </style>
 
-    <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
-    <style name="Theme.DeviceDefault.Dialog.FixedSize">
-        <item name="windowFixedWidthMajor">@android:dimen/dialog_fixed_width_major</item>
-        <item name="windowFixedWidthMinor">@android:dimen/dialog_fixed_width_minor</item>
-        <item name="windowFixedHeightMajor">@android:dimen/dialog_fixed_height_major</item>
-        <item name="windowFixedHeightMinor">@android:dimen/dialog_fixed_height_minor</item>
-    </style>
-
-    <!-- Variant of Theme.DeviceDefault.Dialog.NoActionBar that has a fixed size. -->
-    <style name="Theme.DeviceDefault.Dialog.NoActionBar.FixedSize">
-        <item name="windowFixedWidthMajor">@android:dimen/dialog_fixed_width_major</item>
-        <item name="windowFixedWidthMinor">@android:dimen/dialog_fixed_width_minor</item>
-        <item name="windowFixedHeightMajor">@android:dimen/dialog_fixed_height_major</item>
-        <item name="windowFixedHeightMinor">@android:dimen/dialog_fixed_height_minor</item>
-    </style>
-
-    <!-- DeviceDefault light theme for dialog windows and activities. 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.DeviceDefault.Light.Dialog" parent="Theme.Quantum.Light.Dialog" >
-        <item name="android:windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault.Light</item>
-        <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Dialog</item>
-
-        <item name="android:buttonBarStyle">@android:style/DeviceDefault.Light.ButtonBar.AlertDialog</item>
-        <item name="borderlessButtonStyle">@android:style/Widget.DeviceDefault.Light.Button.Borderless.Small</item>
-
-        <item name="textAppearance">@android:style/TextAppearance.DeviceDefault.Light</item>
-        <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Light.Inverse</item>
-    </style>
-    <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a
-    regular dialog. -->
-    <style name="Theme.DeviceDefault.Light.Dialog.MinWidth" parent="Theme.Quantum.Light.Dialog.MinWidth" >
-
-    </style>
-     <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
-    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar" parent="Theme.Quantum.Light.Dialog.NoActionBar" >
-
-    </style>
-    <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
-    width for a regular dialog. -->
-    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" parent="Theme.Quantum.Light.Dialog.NoActionBar.MinWidth" >
-
-    </style>
-
-    <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
-    <style name="Theme.DeviceDefault.Light.Dialog.FixedSize">
-        <item name="windowFixedWidthMajor">@android:dimen/dialog_fixed_width_major</item>
-        <item name="windowFixedWidthMinor">@android:dimen/dialog_fixed_width_minor</item>
-        <item name="windowFixedHeightMajor">@android:dimen/dialog_fixed_height_major</item>
-        <item name="windowFixedHeightMinor">@android:dimen/dialog_fixed_height_minor</item>
-    </style>
-
-    <!-- Variant of Theme.DeviceDefault.Dialog.NoActionBar that has a fixed size. -->
-    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.FixedSize">
-        <item name="windowFixedWidthMajor">@android:dimen/dialog_fixed_width_major</item>
-        <item name="windowFixedWidthMinor">@android:dimen/dialog_fixed_width_minor</item>
-        <item name="windowFixedHeightMajor">@android:dimen/dialog_fixed_height_major</item>
-        <item name="windowFixedHeightMinor">@android:dimen/dialog_fixed_height_minor</item>
-    </style>
-
-    <!-- DeviceDefault 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.DeviceDefault.DialogWhenLarge" parent="Theme.Quantum.DialogWhenLarge" >
-
-    </style>
-    <!-- DeviceDefault 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.DeviceDefault.DialogWhenLarge.NoActionBar" parent="Theme.Quantum.DialogWhenLarge.NoActionBar" >
-
-    </style>
-    <!-- DeviceDefault light 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.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Quantum.Light.DialogWhenLarge" >
-
-    </style>
-    <!-- DeviceDefault light theme for a window without an action bar that will be displayed either
-    full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
-    xlarge). -->
-    <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="Theme.Quantum.Light.DialogWhenLarge.NoActionBar" >
-
-    </style>
-
-    <!-- DeviceDefault theme for a presentation window on a secondary display. -->
-    <style name="Theme.DeviceDefault.Dialog.Presentation" parent="Theme.Quantum.Dialog.Presentation">
-    </style>
-
-    <!-- DeviceDefault light theme for a presentation window on a secondary display. -->
-    <style name="Theme.DeviceDefault.Light.Dialog.Presentation" parent="Theme.Quantum.Light.Dialog.Presentation">
-    </style>
-
-    <!-- DeviceDefault 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.DeviceDefault.Panel" parent="Theme.Quantum.Panel" >
-
-    </style>
-    <!-- DeviceDefault light 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.DeviceDefault.Light.Panel" parent="Theme.Quantum.Light.Panel" >
-
-    </style>
-    <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
-    behind them. -->
-    <style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Quantum.Wallpaper" >
-
-    </style>
-    <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
-    behind them and without an action bar. -->
-    <style name="Theme.DeviceDefault.Wallpaper.NoTitleBar" parent="Theme.Quantum.Wallpaper.NoTitleBar" >
-
-    </style>
-    <!-- DeviceDefault style for input methods, which is used by the
-         {@link android.inputmethodservice.InputMethodService} class.-->
-    <style name="Theme.DeviceDefault.InputMethod" parent="Theme.Quantum.InputMethod" >
-
-    </style>
     <!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an
     inverse color profile. -->
     <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Quantum.Light.DarkActionBar" >
-        <item name="android:actionBarStyle">@android:style/Widget.DeviceDefault.Light.ActionBar.Solid.Inverse</item>
-
-        <item name="actionDropDownStyle">@android:style/Widget.DeviceDefault.Spinner.DropDown.ActionBar</item>
-        <item name="actionButtonStyle">@android:style/Widget.DeviceDefault.ActionButton</item>
-        <item name="actionOverflowButtonStyle">@android:style/Widget.DeviceDefault.ActionButton.Overflow</item>
+        <item name="actionBarStyle">@style/Widget.DeviceDefault.Light.ActionBar.Solid.Inverse</item>
+        <item name="actionDropDownStyle">@style/Widget.DeviceDefault.Spinner.DropDown.ActionBar</item>
+        <item name="actionButtonStyle">@style/Widget.DeviceDefault.ActionButton</item>
+        <item name="actionOverflowButtonStyle">@style/Widget.DeviceDefault.ActionButton.Overflow</item>
         <item name="actionBarTabStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabView.Inverse</item>
         <item name="actionBarTabBarStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabBar.Inverse</item>
         <item name="actionBarTabTextStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabText.Inverse</item>
         <item name="actionModeStyle">@style/Widget.DeviceDefault.Light.ActionMode.Inverse</item>
         <item name="actionModeCloseButtonStyle">@style/Widget.DeviceDefault.ActionButton.CloseMode</item>
-        <item name="actionModePopupWindowStyle">@android:style/Widget.DeviceDefault.PopupWindow.ActionMode</item>
-
+        <item name="actionModePopupWindowStyle">@style/Widget.DeviceDefault.PopupWindow.ActionMode</item>
     </style>
 
-    <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Quantum.Dialog.Alert">
-        <item name="windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault</item>
+    <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
+    <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Quantum.Light.NoActionBar"  />
+
+    <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar.
+         This theme sets {@link android.R.attr#windowFullscreen} to true.  -->
+    <style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" parent="Theme.Quantum.Light.NoActionBar.Fullscreen"  />
+
+    <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
+    and extending in to overscan region.  This theme
+    sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
+    to true. -->
+    <style name="Theme.DeviceDefault.Light.NoActionBar.Overscan" parent="Theme.Quantum.Light.NoActionBar.Overscan" />
+
+    <!-- Variant of {@link #Theme_DeviceDefault_Light} 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.DeviceDefault.Light.NoActionBar.TranslucentDecor" parent="Theme.Quantum.Light.NoActionBar.TranslucentDecor" />
+
+    <!-- DeviceDefault light theme for dialog windows and activities. 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.DeviceDefault.Light.Dialog" parent="Theme.Quantum.Light.Dialog" >
+        <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item>
+        <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
+
+        <item name="buttonBarStyle">@style/DeviceDefault.Light.ButtonBar.AlertDialog</item>
+        <item name="borderlessButtonStyle">@style/Widget.DeviceDefault.Light.Button.Borderless.Small</item>
+
+        <item name="textAppearance">@style/TextAppearance.DeviceDefault</item>
+        <item name="textAppearanceInverse">@style/TextAppearance.DeviceDefault.Inverse</item>
     </style>
+
+    <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a
+    regular dialog. -->
+    <style name="Theme.DeviceDefault.Light.Dialog.MinWidth" parent="Theme.Quantum.Light.Dialog.MinWidth" />
+
+     <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
+    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar" parent="Theme.Quantum.Light.Dialog.NoActionBar" />
+
+    <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
+    width for a regular dialog. -->
+    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" parent="Theme.Quantum.Light.Dialog.NoActionBar.MinWidth" />
+
+    <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
+    <style name="Theme.DeviceDefault.Light.Dialog.FixedSize">
+        <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
+        <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
+        <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
+        <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+    </style>
+
+    <!-- Variant of Theme.DeviceDefault.Dialog.NoActionBar that has a fixed size. -->
+    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.FixedSize">
+        <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
+        <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
+        <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
+        <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+    </style>
+
+    <!-- DeviceDefault light 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.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Quantum.Light.DialogWhenLarge"  />
+
+    <!-- DeviceDefault light theme for a window without an action bar that will be displayed either
+    full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
+    xlarge). -->
+    <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="Theme.Quantum.Light.DialogWhenLarge.NoActionBar"  />
+
+    <!-- DeviceDefault light theme for a presentation window on a secondary display. -->
+    <style name="Theme.DeviceDefault.Light.Dialog.Presentation" parent="Theme.Quantum.Light.Dialog.Presentation" />
+
+    <style name="Theme.DeviceDefault.Light.Dialog.TimePicker" parent="Theme.Quantum.Light.Dialog.TimePicker"/>
+
+    <!-- DeviceDefault light 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.DeviceDefault.Light.Panel" parent="Theme.Quantum.Light.Panel"  />
+
     <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Quantum.Light.Dialog.Alert">
-        <item name="windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault.Light</item>
-    </style>
-    <style name="Theme.DeviceDefault.SearchBar" parent="Theme.Quantum.SearchBar">
-
-    </style>
-    <style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Quantum.Light.SearchBar">
-
+        <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item>
     </style>
 
-    <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Quantum.Dialog.NoFrame">
-    </style>
+    <style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Quantum.Light.SearchBar" />
 
 </resources>
diff --git a/core/res/res/values/themes_leanback.xml b/core/res/res/values/themes_leanback.xml
new file mode 100644
index 0000000..eba8dec
--- /dev/null
+++ b/core/res/res/values/themes_leanback.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <style name="Theme.Leanback.Dialog.Alert" parent="Theme.Holo.Dialog.BaseAlert">
+      <item name="windowTitleStyle">@style/DialogWindowTitle.Leanback</item>
+      <item name="alertDialogStyle">@style/AlertDialog.Leanback</item>
+      <item name="buttonBarStyle">@style/Leanback.ButtonBar</item>
+      <item name="listDividerAlertDialog">@null</item>
+    </style>
+
+    <style name="Theme.Leanback.Light.Dialog.Alert" parent="Theme.Holo.Light.Dialog.BaseAlert">
+      <item name="windowTitleStyle">@style/DialogWindowTitle.Leanback</item>
+      <item name="alertDialogStyle">@style/AlertDialog.Leanback.Light</item>
+      <item name="buttonBarStyle">@style/Leanback.ButtonBar</item>
+      <item name="listDividerAlertDialog">@null</item>
+    </style>
+
+    <style name="Theme.Leanback.Light.Dialog" parent="Theme.Holo.Light.Dialog">
+        <item name="windowTitleStyle">@style/DialogWindowTitle.Leanback</item>
+    </style>
+
+    <style name="Theme.Leanback.Dialog" parent="Theme.Holo.Dialog">
+        <item name="windowTitleStyle">@style/DialogWindowTitle.Leanback</item>
+    </style>
+
+    <style name="Theme.Leanback.Dialog.AppError" parent="Theme.Leanback.Dialog">
+        <item name="windowFrame">@null</item>
+        <item name="windowBackground">@color/transparent</item>
+        <item name="windowIsFloating">true</item>
+        <item name="windowContentOverlay">@null</item>
+        <item name="windowCloseOnTouchOutside">false</item>
+        <item name="alertDialogStyle">@style/AlertDialog.Leanback</item>
+    </style>
+</resources>
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
index f51b8df..9647947 100644
--- a/core/res/res/values/themes_micro.xml
+++ b/core/res/res/values/themes_micro.xml
@@ -15,20 +15,56 @@
 -->
 <resources>
     <style name="Theme.Micro" parent="Theme.Holo.NoActionBar">
-        <item name="textViewStyle">@android:style/Widget.Micro.TextView</item>
-        <item name="numberPickerStyle">@android:style/Widget.Micro.NumberPicker</item>
-        <item name="windowAnimationStyle">@android:style/Animation.SwipeDismiss</item>
+        <item name="alertDialogTheme">@style/Theme.Micro.Dialog.Alert</item>
+        <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
+        <item name="dialogTheme">@style/Theme.Micro.Dialog</item>
+        <item name="textViewStyle">@style/Widget.Micro.TextView</item>
+
+        <item name="numberPickerStyle">@style/Widget.Micro.NumberPicker</item>
+        <item name="windowAnimationStyle">@style/Animation.SwipeDismiss</item>
         <item name="windowIsFloating">false</item>
         <item name="windowIsTranslucent">true</item>
         <item name="windowSwipeToDismiss">true</item>
 	</style>
 
     <style name="Theme.Micro.Light" parent="Theme.Holo.Light.NoActionBar">
-        <item name="textViewStyle">@android:style/Widget.Micro.TextView</item>
-        <item name="numberPickerStyle">@android:style/Widget.Micro.NumberPicker</item>
-        <item name="windowAnimationStyle">@android:style/Animation.SwipeDismiss</item>
+        <item name="alertDialogTheme">@style/Theme.Micro.Dialog.Alert</item>
+        <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
+        <item name="dialogTheme">@style/Theme.Micro.Dialog</item>
+        <item name="textViewStyle">@style/Widget.Micro.TextView</item>
+        <item name="numberPickerStyle">@style/Widget.Micro.NumberPicker</item>
+        <item name="windowAnimationStyle">@style/Animation.SwipeDismiss</item>
         <item name="windowIsFloating">false</item>
         <item name="windowIsTranslucent">true</item>
         <item name="windowSwipeToDismiss">true</item>
     </style>
+
+    <style name="Theme.Micro.Dialog" parent="Theme.Holo.Light.Dialog">
+        <item name="windowTitleStyle">@android:style/DialogWindowTitle.Micro</item>
+        <item name="windowIsFloating">false</item>
+        <item name="windowFullscreen">true</item>
+        <item name="textAppearance">@style/TextAppearance.Micro</item>
+        <item name="textAppearanceInverse">@style/TextAppearance.Micro</item>
+    </style>
+
+    <style name="Theme.Micro.Dialog.Alert">
+        <item name="windowTitleStyle">@style/DialogWindowTitle.Micro</item>
+        <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
+        <item name="windowIsFloating">false</item>
+        <item name="windowBackground">@android:color/transparent</item>
+        <item name="windowOverscan">true</item>
+        <item name="windowContentOverlay">@null</item>
+        <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
+        <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
+    </style>
+
+    <style name="Theme.Micro.Dialog.AppError" parent="Theme.Micro.Dialog">
+        <item name="windowBackground">@null</item>
+        <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
+        <item name="windowOverscan">true</item>
+        <item name="windowCloseOnTouchOutside">false</item>
+        <item name="textSize">20sp</item>
+        <item name="fontFamily">sans-serif-condensed-light</item>
+        <item name="textColor">@color/micro_text_light</item>
+    </style>
 </resources>
diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml
index 9f76eae..6f93c829 100644
--- a/core/res/res/values/themes_quantum.xml
+++ b/core/res/res/values/themes_quantum.xml
@@ -122,7 +122,7 @@
         <item name="listDivider">@drawable/list_divider_quantum</item>
         <item name="listSeparatorTextViewStyle">@style/Widget.Quantum.TextView.ListSeparator</item>
 
-        <item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum</item>
+        <item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum_anim</item>
         <item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum_anim</item>
 
         <item name="listChoiceBackgroundIndicator">@drawable/list_selector_quantum</item>
@@ -291,6 +291,7 @@
         <item name="actionDropDownStyle">@style/Widget.Quantum.Spinner.DropDown.ActionBar</item>
         <item name="actionButtonStyle">@style/Widget.Quantum.ActionButton</item>
         <item name="actionOverflowButtonStyle">@style/Widget.Quantum.ActionButton.Overflow</item>
+        <item name="actionOverflowMenuStyle">@android:style/Widget.Quantum.PopupMenu.Overflow</item>
         <item name="actionModeBackground">?attr/colorPrimaryDark</item>
         <item name="actionModeSplitBackground">?attr/colorPrimaryDark</item>
         <item name="actionModeCloseDrawable">@drawable/ic_cab_done_quantum</item>
@@ -376,9 +377,6 @@
         <item name="colorControlActivated">?attr/colorPrimary</item>
         <item name="colorButtonNormal">@color/quantum_grey_700</item>
         <item name="colorButtonPressed">@color/quantum_grey_500</item>
-        <!-- TODO: Remove these attrs and move into button style. -->
-        <item name="colorButtonNormalColored">?attr/colorPrimary</item>
-        <item name="colorButtonPressedColored">?attr/colorPrimaryLight</item>
     </style>
 
     <!-- Quantum Paper theme (light version). -->
@@ -391,8 +389,8 @@
         <item name="backgroundDimAmount">0.6</item>
 
         <!-- Text styles -->
-        <item name="textAppearance">@style/TextAppearance.Quantum.Light</item>
-        <item name="textAppearanceInverse">@style/TextAppearance.Quantum.Light.Inverse</item>
+        <item name="textAppearance">@style/TextAppearance.Quantum</item>
+        <item name="textAppearanceInverse">@style/TextAppearance.Quantum.Inverse</item>
 
         <item name="textColorPrimary">@color/primary_text_quantum_light</item>
         <item name="textColorPrimaryInverse">@color/primary_text_quantum_dark</item>
@@ -411,16 +409,16 @@
         <item name="textColorSearchUrl">@color/search_url_text_quantum_light</item>
         <item name="textColorAlertDialogListItem">@color/primary_text_quantum_light</item>
 
-        <item name="textAppearanceLarge">@style/TextAppearance.Quantum.Light.Large</item>
-        <item name="textAppearanceLargeInverse">@style/TextAppearance.Quantum.Light.Large.Inverse</item>
-        <item name="textAppearanceMedium">@style/TextAppearance.Quantum.Light.Medium</item>
-        <item name="textAppearanceMediumInverse">@style/TextAppearance.Quantum.Light.Medium.Inverse</item>
-        <item name="textAppearanceSmall">@style/TextAppearance.Quantum.Light.Small</item>
-        <item name="textAppearanceSmallInverse">@style/TextAppearance.Quantum.Light.Small.Inverse</item>
-        <item name="textAppearanceSearchResultTitle">@style/TextAppearance.Quantum.Light.SearchResult.Title</item>
-        <item name="textAppearanceSearchResultSubtitle">@style/TextAppearance.Quantum.Light.SearchResult.Subtitle</item>
+        <item name="textAppearanceLarge">@style/TextAppearance.Quantum.Large</item>
+        <item name="textAppearanceLargeInverse">@style/TextAppearance.Quantum.Large.Inverse</item>
+        <item name="textAppearanceMedium">@style/TextAppearance.Quantum.Medium</item>
+        <item name="textAppearanceMediumInverse">@style/TextAppearance.Quantum.Medium.Inverse</item>
+        <item name="textAppearanceSmall">@style/TextAppearance.Quantum.Small</item>
+        <item name="textAppearanceSmallInverse">@style/TextAppearance.Quantum.Small.Inverse</item>
+        <item name="textAppearanceSearchResultTitle">@style/TextAppearance.Quantum.SearchResult.Title</item>
+        <item name="textAppearanceSearchResultSubtitle">@style/TextAppearance.Quantum.SearchResult.Subtitle</item>
 
-        <item name="textAppearanceButton">@style/TextAppearance.Quantum.Light.Widget.Button</item>
+        <item name="textAppearanceButton">@style/TextAppearance.Quantum.Widget.Button</item>
 
         <item name="editTextColor">?attr/textColorPrimary</item>
         <item name="editTextBackground">@drawable/edit_text_quantum</item>
@@ -430,8 +428,8 @@
         <item name="textCheckMark">@drawable/indicator_check_mark_light</item>
         <item name="textCheckMarkInverse">@drawable/indicator_check_mark_dark</item>
 
-        <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Quantum.Light.Widget.PopupMenu.Large</item>
-        <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Quantum.Light.Widget.PopupMenu.Small</item>
+        <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Quantum.Widget.PopupMenu.Large</item>
+        <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Quantum.Widget.PopupMenu.Small</item>
 
         <!-- Button styles -->
         <item name="buttonStyle">@style/Widget.Quantum.Light.Button</item>
@@ -465,7 +463,7 @@
         <item name="listDivider">@drawable/list_divider_quantum</item>
         <item name="listSeparatorTextViewStyle">@style/Widget.Quantum.Light.TextView.ListSeparator</item>
 
-        <item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum</item>
+        <item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum_anim</item>
         <item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum_anim</item>
 
         <item name="listChoiceBackgroundIndicator">@drawable/list_selector_quantum</item>
@@ -606,7 +604,7 @@
         <item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.Quantum.QuickContactBadgeSmall.WindowLarge</item>
         <item name="listPopupWindowStyle">@style/Widget.Quantum.Light.ListPopupWindow</item>
         <item name="popupMenuStyle">@style/Widget.Quantum.Light.PopupMenu</item>
-        <item name="stackViewStyle">@style/Widget.Quantum.StackView</item>
+        <item name="stackViewStyle">@style/Widget.Quantum.Light.StackView</item>
         <item name="activityChooserViewStyle">@style/Widget.Quantum.Light.ActivityChooserView</item>
         <item name="fragmentBreadCrumbsStyle">@style/Widget.Quantum.Light.FragmentBreadCrumbs</item>
 
@@ -636,6 +634,7 @@
         <item name="actionDropDownStyle">@style/Widget.Quantum.Light.Spinner.DropDown.ActionBar</item>
         <item name="actionButtonStyle">@style/Widget.Quantum.Light.ActionButton</item>
         <item name="actionOverflowButtonStyle">@style/Widget.Quantum.Light.ActionButton.Overflow</item>
+        <item name="actionOverflowMenuStyle">@android:style/Widget.Quantum.Light.PopupMenu.Overflow</item>
         <item name="actionModeBackground">@drawable/cab_background_top_holo_light</item>
         <item name="actionModeSplitBackground">@drawable/cab_background_bottom_holo_light</item>
         <item name="actionModeCloseDrawable">@drawable/ic_cab_done_quantum</item>
@@ -690,10 +689,10 @@
         <item name="timePickerHeaderBackgroundColor">?attr/colorBackground</item>
 
         <!-- TimePicker Header time label text appearance -->
-        <item name="timePickerHeaderTimeLabelTextAppearance">@style/TextAppearance.Quantum.Light.TimePicker.TimeLabel</item>
+        <item name="timePickerHeaderTimeLabelTextAppearance">@style/TextAppearance.Quantum.TimePicker.TimeLabel</item>
 
         <!-- TimePicker Header am pm label text appearance -->
-        <item name="timePickerHeaderAmPmLabelTextAppearance">@style/TextAppearance.Quantum.Light.TimePicker.AmPmLabel</item>
+        <item name="timePickerHeaderAmPmLabelTextAppearance">@style/TextAppearance.Quantum.TimePicker.AmPmLabel</item>
 
         <!-- TimePicker dialog theme -->
         <item name="timePickerDialogTheme">@style/Theme.Quantum.Light.Dialog.TimePicker</item>
@@ -717,9 +716,6 @@
         <item name="colorControlActivated">?attr/colorPrimary</item>
         <item name="colorButtonNormal">@color/quantum_grey_100</item>
         <item name="colorButtonPressed">@color/quantum_grey_500</item>
-        <!-- TODO: Remove these attrs and move into button style. -->
-        <item name="colorButtonNormalColored">?attr/colorPrimary</item>
-        <item name="colorButtonPressedColored">?attr/colorPrimaryDark</item>
     </style>
 
     <style name="ThemeOverlay" />
@@ -856,6 +852,14 @@
         <item name="imeExtractExitAnimation">@anim/input_method_extract_exit</item>
     </style>
 
+    <!-- Default theme for quantum style voice interaction, which is used by the
+         {@link android.service.voice.VoiceInteractionSession} class.
+         this inherits from Theme.Panel, but sets up appropriate animations
+         and a few custom attributes. -->
+    <style name="Theme.Quantum.VoiceInteractionSession" parent="Theme.Quantum.Light.Panel">
+        <item name="android:windowAnimationStyle">@android:style/Animation.VoiceInteractionSession</item>
+    </style>
+
     <!-- Theme for the search input bar. -->
 
     <style name="Theme.Quantum.SearchBar" parent="Theme.Quantum.Panel">
@@ -1031,8 +1035,8 @@
         <item name="buttonBarStyle">@style/Widget.Quantum.Light.ButtonBar.AlertDialog</item>
         <item name="borderlessButtonStyle">@style/Widget.Quantum.Light.Button.Borderless.Small</item>
 
-        <item name="textAppearance">@style/TextAppearance.Quantum.Light</item>
-        <item name="textAppearanceInverse">@style/TextAppearance.Quantum.Light.Inverse</item>
+        <item name="textAppearance">@style/TextAppearance.Quantum</item>
+        <item name="textAppearanceInverse">@style/TextAppearance.Quantum.Inverse</item>
 
         <item name="listPreferredItemPaddingLeft">16dip</item>
         <item name="listPreferredItemPaddingRight">16dip</item>
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
index 0cd19f2..67203b2 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
@@ -64,6 +64,8 @@
             unpairAll();
         } else if ("getName".equals(command)) {
             getName();
+        } else if ("getAddress".equals(command)) {
+            getAddress();
         } else {
             finish(null);
         }
@@ -90,6 +92,12 @@
         finish(mSuccessResult);
     }
 
+    public void getAddress() {
+        String name = getBluetoothAdapter().getAddress();
+        mSuccessResult.putString("address", name);
+        finish(mSuccessResult);
+    }
+
     public void finish(Bundle result) {
         if (result == null) {
             result = new Bundle();
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java
new file mode 100644
index 0000000..0f3ea0e
--- /dev/null
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.os.ParcelUuid;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit test cases for {@link BluetoothUuid}.
+ * <p>
+ * To run this test, use adb shell am instrument -e class 'android.bluetooth.BluetoothUuidTest' -w
+ * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner'
+ */
+public class BluetoothUuidTest extends TestCase {
+
+    @SmallTest
+    public void testUuidParser() {
+        byte[] uuid16 = new byte[] {
+                0x0B, 0x11 };
+        assertEquals(ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"),
+                BluetoothUuid.parseUuidFrom(uuid16));
+
+        byte[] uuid32 = new byte[] {
+                0x0B, 0x11, 0x33, (byte) 0xFE };
+        assertEquals(ParcelUuid.fromString("FE33110B-0000-1000-8000-00805F9B34FB"),
+                BluetoothUuid.parseUuidFrom(uuid32));
+
+        byte[] uuid128 = new byte[] {
+                0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+                0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, (byte) 0xFF };
+        assertEquals(ParcelUuid.fromString("FF0F0E0D-0C0B-0A09-0807-0060504030201"),
+                BluetoothUuid.parseUuidFrom(uuid128));
+    }
+}
diff --git a/core/tests/coretests/res/anim/reset_state_anim.xml b/core/tests/coretests/res/anim/reset_state_anim.xml
new file mode 100644
index 0000000..918d0a3
--- /dev/null
+++ b/core/tests/coretests/res/anim/reset_state_anim.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+    <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+    <objectAnimator android:propertyName="z" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+</set>
\ No newline at end of file
diff --git a/core/tests/coretests/res/anim/test_state_anim.xml b/core/tests/coretests/res/anim/test_state_anim.xml
new file mode 100644
index 0000000..9e08f68
--- /dev/null
+++ b/core/tests/coretests/res/anim/test_state_anim.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true">
+        <set>
+            <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="10" android:valueType="floatType"/>
+            <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="20" android:valueType="floatType"/>
+            <objectAnimator android:propertyName="z" android:duration="100" android:valueTo="20" android:valueType="floatType"/>
+        </set>
+    </item>
+    <item android:state_enabled="true" android:state_pressed="false">
+        <set>
+            <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+            <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+            <objectAnimator android:propertyName="z" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+        </set>
+    </item>
+    <!-- base state-->
+    <item android:animation="@anim/reset_state_anim"/>
+</selector>
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/animation/StateListAnimatorTest.java b/core/tests/coretests/src/android/animation/StateListAnimatorTest.java
new file mode 100644
index 0000000..38df78d
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/StateListAnimatorTest.java
@@ -0,0 +1,102 @@
+/*
+* Copyright (C) 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+package android.animation;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.util.StateSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.frameworks.coretests.R;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+
+public class StateListAnimatorTest extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
+
+    public StateListAnimatorTest() {
+        super(BasicAnimatorActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public void testInflateFromAnimator() throws Exception {
+        StateListAnimator stateListAnimator = AnimatorInflater
+                .loadStateListAnimator(getActivity(), R.anim.test_state_anim);
+        assertNotNull("A state list animator should be returned", stateListAnimator);
+        assertEquals("State list animator should have three items", 3,
+                stateListAnimator.getTuples().size());
+    }
+
+    @UiThreadTest
+    public void testAttachDetach() throws Exception {
+        View view = new View(getActivity());
+        final AtomicInteger setStateCount = new AtomicInteger(0);
+        StateListAnimator stateListAnimator = new StateListAnimator() {
+            @Override
+            public void setState(int[] state) {
+                setStateCount.incrementAndGet();
+                super.setState(state);
+            }
+        };
+        view.setStateListAnimator(stateListAnimator);
+        assertNotNull("State list animator should have a reference to view even if it is detached",
+                stateListAnimator.getTarget());
+        ViewGroup viewGroup = (ViewGroup) getActivity().findViewById(android.R.id.content);
+        int preSetStateCount = setStateCount.get();
+        viewGroup.addView(view);
+        assertTrue("When view is attached, state list drawable's setState should be called",
+                preSetStateCount < setStateCount.get());
+
+        StateListAnimator stateListAnimator2 = new StateListAnimator();
+        view.setStateListAnimator(stateListAnimator2);
+        assertNull("When a new state list animator is assigned, previous one should be detached",
+                stateListAnimator.getTarget());
+        assertNull("Any running animator should be removed on detach",
+                stateListAnimator.getRunningAnimator());
+        assertEquals("The new state list animator should be attached to the view",
+                view, stateListAnimator2.getTarget());
+        viewGroup.removeView(view);
+        assertNotNull("When view is detached from window, state list animator should still keep the"
+                        + " reference",
+                stateListAnimator2.getTarget());
+    }
+
+    public void testStateListLoading() throws InterruptedException {
+        StateListAnimator stateListAnimator = AnimatorInflater
+                .loadStateListAnimator(getActivity(), R.anim.test_state_anim);
+        assertNotNull("A state list animator should be returned", stateListAnimator);
+        assertEquals("Steate list animator should have two items", 3,
+                stateListAnimator.getTuples().size());
+        StateListAnimator.Tuple tuple1 = stateListAnimator.getTuples().get(0);
+        assertEquals("first tuple should have one state", 1, tuple1.getSpecs().length);
+        assertEquals("first spec in tuple 1 should be pressed",
+                com.android.internal.R.attr.state_pressed, tuple1.getSpecs()[0]);
+
+        StateListAnimator.Tuple tuple2 = stateListAnimator.getTuples().get(1);
+        assertEquals("Second tuple should have two specs", 2, tuple2.getSpecs().length);
+        assertTrue("Tuple two should match the expected state",
+                StateSet.stateSetMatches(tuple2.getSpecs(),
+                new int[]{-com.android.internal.R.attr.state_pressed,
+                com.android.internal.R.attr.state_enabled}));
+    }
+}
diff --git a/core/tests/coretests/src/android/net/LinkSocketTest.java b/core/tests/coretests/src/android/net/LinkSocketTest.java
deleted file mode 100644
index af77d63..0000000
--- a/core/tests/coretests/src/android/net/LinkSocketTest.java
+++ /dev/null
@@ -1,44 +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;
-
-import android.net.LinkSocket;
-import android.test.suitebuilder.annotation.SmallTest;
-import junit.framework.TestCase;
-
-/**
- * Test LinkSocket
- */
-public class LinkSocketTest extends TestCase {
-
-    @SmallTest
-    public void testBasic() throws Exception {
-        LinkSocket ls;
-
-        ls = new LinkSocket();
-        ls.close();
-    }
-
-    @SmallTest
-    public void testLinkCapabilities() throws Exception {
-        LinkCapabilities lc;
-
-        lc = new LinkCapabilities();
-        assertEquals(0, lc.size());
-        assertEquals(true, lc.isEmpty());
-    }
-}
diff --git a/core/tests/coretests/src/android/net/RssiCurveTest.java b/core/tests/coretests/src/android/net/RssiCurveTest.java
new file mode 100644
index 0000000..d4438df
--- /dev/null
+++ b/core/tests/coretests/src/android/net/RssiCurveTest.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 android.net;
+
+import junit.framework.TestCase;
+
+public class RssiCurveTest extends TestCase {
+    public void testLookupScore_constantCurve() {
+        RssiCurve curve = new RssiCurve(-100, 200, new byte[] { 10 });
+        assertEquals(10, curve.lookupScore(-200));
+        assertEquals(10, curve.lookupScore(-100));
+        assertEquals(10, curve.lookupScore(0));
+        assertEquals(10, curve.lookupScore(100));
+        assertEquals(10, curve.lookupScore(200));
+    }
+
+    public void testLookupScore_changingCurve() {
+        RssiCurve curve = new RssiCurve(-100, 100, new byte[] { -10, 10 });
+        assertEquals(-10, curve.lookupScore(-200));
+        assertEquals(-10, curve.lookupScore(-100));
+        assertEquals(-10, curve.lookupScore(-50));
+        assertEquals(10, curve.lookupScore(0));
+        assertEquals(10, curve.lookupScore(50));
+        assertEquals(10, curve.lookupScore(100));
+        assertEquals(10, curve.lookupScore(200));
+    }
+}
diff --git a/core/tests/inputmethodtests/run_core_inputmethod_test.sh b/core/tests/inputmethodtests/run_core_inputmethod_test.sh
index b0b119b..e0f4f6d 100755
--- a/core/tests/inputmethodtests/run_core_inputmethod_test.sh
+++ b/core/tests/inputmethodtests/run_core_inputmethod_test.sh
@@ -21,4 +21,4 @@
   $COMMAND
 fi
 
-adb shell am instrument -w -e class android.os.InputMethodTest,android.os.InputMethodSubtypeArrayTest com.android.frameworks.coretests.inputmethod/android.test.InstrumentationTestRunner
+adb shell am instrument -w -e class android.os.InputMethodTest,android.os.InputMethodSubtypeArrayTest,android.os.InputMethodSubtypeSwitchingControllerTest,android.os.CursorAnchorInfoTest,android.os.SparseRectFArrayTest com.android.frameworks.coretests.inputmethod/android.test.InstrumentationTestRunner
diff --git a/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java b/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java
new file mode 100644
index 0000000..e7b1b39
--- /dev/null
+++ b/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.inputmethod.CursorAnchorInfo;
+import android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder;
+
+public class CursorAnchorInfoTest extends InstrumentationTestCase {
+    // null represents a character that is invisible, for example because it's overlapped by some
+    // other UI elements.
+    private static final RectF[] MANY_RECTS = new RectF[] {
+            null,
+            new RectF(102.0f, 202.0f, 302.0f, 402.0f),
+            new RectF(103.0f, 203.0f, 303.0f, 403.0f),
+            new RectF(104.0f, 204.0f, 304.0f, 404.0f),
+            new RectF(105.0f, 205.0f, 305.0f, 405.0f),
+            new RectF(106.0f, 206.0f, 306.0f, 406.0f),
+            null,
+            new RectF(108.0f, 208.0f, 308.0f, 408.0f),
+            new RectF(109.0f, 209.0f, 309.0f, 409.0f),
+            new RectF(110.0f, 210.0f, 310.0f, 410.0f),
+            new RectF(111.0f, 211.0f, 311.0f, 411.0f),
+            new RectF(112.0f, 212.0f, 312.0f, 412.0f),
+            new RectF(113.0f, 213.0f, 313.0f, 413.0f),
+            new RectF(114.0f, 214.0f, 314.0f, 414.0f),
+            new RectF(115.0f, 215.0f, 315.0f, 415.0f),
+            new RectF(116.0f, 216.0f, 316.0f, 416.0f),
+            new RectF(117.0f, 217.0f, 317.0f, 417.0f),
+            null,
+            null,
+    };
+
+    @SmallTest
+    public void testBuilder() throws Exception {
+        final int SELECTION_START = 30;
+        final int SELECTION_END = 40;
+        final int COMPOSING_TEXT_START = 32;
+        final String COMPOSING_TEXT = "test";
+        final float INSERTION_MARKER_HORIZONTAL = 10.5f;
+        final float INSERTION_MARKER_TOP = 100.1f;
+        final float INSERTION_MARKER_BASELINE = 110.4f;
+        final float INSERTION_MARKER_BOTOM = 111.0f;
+        final int CHAR_INDEX = 32;
+        final char CHAR_VALUE = 'X';
+        final char DEFAULT_CHAR_VALUE = '!';
+        Matrix TRANSFORM_MATRIX = new Matrix(Matrix.IDENTITY_MATRIX);
+        TRANSFORM_MATRIX.setScale(10.0f, 20.0f);
+
+        final CursorAnchorInfoBuilder builder = new CursorAnchorInfoBuilder();
+        builder.setSelectionRange(SELECTION_START, SELECTION_END)
+                .setComposingText(COMPOSING_TEXT_START, COMPOSING_TEXT)
+                .setInsertionMarkerLocation(INSERTION_MARKER_HORIZONTAL, INSERTION_MARKER_TOP,
+                        INSERTION_MARKER_BASELINE, INSERTION_MARKER_BOTOM)
+                .setMatrix(TRANSFORM_MATRIX);
+        for (int i = 0; i < MANY_RECTS.length; i++) {
+            final RectF rect = MANY_RECTS[i];
+            if (rect != null) {
+                builder.addCharacterRect(i, rect.left, rect.top, rect.right, rect.bottom);
+            }
+        }
+
+        final CursorAnchorInfo info = builder.build();
+        assertEquals(SELECTION_START, info.getSelectionStart());
+        assertEquals(SELECTION_END, info.getSelectionEnd());
+        assertEquals(COMPOSING_TEXT_START, info.getComposingTextStart());
+        assertEquals(COMPOSING_TEXT, info.getComposingText());
+        assertEquals(INSERTION_MARKER_HORIZONTAL, info.getInsertionMarkerHorizontal());
+        assertEquals(INSERTION_MARKER_TOP, info.getInsertionMarkerTop());
+        assertEquals(INSERTION_MARKER_BASELINE, info.getInsertionMarkerBaseline());
+        assertEquals(INSERTION_MARKER_BOTOM, info.getInsertionMarkerBottom());
+        assertEquals(TRANSFORM_MATRIX, info.getMatrix());
+        for (int i = 0; i < MANY_RECTS.length; i++) {
+            final RectF rect = MANY_RECTS[i];
+            assertEquals(rect, info.getCharacterRect(i));
+        }
+
+        // Make sure that the builder can reproduce the same object.
+        final CursorAnchorInfo info2 = builder.build();
+        assertEquals(SELECTION_START, info2.getSelectionStart());
+        assertEquals(SELECTION_END, info2.getSelectionEnd());
+        assertEquals(COMPOSING_TEXT_START, info2.getComposingTextStart());
+        assertEquals(COMPOSING_TEXT, info2.getComposingText());
+        assertEquals(INSERTION_MARKER_HORIZONTAL, info2.getInsertionMarkerHorizontal());
+        assertEquals(INSERTION_MARKER_TOP, info2.getInsertionMarkerTop());
+        assertEquals(INSERTION_MARKER_BASELINE, info2.getInsertionMarkerBaseline());
+        assertEquals(INSERTION_MARKER_BOTOM, info2.getInsertionMarkerBottom());
+        assertEquals(TRANSFORM_MATRIX, info2.getMatrix());
+        for (int i = 0; i < MANY_RECTS.length; i++) {
+            final RectF rect = MANY_RECTS[i];
+            assertEquals(rect, info2.getCharacterRect(i));
+        }
+        assertEquals(info, info2);
+        assertEquals(info.hashCode(), info2.hashCode());
+
+        // Make sure that object can be marshalled via {@link Parsel}.
+        final CursorAnchorInfo info3 = cloneViaParcel(info2);
+        assertEquals(SELECTION_START, info3.getSelectionStart());
+        assertEquals(SELECTION_END, info3.getSelectionEnd());
+        assertEquals(COMPOSING_TEXT_START, info3.getComposingTextStart());
+        assertEquals(COMPOSING_TEXT, info3.getComposingText());
+        assertEquals(INSERTION_MARKER_HORIZONTAL, info3.getInsertionMarkerHorizontal());
+        assertEquals(INSERTION_MARKER_TOP, info3.getInsertionMarkerTop());
+        assertEquals(INSERTION_MARKER_BASELINE, info3.getInsertionMarkerBaseline());
+        assertEquals(INSERTION_MARKER_BOTOM, info3.getInsertionMarkerBottom());
+        assertEquals(TRANSFORM_MATRIX, info3.getMatrix());
+        for (int i = 0; i < MANY_RECTS.length; i++) {
+            final RectF rect = MANY_RECTS[i];
+            assertEquals(rect, info3.getCharacterRect(i));
+        }
+        assertEquals(info.hashCode(), info3.hashCode());
+
+        builder.reset();
+        final CursorAnchorInfo uninitializedInfo = builder.build();
+        assertEquals(-1, uninitializedInfo.getSelectionStart());
+        assertEquals(-1, uninitializedInfo.getSelectionEnd());
+        assertEquals(-1, uninitializedInfo.getComposingTextStart());
+        assertNull(uninitializedInfo.getComposingText());
+        assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerHorizontal());
+        assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerTop());
+        assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBaseline());
+        assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBottom());
+    }
+
+    @SmallTest
+    public void testBuilderAdd() throws Exception {
+        // A negative index should be rejected.
+        try {
+            new CursorAnchorInfoBuilder().addCharacterRect(-1, 0.0f, 0.0f, 0.0f, 0.0f);
+        } catch (IllegalArgumentException ex) {
+            assertTrue(true);
+        }
+    }
+
+    private static CursorAnchorInfo cloneViaParcel(final CursorAnchorInfo src) {
+        Parcel parcel = null;
+        try {
+            parcel = Parcel.obtain();
+            src.writeToParcel(parcel, 0);
+            parcel.setDataPosition(0);
+            return new CursorAnchorInfo(parcel);
+        } finally {
+            if (parcel != null) {
+                parcel.recycle();
+            }
+        }
+    }
+}
+
diff --git a/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java b/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java
new file mode 100644
index 0000000..23b6780
--- /dev/null
+++ b/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
+import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
+
+import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController;
+import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class InputMethodSubtypeSwitchingControllerTest extends InstrumentationTestCase {
+    final private static String DUMMY_PACKAGE_NAME = "dymmy package name";
+    final private static String DUMMY_SETTING_ACTIVITY_NAME = "";
+    final private static boolean DUMMY_IS_AUX_IME = false;
+    final private static boolean DUMMY_FORCE_DEFAULT = false;
+    final private static int DUMMY_IS_DEFAULT_RES_ID = 0;
+    final private static String SYSTEM_LOCALE = "en_US";
+
+    private static InputMethodSubtype createDummySubtype(final String locale) {
+        final InputMethodSubtypeBuilder builder = new InputMethodSubtypeBuilder();
+        return builder.setSubtypeNameResId(0)
+                .setSubtypeIconResId(0)
+                .setSubtypeLocale(locale)
+                .setIsAsciiCapable(true)
+                .build();
+    }
+
+    private static void addDummyImeSubtypeListItems(List<ImeSubtypeListItem> items,
+            String imeName, String imeLabel, List<String> subtypeLocales,
+            boolean supportsSwitchingToNextInputMethod) {
+        final ResolveInfo ri = new ResolveInfo();
+        final ServiceInfo si = new ServiceInfo();
+        final ApplicationInfo ai = new ApplicationInfo();
+        ai.packageName = DUMMY_PACKAGE_NAME;
+        ai.enabled = true;
+        si.applicationInfo = ai;
+        si.enabled = true;
+        si.packageName = DUMMY_PACKAGE_NAME;
+        si.name = imeName;
+        si.exported = true;
+        si.nonLocalizedLabel = imeLabel;
+        ri.serviceInfo = si;
+        final List<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+        for (String subtypeLocale : subtypeLocales) {
+            subtypes.add(createDummySubtype(subtypeLocale));
+        }
+        final InputMethodInfo imi = new InputMethodInfo(ri, DUMMY_IS_AUX_IME,
+                DUMMY_SETTING_ACTIVITY_NAME, subtypes, DUMMY_IS_DEFAULT_RES_ID,
+                DUMMY_FORCE_DEFAULT, supportsSwitchingToNextInputMethod);
+        for (int i = 0; i < subtypes.size(); ++i) {
+            final String subtypeLocale = subtypeLocales.get(i);
+            items.add(new ImeSubtypeListItem(imeName, subtypeLocale, imi, i, subtypeLocale,
+                    SYSTEM_LOCALE));
+        }
+    }
+
+    private static List<ImeSubtypeListItem> createTestData() {
+        final List<ImeSubtypeListItem> items = new ArrayList<ImeSubtypeListItem>();
+        addDummyImeSubtypeListItems(items, "switchAwareLatinIme", "switchAwareLatinIme",
+                Arrays.asList("en_US", "es_US", "fr"),
+                true /* supportsSwitchingToNextInputMethod*/);
+        addDummyImeSubtypeListItems(items, "nonSwitchAwareLatinIme", "nonSwitchAwareLatinIme",
+                Arrays.asList("en_UK", "hi"),
+                false /* supportsSwitchingToNextInputMethod*/);
+        addDummyImeSubtypeListItems(items, "switchAwareJapaneseIme", "switchAwareJapaneseIme",
+                Arrays.asList("ja_JP"),
+                true /* supportsSwitchingToNextInputMethod*/);
+        addDummyImeSubtypeListItems(items, "nonSwitchAwareJapaneseIme", "nonSwitchAwareJapaneseIme",
+                Arrays.asList("ja_JP"),
+                false /* supportsSwitchingToNextInputMethod*/);
+        return items;
+    }
+
+    @SmallTest
+    public void testGetNextInputMethodImplWithNotOnlyCurrentIme() throws Exception {
+        final List<ImeSubtypeListItem> imList = createTestData();
+
+        final boolean ONLY_CURRENT_IME = false;
+        ImeSubtypeListItem currentIme;
+        ImeSubtypeListItem nextIme;
+
+        // "switchAwareLatinIme/en_US" -> "switchAwareLatinIme/es_US"
+        currentIme = imList.get(0);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(1), nextIme);
+        // "switchAwareLatinIme/es_US" -> "switchAwareLatinIme/fr"
+        currentIme = imList.get(1);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(2), nextIme);
+        // "switchAwareLatinIme/fr" -> "switchAwareJapaneseIme/ja_JP"
+        currentIme = imList.get(2);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(5), nextIme);
+        // "switchAwareJapaneseIme/ja_JP" -> "switchAwareLatinIme/en_US"
+        currentIme = imList.get(5);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(0), nextIme);
+
+        // "nonSwitchAwareLatinIme/en_UK" -> "nonSwitchAwareLatinIme/hi"
+        currentIme = imList.get(3);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(4), nextIme);
+        // "nonSwitchAwareLatinIme/hi" -> "nonSwitchAwareJapaneseIme/ja_JP"
+        currentIme = imList.get(4);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(6), nextIme);
+        // "nonSwitchAwareJapaneseIme/ja_JP" -> "nonSwitchAwareLatinIme/en_UK"
+        currentIme = imList.get(6);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(3), nextIme);
+    }
+
+    @SmallTest
+    public void testGetNextInputMethodImplWithOnlyCurrentIme() throws Exception {
+        final List<ImeSubtypeListItem> imList = createTestData();
+
+        final boolean ONLY_CURRENT_IME = true;
+        ImeSubtypeListItem currentIme;
+        ImeSubtypeListItem nextIme;
+
+        // "switchAwareLatinIme/en_US" -> "switchAwareLatinIme/es_US"
+        currentIme = imList.get(0);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(1), nextIme);
+        // "switchAwareLatinIme/es_US" -> "switchAwareLatinIme/fr"
+        currentIme = imList.get(1);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(2), nextIme);
+        // "switchAwareLatinIme/fr" -> "switchAwareLatinIme/en_US"
+        currentIme = imList.get(2);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(0), nextIme);
+
+        // "nonSwitchAwareLatinIme/en_UK" -> "nonSwitchAwareLatinIme/hi"
+        currentIme = imList.get(3);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(4), nextIme);
+        // "nonSwitchAwareLatinIme/hi" -> "switchAwareLatinIme/en_UK"
+        currentIme = imList.get(4);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertEquals(imList.get(3), nextIme);
+
+        // "switchAwareJapaneseIme/ja_JP" -> null
+        currentIme = imList.get(5);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertNull(nextIme);
+
+        // "nonSwitchAwareJapaneseIme/ja_JP" -> null
+        currentIme = imList.get(6);
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+                        currentIme.mSubtypeName.toString()));
+        assertNull(nextIme);
+    }
+ }
diff --git a/core/tests/inputmethodtests/src/android/os/SparseRectFArrayTest.java b/core/tests/inputmethodtests/src/android/os/SparseRectFArrayTest.java
new file mode 100644
index 0000000..fae7230
--- /dev/null
+++ b/core/tests/inputmethodtests/src/android/os/SparseRectFArrayTest.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.graphics.RectF;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.inputmethod.SparseRectFArray;
+import android.view.inputmethod.SparseRectFArray.SparseRectFArrayBuilder;
+
+import java.util.Objects;
+
+public class SparseRectFArrayTest extends InstrumentationTestCase {
+    // A test data for {@link SparseRectFArray}. null represents the gap of indices.
+    private static final RectF[] MANY_RECTS = new RectF[] {
+            null,
+            new RectF(102.0f, 202.0f, 302.0f, 402.0f),
+            new RectF(103.0f, 203.0f, 303.0f, 403.0f),
+            new RectF(104.0f, 204.0f, 304.0f, 404.0f),
+            new RectF(105.0f, 205.0f, 305.0f, 405.0f),
+            new RectF(106.0f, 206.0f, 306.0f, 406.0f),
+            null,
+            new RectF(108.0f, 208.0f, 308.0f, 408.0f),
+            new RectF(109.0f, 209.0f, 309.0f, 409.0f),
+            new RectF(110.0f, 210.0f, 310.0f, 410.0f),
+            new RectF(111.0f, 211.0f, 311.0f, 411.0f),
+            new RectF(112.0f, 212.0f, 312.0f, 412.0f),
+            new RectF(113.0f, 213.0f, 313.0f, 413.0f),
+            new RectF(114.0f, 214.0f, 314.0f, 414.0f),
+            new RectF(115.0f, 215.0f, 315.0f, 415.0f),
+            new RectF(116.0f, 216.0f, 316.0f, 416.0f),
+            new RectF(117.0f, 217.0f, 317.0f, 417.0f),
+            null,
+            null,
+            new RectF(118.0f, 218.0f, 318.0f, 418.0f),
+    };
+
+    @SmallTest
+    public void testBuilder() throws Exception {
+        final RectF TEMP_RECT = new RectF(10.0f, 20.0f, 30.0f, 40.0f);
+
+        final SparseRectFArrayBuilder builder = new SparseRectFArrayBuilder();
+        builder.append(100, TEMP_RECT.left, TEMP_RECT.top, TEMP_RECT.right, TEMP_RECT.bottom);
+        assertNull(builder.build().get(-1));
+        assertNull(builder.build().get(0));
+        assertNull(builder.build().get(99));
+        assertEquals(TEMP_RECT, builder.build().get(100));
+        assertNull(builder.build().get(101));
+
+        // Test if {@link SparseRectFArrayBuilder#reset} resets its internal state.
+        builder.reset();
+        assertNull(builder.build().get(100));
+
+        builder.reset();
+        for (int i = 0; i < MANY_RECTS.length; i++) {
+            final RectF rect = MANY_RECTS[i];
+            if (rect != null) {
+                builder.append(i, rect.left, rect.top, rect.right, rect.bottom);
+            }
+        }
+        final SparseRectFArray array = builder.build();
+        for (int i = 0; i < MANY_RECTS.length; i++) {
+            final RectF rect = MANY_RECTS[i];
+            assertEquals(rect, array.get(i));
+        }
+
+        // Make sure the builder reproduces an equivalent object.
+        final SparseRectFArray array2 = builder.build();
+        for (int i = 0; i < MANY_RECTS.length; i++) {
+            final RectF rect = MANY_RECTS[i];
+            assertEquals(rect, array2.get(i));
+        }
+        assertEqualRects(array, array2);
+
+        // Make sure the instance can be marshaled via {@link Parcel}.
+        final SparseRectFArray array3 = cloneViaParcel(array);
+        for (int i = 0; i < MANY_RECTS.length; i++) {
+            final RectF rect = MANY_RECTS[i];
+            assertEquals(rect, array3.get(i));
+        }
+        assertEqualRects(array, array3);
+
+        // Make sure the builder can be reset.
+        builder.reset();
+        assertNull(builder.build().get(0));
+    }
+
+    @SmallTest
+    public void testEquality() throws Exception {
+        // Empty array should be equal.
+        assertEqualRects(new SparseRectFArrayBuilder().build(),
+                new SparseRectFArrayBuilder().build());
+
+        assertEqualRects(
+                new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f).build(),
+                new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f).build());
+        assertNotEqualRects(
+                new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f).build(),
+                new SparseRectFArrayBuilder().append(100, 2.0f, 2.0f, 3.0f, 4.0f).build());
+        assertNotEqualRects(
+                new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f).build(),
+                new SparseRectFArrayBuilder().append(101, 1.0f, 2.0f, 3.0f, 4.0f).build());
+
+        assertEqualRects(
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build(),
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build());
+        assertNotEqualRects(
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f).build(),
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build());
+        assertNotEqualRects(
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build(),
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f).build());
+        assertNotEqualRects(
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build(),
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(101, 1.0f, 0.0f, 0.0f, 0.0f).build());
+        assertNotEqualRects(
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(101, 1.0f, 0.0f, 0.0f, 0.0f).build(),
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build());
+        assertNotEqualRects(
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build(),
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(102, 0.0f, 0.0f, 0.0f, 0.0f).build());
+
+        assertEqualRects(
+                new SparseRectFArrayBuilder()
+                        .append(1, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(1000, 0.0f, 0.0f, 0.0f, 0.0f)
+                        .append(100000000, 0.0f, 0.0f, 0.0f, 0.0f)
+                        .build(),
+                new SparseRectFArrayBuilder()
+                        .append(1, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(1000, 0.0f, 0.0f, 0.0f, 0.0f)
+                        .append(100000000, 0.0f, 0.0f, 0.0f, 0.0f)
+                        .build());
+
+        assertNotEqualRects(
+                new SparseRectFArrayBuilder()
+                        .append(1, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(1000, 0.0f, 0.0f, 0.0f, 0.0f)
+                        .append(100000000, 0.0f, 0.0f, 0.0f, 0.0f)
+                        .build(),
+                new SparseRectFArrayBuilder()
+                        .append(1, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .build());
+        assertNotEqualRects(
+                new SparseRectFArrayBuilder()
+                        .append(1, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(1000, 0.0f, 0.0f, 0.0f, 0.0f)
+                        .append(100000000, 0.0f, 0.0f, 0.0f, 0.0f)
+                        .build(),
+                new SparseRectFArrayBuilder()
+                        .append(1, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(1000, 1.0f, 0.0f, 0.0f, 0.0f)
+                        .append(100000000, 0.0f, 0.0f, 0.0f, 0.0f)
+                        .build());
+    }
+
+    @SmallTest
+    public void testBuilderAppend() throws Exception {
+        // Key should be appended in ascending order.
+        try {
+            new SparseRectFArrayBuilder().append(10, 0, 0, 0, 0).append(0, 1, 2, 3, 4);
+        } catch (IllegalArgumentException ex) {
+            assertTrue(true);
+        }
+
+        try {
+            new SparseRectFArrayBuilder().append(10, 0, 0, 0, 0).append(10, 1, 2, 3, 4);
+        } catch (IllegalArgumentException ex) {
+            assertTrue(true);
+        }
+    }
+
+    private static void assertEqualRects(SparseRectFArray a, SparseRectFArray b) {
+        assertEquals(a, b);
+        if (a != null && b != null) {
+            assertEquals(a.hashCode(), b.hashCode());
+        }
+    }
+
+    private static void assertNotEqualRects(SparseRectFArray a, SparseRectFArray b) {
+        assertFalse(Objects.equals(a, b));
+    }
+
+    private static SparseRectFArray cloneViaParcel(final SparseRectFArray src) {
+        Parcel parcel = null;
+        try {
+            parcel = Parcel.obtain();
+            src.writeToParcel(parcel, 0);
+            parcel.setDataPosition(0);
+            return new SparseRectFArray(parcel);
+        } finally {
+            if (parcel != null) {
+                parcel.recycle();
+            }
+        }
+    }
+}
diff --git a/data/keyboards/Generic.kcm b/data/keyboards/Generic.kcm
index 01d22ee..1ef74ba 100644
--- a/data/keyboards/Generic.kcm
+++ b/data/keyboards/Generic.kcm
@@ -492,11 +492,11 @@
 }
 
 key BUTTON_X {
-    base:                               fallback DPAD_CENTER
+    base:                               fallback DEL
 }
 
 key BUTTON_Y {
-    base:                               fallback BACK
+    base:                               fallback SPACE
 }
 
 key BUTTON_Z {
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index 56423c9..cfc1484 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -404,6 +404,8 @@
 # key 503 KEY_BRL_DOT7
 # key 504 KEY_BRL_DOT8
 
+key 580   APP_SWITCH
+
 # Keys defined by HID usages
 key usage 0x0c006F BRIGHTNESS_UP
 key usage 0x0c0070 BRIGHTNESS_DOWN
diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml
index fc60e1f..58cf523 100644
--- a/docs/html/_redirects.yaml
+++ b/docs/html/_redirects.yaml
@@ -81,7 +81,7 @@
   to: /guide/components/aidl.html
 
 - from: /guide/publishing/publishing.html
-  to: /distribute/googleplay/publish/preparing.html
+  to: /distribute/tools/launch-checklist.html
 
 - from: /guide/publishing/...
   to: /tools/publishing/...
diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index 92ecd24..c61a94b 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -1,4 +1,7 @@
 page.title=Dashboards
+page.metaDescription=page.metaDescription=Charts that give you an overview of device characteristics and platform versions that are active in the Android ecosystem.
+page.tags="android, dashboard, platforms, versions"
+meta.tags="ecosystem, versions, whatsnew"
 @jd:body
 
 <style>
@@ -22,7 +25,7 @@
 <div class="sidebox">
 <h2>Google Play Install Stats</h2>
 <p>The Google Play Developer Console also provides <a
-href="{@docRoot}distribute/googleplay/about/distribution.html#stats">detailed statistics</a>
+href="{@docRoot}distribute/googleplay/developer-console.html#app-stats">detailed statistics</a>
 about your users' devices. Those stats may help you prioritize the device profiles for which
 you optimize your app.</p>
 </div>
@@ -61,7 +64,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on April 1, 2014.
+<p style="clear:both"><em>Data collected during a 7-day period ending on May 1, 2014.
 <br/>Any versions with less than 0.1% distribution are not shown.</em>
 </p>
 
@@ -92,7 +95,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on April 1, 2014.
+<p style="clear:both"><em>Data collected during a 7-day period ending on May 1, 2014.
 <br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
 
 
@@ -111,7 +114,7 @@
 
 
 <img alt="" style="float:right"
-src="//chart.googleapis.com/chart?chl=GL%201.1%20only%7CGL%202.0%7CGL%203.0&chf=bg%2Cs%2C00000000&chd=t%3A0.1%2C93.5%2C6.4&chco=c4df9b%2C6fad0c&chs=400x250&cht=p" />
+src="//chart.googleapis.com/chart?chs=400x250&cht=p&chd=t%3A0.1%2C87.0%2C12.9&chf=bg%2Cs%2C00000000&chl=GL%201.1%20only%7CGL%202.0%7CGL%203.0&chco=c4df9b%2C6fad0c" />
 
 <p>To declare which version of OpenGL ES your application requires, you should use the {@code
 android:glEsVersion} attribute of the <a
@@ -133,17 +136,17 @@
 </tr>
 <tr>
 <td>2.0</th>
-<td>89.4%</td>
+<td>87.0%</td>
 </tr>
 <tr>
 <td>3.0</th>
-<td>10.5%</td>
+<td>12.9%</td>
 </tr>
 </table>
 
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on April 1, 2014</em></p>
+<p style="clear:both"><em>Data collected during a 7-day period ending on May 1, 2014</em></p>
 
 
 
@@ -161,17 +164,17 @@
 var VERSION_DATA =
 [
   {
-    "chart": "//chart.googleapis.com/chart?cht=p&chs=500x250&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A1.1%2C17.8%2C0.1%2C14.3%2C61.4%2C5.3&chl=Froyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat",
+    "chart": "//chart.googleapis.com/chart?chs=500x250&cht=p&chd=t%3A1.0%2C16.2%2C0.1%2C13.4%2C60.8%2C8.5&chf=bg%2Cs%2C00000000&chl=Froyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat&chco=c4df9b%2C6fad0c",
     "data": [
       {
         "api": 8,
         "name": "Froyo",
-        "perc": "1.1"
+        "perc": "1.0"
       },
       {
         "api": 10,
         "name": "Gingerbread",
-        "perc": "17.8"
+        "perc": "16.2"
       },
       {
         "api": 13,
@@ -181,27 +184,27 @@
       {
         "api": 15,
         "name": "Ice Cream Sandwich",
-        "perc": "14.3"
+        "perc": "13.4"
       },
       {
         "api": 16,
         "name": "Jelly Bean",
-        "perc": "34.4"
+        "perc": "33.5"
       },
       {
         "api": 17,
         "name": "Jelly Bean",
-        "perc": "18.1"
+        "perc": "18.8"
       },
       {
         "api": 18,
         "name": "Jelly Bean",
-        "perc": "8.9"
+        "perc": "8.5"
       },
       {
         "api": 19,
         "name": "KitKat",
-        "perc": "5.3"
+        "perc": "8.5"
       }
     ]
   }
@@ -217,19 +220,19 @@
     "data": {
       "Large": {
         "hdpi": "0.6",
-        "ldpi": "0.7",
+        "ldpi": "0.6",
         "mdpi": "4.4",
-        "tvdpi": "1.5",
+        "tvdpi": "1.6",
         "xhdpi": "0.6"
       },
       "Normal": {
-        "hdpi": "33.7",
-        "mdpi": "13.2",
-        "xhdpi": "19.8",
-        "xxhdpi": "12.5"
+        "hdpi": "33.9",
+        "mdpi": "12.5",
+        "xhdpi": "19.9",
+        "xxhdpi": "13.5"
       },
       "Small": {
-        "ldpi": "8.1"
+        "ldpi": "7.5"
       },
       "Xlarge": {
         "hdpi": "0.3",
@@ -238,8 +241,8 @@
         "xhdpi": "0.3"
       }
     },
-    "densitychart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A8.9%2C21.8%2C1.5%2C34.6%2C20.7%2C12.6&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi",
-    "layoutchart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A4.9%2C7.8%2C79.3%2C8.1&chl=Xlarge%7CLarge%7CNormal%7CSmall"
+    "densitychart": "//chart.googleapis.com/chart?chs=400x250&cht=p&chd=t%3A8.2%2C21.1%2C1.6%2C34.8%2C20.8%2C13.5&chf=bg%2Cs%2C00000000&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chco=c4df9b%2C6fad0c",
+    "layoutchart": "//chart.googleapis.com/chart?chs=400x250&cht=p&chd=t%3A4.9%2C7.8%2C80.0%2C7.5&chf=bg%2Cs%2C00000000&chl=Xlarge%7CLarge%7CNormal%7CSmall&chco=c4df9b%2C6fad0c"
   }
 ];
 
diff --git a/docs/html/design/index.jd b/docs/html/design/index.jd
index 7c7c5d9..cb7dd4f 100644
--- a/docs/html/design/index.jd
+++ b/docs/html/design/index.jd
@@ -1,5 +1,7 @@
 page.title=Design
 page.viewport_width=970
+section.landing=true
+meta.tags="beautifulapps, design, ux, patterns, holo, appquality, landing"
 header.hide=1
 footer.hide=1
 @jd:body
diff --git a/docs/html/design/patterns/multi-pane-layouts.jd b/docs/html/design/patterns/multi-pane-layouts.jd
index c207006..4e99462 100644
--- a/docs/html/design/patterns/multi-pane-layouts.jd
+++ b/docs/html/design/patterns/multi-pane-layouts.jd
@@ -1,6 +1,7 @@
 page.title=Multi-pane Layouts
 page.tags="tablet","navigation","layout","fragment"
-page.metaDescription=Android devices come in many different screen sizes and types. Multi-pane layouts help you provide a balanced and aesthetically pleasing layout across the range of Android devices.
+page.metaDescription=Design guide with examples of how to flatten navigation and provide improved layout across the range of Android devices.
+
 @jd:body
 
 
diff --git a/docs/html/design/patterns/navigation.jd b/docs/html/design/patterns/navigation.jd
index 3edf6ba..703528e 100644
--- a/docs/html/design/patterns/navigation.jd
+++ b/docs/html/design/patterns/navigation.jd
@@ -1,5 +1,6 @@
 page.title=Navigation with Back and Up
-page.tags=navigation,activity,task,up navigation,back navigation
+page.tags="navigation","activity","task","up navigation","back navigation"
+page.image=/design/media/navigation_between_siblings_gmail.png
 @jd:body
 
 <a class="notice-developers" href="{@docRoot}training/implementing-navigation/index.html">
diff --git a/docs/html/design/patterns/widgets.jd b/docs/html/design/patterns/widgets.jd
index 654cf37..47acc7b 100644
--- a/docs/html/design/patterns/widgets.jd
+++ b/docs/html/design/patterns/widgets.jd
@@ -1,5 +1,6 @@
 page.title=Widgets
-page.tags=appwidget,home
+page.tags="appwidget","home"
+page.metaDescription=Design guide to creating widgets that are easy to use and look great.
 @jd:body
 
 <a class="notice-developers" href="{@docRoot}guide/topics/appwidgets/index.html">
diff --git a/docs/html/design/style/devices-displays.jd b/docs/html/design/style/devices-displays.jd
index a8f9d6f..6a7234b 100644
--- a/docs/html/design/style/devices-displays.jd
+++ b/docs/html/design/style/devices-displays.jd
@@ -1,7 +1,9 @@
 page.title=Devices and Displays
+page.metaDescription=Take advantage of Android's flexible layout system and create apps that gracefully scale from phones to tablets and beyond.
+
 @jd:body
 
-<p>Android powers millions of phones, tablets, and other devices in a wide variety of screen sizes and
+<p>Android powers hundreds of millions of phones, tablets, and other devices in a wide variety of screen sizes and
 form factors. By taking advantage of Android's flexible layout system, you can create apps that
 gracefully scale from large tablets to smaller phones.</p>
 
diff --git a/docs/html/design/style/metrics-grids.jd b/docs/html/design/style/metrics-grids.jd
index a553475..e92d57e 100644
--- a/docs/html/design/style/metrics-grids.jd
+++ b/docs/html/design/style/metrics-grids.jd
@@ -1,5 +1,8 @@
 page.title=Metrics and Grids
-page.tags=layout,screens
+page.metaDescription=Optimize your app's UI by designing layouts based on density-independent grids.
+page.tags="layout","screens"
+meta.tags="multiple screens, layout, tablets"
+page.image=/design/media/metrics_closeup.png
 @jd:body
 
 <p>Devices vary not only in physical size, but also in screen density (<acronym title="Dots per
diff --git a/docs/html/design/style/typography.jd b/docs/html/design/style/typography.jd
index ec6fba2..6923f0b 100644
--- a/docs/html/design/style/typography.jd
+++ b/docs/html/design/style/typography.jd
@@ -1,5 +1,6 @@
 page.title=Typography
-page.tags=textview,font
+page.tags="textview","font"
+page.metaDescription=How to use typography in your Android apps.
 @jd:body
 
 <div class="layout-content-row">
diff --git a/docs/html/develop/index.jd b/docs/html/develop/index.jd
index eb28da8..bb90cca 100644
--- a/docs/html/develop/index.jd
+++ b/docs/html/develop/index.jd
@@ -1,6 +1,8 @@
 fullpage=true
-page.title=Develop
+page.title=Develop Apps
 page.viewport_width=970
+meta.tags="develop, getstarted, sdk, appquality, landing"
+section.landing=true
 header.hide=1
 carousel=1
 tabbedList=1
diff --git a/docs/html/distribute/distribute_toc.cs b/docs/html/distribute/distribute_toc.cs
deleted file mode 100644
index 1fabcb3..0000000
--- a/docs/html/distribute/distribute_toc.cs
+++ /dev/null
@@ -1,103 +0,0 @@
-<ul id="nav">
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/index.html">Google Play</a></div>
-    <ul>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/about/visibility.html">Visibility</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/about/monetizing.html">Monetizing</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/about/distribution.html">Distribution</a></li>
-    </ul>  
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/publish/index.html">Publishing</a></div>
-    <ul>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/register.html">Get Started</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/console.html">Developer Console</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/localizing.html">Localization Checklist</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/preparing.html">Launch Checklist</a></li>
-    </ul>
-  </li>
-  
-<!--  <li class="nav-section">
-    <div class="nav-section-header">
-      <a href="<?cs var:toroot ?>distribute/googleplay/developer-console.html">The Developer Console</a>
-    </div>
-    <ul>
-      <li class="nav-section"><a href="<?cs var:toroot ?>distribute/googleplay/register.html">Get Started</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/distribution-controls.html">Managing Distribution</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/pricing-billing.html">Pricing and Billing</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/app-data.html">Reviewing App Data</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/advanced-options.html">Advanced Options</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/publishing.html">Publishing and Updating</a></li>
-    </ul>
-  </li> end of Developer Console -->
-
-   <li class="nav-section">
-     <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/promote/index.html">Promoting</a>
-     </div>
-     <ul>
-<!--   <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/product-pages.html">Your Product Pages</a></li> -->
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/linking.html">Linking to Your Products</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/badges.html">Google Play Badges</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/promote/device-art.html">Device Art Generator</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/brand.html">Brand Guidelines</a></li>
-     </ul>
-   </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/quality/index.html">App Quality</a></div>
-    <ul>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/quality/core.html">Core App Quality</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/quality/tablet.html">Tablet App Quality</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/strategies/app-quality.html">Improving App Quality</a></li>
-    </ul>
-  </li> 
-
-   <li class="nav-section">
-     <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/policies/index.html">Policies</a></div>
-     <ul>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/policies/spam.html">Spam</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/policies/ip.html">Intellectual<br />Property</a></li> 
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/policies/ads.html">Ads</a></li>
-     </ul>
-   </li>
-
-<!--    
-   <li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/after.html">
-      After Launch</a>
-    </div>
-    <ul>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/errors.html.html">Reviewing Errors</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/reviews.html">Tracking User Reviews</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/supporting-users.html">Supporting Users</a></li>
-    </ul>
-  </li> 
--->
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/index.html">Spotlight</a></div>
-    <ul>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/tablets.html">Tablet Stories</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/games.html">Game Stories</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/localization.html">Localization Stories</a></li>
-    </ul>
-  </li> 
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/edu/index.html">Google Play for Education</a></div>
-    <ul>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/edu/about.html">About</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/edu/start.html">Get Started</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/edu/guidelines.html">Guidelines</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/edu/faq.html">FAQ</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/edu/contact.html">Sign Up</a></li>
-    </ul>  
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>distribute/open.html">Open Distribution</a></div>
-  </li>
-</ul>
-  
\ No newline at end of file
diff --git a/docs/html/distribute/engage/app-updates.jd b/docs/html/distribute/engage/app-updates.jd
new file mode 100644
index 0000000..6b751b9
--- /dev/null
+++ b/docs/html/distribute/engage/app-updates.jd
@@ -0,0 +1,50 @@
+page.title=Update Your Apps Regularly
+page.metaDescription=Keeping your content fresh gives users a reason to come back.
+page.tags="updates"
+page.image=/images/gp-your-user-0.jpg
+
+@jd:body
+
+<p>
+  Keeping your content fresh gives users a reason to come back. Use any
+  <a href="{@docRoot}distribute/users/know-your-user.html#add-analytics">in-app
+  or game measurement tool</a> to keep an eye on what users respond to. Use
+  <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">alpha-beta
+  testing</a> and <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#staged-rollouts">staged
+  rollouts</a> to quickly test new features, in-app content, and game
+  characters.
+</p>
+
+<p>
+  Updating regularly also gives you a chance to notify users about new content
+  should users lapse. Notification, email, and social media are several
+  channels to remind users to come back.
+</p>
+
+<p>
+  Check out the video below see how Kiwi uses frequent updates to engage and
+  retain users.
+</p>
+
+<p style="margin-bottom:2em">
+</p>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/engage/kiwi" data-sortorder="-timestamp" data-cardsizes=
+"18x6," data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="related-resources">
+    Related Resources
+  </h1>
+
+  <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/engage/appupdates" data-sortorder="-timestamp"
+data-cardsizes="9x3" data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/community.jd b/docs/html/distribute/engage/community.jd
new file mode 100644
index 0000000..035058a
--- /dev/null
+++ b/docs/html/distribute/engage/community.jd
@@ -0,0 +1,43 @@
+page.title=Engage Your Community
+page.metaDescription=Building a community has many benefits, including improving your app and bringing users back to it.
+page.image=/images/gp-engage-9.jpg
+
+
+@jd:body
+
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-engage-9.jpg" style="width:300px;">
+</div>
+
+<p>
+  Building a community has many benefits, including improving your apps and
+  bringing users back to them. Using social media, groups, and forum tools will
+  help you build a rapport with your audience that will drive loyalty and
+  engagement.
+</p>
+
+<p>
+  There are many tactics to bring users back to your apps. In addition to app
+  updates that users want to check out, you can also use communities to
+  announce game tournaments, new content, promotions, and other great content.
+  Any reason to go back to your app is a great post to share with your
+  community.
+</p>
+
+<p>
+  Learn more about how to <a href="{@docRoot}distribute/users/build-community.html">build and manage a community</a>.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="related-resources">
+    Related Resources
+  </h1>
+
+  <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/engage/community" data-sortorder="-timestamp"
+data-cardsizes="9x3" data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/deep-linking.jd b/docs/html/distribute/engage/deep-linking.jd
new file mode 100644
index 0000000..cd62f9d
--- /dev/null
+++ b/docs/html/distribute/engage/deep-linking.jd
@@ -0,0 +1,78 @@
+page.title=Deep Link to Bring Users Back
+page.metaDescription=Use deep links to bring your users into your apps from social posts or search.
+page.tags="app indexing, google+ signin"
+page.image=/images/gp-listing-4.jpg
+
+@jd:body
+
+<p>
+  Use deep links to bring your users into your apps from social posts or
+  search.
+</p>
+
+<div class="headerLine">
+<h1>Deep Linking from Google+ Posts</h1><hr>
+</div>
+
+<p>
+  <a href="https://developers.google.com/+/mobile/android/share/deep-link">Deep
+  linking</a> allows the Google+ apps on mobile devices to direct clicks on a
+  shared post that contains deep-link information to a resource within your
+  apps.
+</p>
+
+<p style="margin-bottom:2em;">
+  If the user doesn’t have your app installed, they’re prompted to install it
+  before accessing the resource.
+</p>
+
+<div style="padding:2em, auto;width:550px;">
+  <div style="float:right; width:260px; padding-left:1em;">
+    <img src="{@docRoot}images/gp-engage-5.jpg" class="border-img">
+    <p class="img-caption">
+      G+ Post with Deep Link to Buy
+    </p>
+  </div>
+
+  <div style="width:260px;float:left;">
+    <img src="{@docRoot}images/gp-engage-6.jpg" class="border-img">
+    <p class="img-caption">
+      Purchase page within app
+    </p>
+  </div>
+</div>
+
+
+<div class="headerLine clearfloat">
+<h1>Deep Linking from Google Search &mdash; App Indexing</h1><hr>
+</div>
+
+<p>
+  Another way to bring users back to your apps is to apply for app indexing.
+</p>
+
+<p>
+  When a user searches for content available within your app, Google can show
+  an "Open in App" button in in mobile search results. For instance, if a user
+  searches for a restaurant and you’ve got that establishment in your dining
+  app, a link can be shown to open the page within your app. Learn more about
+  <a href="https://developers.google.com/app-indexing/">linking to in-app
+  content</a>.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-listing-4.jpg" style="padding-top:1em;">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="related-resources">
+    Related Resources
+  </h1>
+
+  <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/engage/deeplinks" data-sortorder="-timestamp"
+data-cardsizes="9x3" data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/easy-signin.jd b/docs/html/distribute/engage/easy-signin.jd
new file mode 100644
index 0000000..92c3ffc
--- /dev/null
+++ b/docs/html/distribute/engage/easy-signin.jd
@@ -0,0 +1,103 @@
+page.title=Make Signing In Easy
+page.metaDescription=Increase conversion rates while helping users minimize typing by letting users sign in with Google+.
+page.tags="google+"
+page.image=/images/google/gps-googleplus.png
+
+
+@jd:body
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox" style="width:360px;">
+    <p>
+      <strong>Tip:</strong> For game developers, Google+ signin is already
+      included as part of Google Play game services.
+    </p>
+  </div>
+</div>
+
+<p>
+  Increase conversion rates while helping users minimize typing by letting
+  users sign in with Google+. The <a href=
+  "{@docRoot}google/play-services/plus.html">Google+ platform for Android</a>
+  authenticates users with their Google credentials safely and securely. With
+  your <a href="https://developers.google.com/+/mobile/android/sign-in">users
+  signing in with Google</a>, you can create more engaging experiences and
+  drive the use of your apps .
+</p>
+
+<div style="width:450px;">
+  <img src="{@docRoot}images/google/gps-googleplus.png" style="padding-top:1em;">
+</div>
+
+<p>
+  Use the Google+ social graph to welcome users by name, display their
+  pictures, connect them with friends and more. Users authenticate once and
+  then are signed-in automatically when they come back, eliminating the need to
+  remember and type names and passwords.
+</p>
+
+<div class="headerLine">
+  <h1>
+    And Spreading the Word a Snap
+  </h1>
+
+  <hr>
+</div>
+
+
+<div class="figure" style="float:right;">
+  <img src="{@docRoot}images/gp-engage-share-plus.png" style=
+  "width:160px;padding-top:1em;">
+  <p class="img-caption">
+    Easy sharing through Google+
+  </p>
+</div>
+
+
+<p>
+  Using Google+ can help users spread the word about your apps to their
+  friends, attracting them to your apps, right from within your apps:
+</p>
+
+<p>
+  Google+ is also a great way to build a community of loyal fans that will help
+  you with <a href=
+  "https://support.google.com/googleplay/android-developer/answer/3131213">beta
+  testing</a>.
+</p>
+
+<ul>
+  <li>Using a <a href=
+  "https://developers.google.com/+/mobile/android/recommend">native +1
+  button</a> to let users make a recommendation for your apps or their content.
+  </li>
+
+  <li>
+    <a href="https://developers.google.com/+/mobile/android/share/">Share rich
+    content</a> to the Google+ stream, including text, photos, URL attachments,
+    and location.
+  </li>
+
+  <li>Create <a href=
+  "https://developers.google.com/+/mobile/android/share/interactive-post">Interactive
+  posts</a> to share your website or apps, users can even invite friends to
+  "listen," "RSVP," "check-in," or one of over 100 actions.
+  </li>
+</ul>
+
+  <div class="headerLine clearfloat">
+    <h1 id="related-resources">
+      Related Resources
+    </h1>
+
+    <hr>
+  </div>
+
+  <div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/engage/gplus"
+  data-sortorder="-timestamp"
+  data-cardsizes="9x3"
+  data-maxresults="6">
+  </div>
+</div>
+
diff --git a/docs/html/distribute/engage/engage_toc.cs b/docs/html/distribute/engage/engage_toc.cs
new file mode 100644
index 0000000..0314f8c
--- /dev/null
+++ b/docs/html/distribute/engage/engage_toc.cs
@@ -0,0 +1,66 @@
+<ul id="nav">
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+        var:toroot?>distribute/engage/widgets.html">
+        <span class="en">Build Useful Widgets</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+        var:toroot?>distribute/engage/notifications.html">
+        <span class="en">Use Rich Notifications</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+        var:toroot?>distribute/engage/gcm.html">
+        <span class="en">Integrate GCM</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+        var:toroot?>distribute/engage/easy-signin.html">
+        <span class="en">Make Signing In Easy</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+        var:toroot?>distribute/engage/deep-linking.html">
+        <span class="en">Deep Link to Bring Users Back</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+        var:toroot?>distribute/engage/game-services.html">
+        <span class="en">Encourage Competition</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+        var:toroot?>distribute/engage/app-updates.html">
+        <span class="en">Update Regularly</span></a>
+    </div>
+  </li>
+
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+        var:toroot?>distribute/engage/community.html">
+        <span class="en">Engage Your Community</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+        var:toroot?>distribute/engage/video.html">
+        <span class="en">Delight with Videos</span></a>
+    </div>
+  </li>
+
+</ul>
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
+
diff --git a/docs/html/distribute/engage/game-services.jd b/docs/html/distribute/engage/game-services.jd
new file mode 100644
index 0000000..5153435
--- /dev/null
+++ b/docs/html/distribute/engage/game-services.jd
@@ -0,0 +1,90 @@
+page.title=Encourage Competition
+page.metaDescription= Bring out the competitor in your users with cloud save, multiplayer game play, and more.
+page.tags="games"
+page.image=/images/google/gps-play_games_logo.png
+
+@jd:body
+
+<div class="figure" style="width:330px;">
+  <img src="{@docRoot}images/google/gps-play_games_logo.png">
+</div>
+
+<p>
+  Increase game installs, in-app revenue, and engagement with <a href=
+  "{@docRoot}google/play-services/games.html">Google Play
+  Game Services</a>. Bring out the competitor in your users with cloud save,
+  multiplayer game play, and more.
+</p>
+
+<ul>
+  <li>
+    <p>
+      <a href=
+      "https://developers.google.com/games/services/android/achievements">Achievements</a>
+      encourage players to try new features, resulting in more time spent in
+      your games.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <a href=
+      "https://developers.google.com/games/services/android/leaderboards">Leaderboards</a>
+      are a fun way to drive competition among your players.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <a href=
+      "https://developers.google.com/games/services/android/cloudsave">Cloud
+      Save</a> allows users to continue where they left off on another device
+      or platform.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Multiplayer features allow users to invite friends to install games and
+      play together in <a href=
+      "https://developers.google.com/games/services/common/concepts/realtimeMultiplayer">
+      real-time</a> or <a href=
+      "https://developers.google.com/games/services/common/concepts/turnbasedMultiplayer">
+      turn-by-turn</a>.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <a href=
+      "https://play.google.com/store/apps/details?id=com.google.android.play.games">
+      Google Play Games App</a> provides additional exposure to increase
+      downloads and gameplay. It helps users play with friends, see what others
+      are playing, and discover featured games.
+    </p>
+  </li>
+</ul>
+
+<p>
+  And there is no need to worrying about device or OS version support. Google
+  Play Game Services is backward compatible, allowing you to reach more
+  users with less effort. Get started on <a href=
+  "{@docRoot}google/play-services/games.html">Google Play
+  Game Services</a>. For more tips on keeping gamers engaged, see the <a href=
+  "{@docRoot}distribute/essentials/best-practices/games.html">
+  Game Developer Best Practices</a>.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="related-resources">
+    Related Resources
+  </h1>
+
+  <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/engage/googleplaygames" data-sortorder="-timestamp"
+data-cardsizes="9x3" data-maxresults="6">
+</div>
+
diff --git a/docs/html/distribute/engage/gcm.jd b/docs/html/distribute/engage/gcm.jd
new file mode 100644
index 0000000..d793124e
--- /dev/null
+++ b/docs/html/distribute/engage/gcm.jd
@@ -0,0 +1,51 @@
+page.title=Integrate Google Cloud Messaging
+page.metaDescription=Keep your users in sync with your latest content by delivering lightweight messages over Google's infrastructure.
+page.tags="gcm"
+page.image=/images/gcm/gcm-logo.png
+
+@jd:body
+
+<div class="figure" style="width:330px">
+  <img src="{@docRoot}images/gcm/gcm-logo.png">
+</div>
+
+<p>
+  Keeping app content fresh is important to retaining users. And it’s easy with
+  the popular <a href="{@docRoot}google/gcm/index.html">Google Cloud
+  Messaging</a> for Android, by sending lightweight messages to your apps
+  installed on Android devices anywhere in the world.
+</p>
+
+<p>
+  Push messages from your backend servers to tell your apps that there's new
+  content for the user, or other data to sync.
+</p>
+
+<p>
+  You can use Google Cloud Messaging for two way messaging too. Another
+  possibility is to improve the experience for users with multiple devices, by
+  syncing content through the cloud so users have the same content on all their
+  devices.
+</p>
+
+<p>
+  Google Cloud Messaging lets your users stay in sync with your service without
+  draining the user’s battery, as there's no need for your apps poll a server
+  to discover new content. Best of all, Google Cloud Messaging is available for
+  free and there are no quotas.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="related-resources">
+    Related Resources
+  </h1>
+
+  <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" 
+  data-query="collection:distribute/engage/gcm"
+  data-sortorder="-timestamp"
+  data-cardsizes="9x3"
+  data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/index.jd b/docs/html/distribute/engage/index.jd
new file mode 100644
index 0000000..f8cd1ee
--- /dev/null
+++ b/docs/html/distribute/engage/index.jd
@@ -0,0 +1,36 @@
+page.title=Engage & Retain Users
+page.metaDescription=Engaging and retaining active users is the key to success. Here are some resources to help you build an active user base.
+section.landing=true
+nonavpage=true
+
+@jd:body
+
+<p>
+  Engaging and retaining active users is the key to success. This is specially
+  true for subscription and in-app purchase models. Here are several tools and
+  techniques to keep your users coming back.
+</p>
+
+<div class="dynamic-grid">
+
+  <div class="resource-widget resource-flow-layout landing col-16"
+    data-query="collection:distribute/engagelanding"
+    data-cardSizes="6x6"
+    data-maxResults="9">
+  </div>
+
+  <h3>Related Resources</h3>
+  <div class="resource-widget resource-flow-layout col-16"
+    data-query="type:youtube+tag:engagement"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x3"
+    data-maxResults="3">
+  </div>
+  <div class="resource-widget resource-flow-layout col-16"
+    data-query="type:blog+tag:engagement"
+    data-sortdOrder="-timestamp"
+    data-cardSizes="6x3"
+    data-maxResults="3">
+  </div>
+
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/notifications.jd b/docs/html/distribute/engage/notifications.jd
new file mode 100644
index 0000000..fecfb45
--- /dev/null
+++ b/docs/html/distribute/engage/notifications.jd
@@ -0,0 +1,61 @@
+page.title=Use Rich Notifications to Keep Users Informed
+page.metaDescription=Use Android's notifications to keep users in touch with your content and services &mdash; even when the app is not in use.
+page.tags=""
+page.image=/design/media/notifications_pattern_anatomy.png
+
+@jd:body
+
+<div class="figure">
+  <img src="{@docRoot}design/media/notifications_pattern_anatomy.png">
+</div>
+
+<p>
+  The <a href="/design/patterns/notifications.html">notification system</a>
+  allows your app to keep the user informed about events, such as new messages,
+  upcoming calendar appointments, shared photos, and much more. They are a
+  fundamental feature of Android that consumers check frequently to receive
+  important notifications and status updates. Notifications are like a news
+  channel that alerts the user to events as they happen and maintains a list of
+  updates since last review.
+</p>
+
+
+
+<p>
+  In addition to status updates from friends and family, notifications can also
+  be used to help gamers know when a time-based action is completed or another
+  player took their turn.</p>
+
+  <p>Some game developers use notifications to alert users
+  when a new limited time character can be won or a discount on an in-app
+  purchase is available. </p>
+
+<h3>But Use Them Sparingly</h3>
+
+<p>
+  Frequent notifications and spam notifications can turn users off, thereby
+  risking your ratings and user base. Also sure to check our <a href=
+  "https://support.google.com/googleplay/android-developer/answer/4430948">policies</a>
+  to ensure you’re treating your user respectfully.
+</p>
+
+
+  <div class="sidebox" style="width:326px;float:left;margin-left:0">
+          <p><strong>Tip:</strong>
+       Use notifications sparingly &mdash; be sure any information presented is
+      useful. Give users the option to turn notifications off.
+    </p>
+  </div>
+
+  <div class="headerLine clearfloat">
+  <h1 id="related-resources">
+    Related Resources
+  </h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" 
+  data-query="collection:distribute/getusers/notifications"
+  data-sortorder="-timestamp"
+  data-cardsizes="9x3"
+  data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/video.jd b/docs/html/distribute/engage/video.jd
new file mode 100644
index 0000000..1a30f3a
--- /dev/null
+++ b/docs/html/distribute/engage/video.jd
@@ -0,0 +1,37 @@
+page.title=Delight Users with Videos
+page.metaDescription=Videos are one of the most effective ways to get users excited about your apps. 
+page.tags="engagement"
+page.image=/images/gp-engage-smule.jpg
+
+@jd:body
+<p>
+  Videos are one of the most effective ways to get users excited about your
+  apps. Use videos to showcase your apps on your Google Play Product Details
+  pages. Be sure to build a <a href="http://www.youtube.com/yt/dev/">YouTube</a>
+  page to host new videos so users can see new features or content that will
+  get them excited to return to your apps.
+</p>
+
+<p>
+  Videos let you do more than tell users about your apps &mdash; you can
+  <em>show them</em>. One of the most viewed content types is how-to videos.
+  Help users progress to the next level with YouTube <strong>game play
+  videos</strong> in Google Play, on your YouTube channel, and on your website.
+</p>
+
+<div class="center-img">
+  <img src="{@docRoot}images/gp-engage-smule.jpg">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="related-resources">
+    Related Resources
+  </h1>
+
+  <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/engage/video/more" data-sortorder="-timestamp"
+data-cardsizes="9x3" data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/widgets.jd b/docs/html/distribute/engage/widgets.jd
new file mode 100644
index 0000000..b17af08
--- /dev/null
+++ b/docs/html/distribute/engage/widgets.jd
@@ -0,0 +1,42 @@
+page.title=Build Useful Widgets
+page.metaDescription=Use widgets to remind users about important information in your apps and games, even when your apps are closed.
+page.tags=""
+page.image=/images/gp-engage-0.jpg
+
+@jd:body
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-engage-0.jpg" style="width:320px;">
+</div>
+<p>
+  <a href=
+  "/design/patterns/widgets.html">Widgets</a> are
+  an essential aspect of home screen customization. They are "at-a-glance"
+  views of an app's <strong>most important data and features</strong>,
+  instantly available from the user's home screen.
+</p>
+
+<p>
+  Use widgets to <strong>remind users</strong> about important information in
+  your apps and games, even when your apps are closed. For instance, if you
+  have a news app, showcase the latest headlines.
+</p>
+
+  <div class="sidebox" style="float:none;margin-left:0">
+  <p><strong>Tip:</strong>
+  Make your widgets useful &mdash; provide in-app information like news, game status,
+  or upcoming deadlines. Widgets should serve as more than a launcher icon.</p>
+  </div>
+
+<div class="headerLine clearfloat">
+  <h1 id="related-resources">
+    Related Resources
+  </h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" 
+  data-query="collection:distribute/engage/widgets"
+  data-sortorder="-timestamp"
+  data-cardsizes="9x3"
+  data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/essentials/best-practices/apps.jd b/docs/html/distribute/essentials/best-practices/apps.jd
new file mode 100644
index 0000000..055a349
--- /dev/null
+++ b/docs/html/distribute/essentials/best-practices/apps.jd
@@ -0,0 +1,260 @@
+page.title=App Developer Best Practices
+page.image=/distribute/images/gp-app-practices.png
+page.metaDescription=Essential tips for launching successful apps in Google Play.
+@jd:body
+
+<div id="qv-wrapper"><div id="qv">
+<h2>Best Practices</h2>
+<ol>
+<li><a href="#essentials">Get the Essentials Right</a></li>
+<li><a href="#users">Get Users</a></li>
+<li><a href="#engage">Engage and Retain</a></li>
+<li><a href="#beyond">Beyond the Basics</a></li>
+<li><a href="#related-resources">Related Resources</a></li>
+</ol>
+</div></div>
+
+<p>The following best practices have enabled developers worldwide to build great, successful apps for Google Play.</p>
+
+<div class="headerLine">
+<h1 id="essentials">Get the Essentials Right</h1><hr>
+</div>
+
+<h3>1. Make it Android</h3>
+
+<ul>
+  <li>
+  <p>
+    Build your apps to make best use of the unique Android features, such as
+    <a href="{@docRoot}distribute/engage/widgets.html">widgets</a>, <a href=
+    "{@docRoot}distribute/engage/notifications.html">rich notifications</a>,
+    <a href=
+    "http://android-developers.blogspot.com/2012/02/share-with-intents.html">sharing
+    through Intents</a>, and more.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Add the power of Google features your users already love, such as
+    <a href="https://developers.google.com/maps/documentation/android/">Google
+    Maps</a>, <a href="https://developers.google.com/drive/">Google
+    Drive</a>, and more, all with <a href=
+    "https://developers.google.com/+/mobile/android/sign-in">single sign
+    on</a>.
+  </p>
+  </li>
+</ul>
+
+<h3>
+  2. Make it quality
+</h3>
+
+<ul>
+  <li>
+  <p>
+    Make sure your apps follow the <a href=
+    "{@docRoot}distribute/essentials/quality/core.html">Core App Quality</a>
+    guidelines.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Create apps that are available on all form factors and screen sizes, by
+    following the <a href=
+    "{@docRoot}distribute/essentials/quality/tablets.html">Tablet App
+    Quality</a> guidelines.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Test and <a href=
+    "{@docRoot}distribute/essentials/optimizing-your-app.html">optimize your
+    quality</a> at every step and make use of the Google Play <a href=
+    "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">beta-testing</a>
+    and <a href=
+    "{@docRoot}distribute/googleplay/developer-console.html#staged-rollouts">staged
+    rollouts</a> features to test with users before launch.
+  </p>
+  </li>
+</ul>
+
+<div class="headerLine">
+  <h1 id="users">
+  Get Users
+  </h1>
+
+  <hr>
+</div>
+
+<h3>
+  1. Build buzz
+</h3>
+
+<ul>
+  <li>
+  <p>
+    Create a great <a href="{@docRoot}distribute/users/your-listing.html">app
+    listing page</a> to showcase your apps and grab users’ attention. Don’t
+    forget to include a <a href=
+    "{@docRoot}distribute/engage/video.html">YouTube video</a>.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    <a href="{@docRoot}distribute/tools/launch-checklist.html">Launch</a> on
+    multiple platforms simultaneously to maximize your reach.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Promote your apps with the official <a href=
+    "{@docRoot}distribute/tools/promote/badges.html">Google Play badge</a>
+    and <a href="{@docRoot}distribute/tools/promote/linking.html">link to
+    your products</a> on Google Play.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Build a community with social media, <a href=
+    "http://groups.google.com/">forums</a>, and <a href=
+    "http://plus.google.com">communities</a> to get and keep users talking.
+  </p>
+  </li>
+</ul>
+
+<h3>
+  2. Optimize for great ratings
+</h3>
+
+<ul>
+  <li>
+  <p>
+    Get to <a href="{@docRoot}distribute/users/know-your-user.html">know your
+    users</a>, listen to and <a href=
+    "{@docRoot}distribute/engage/app-updates.html">update your apps</a> from
+    their feedback.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Focus on your strength markets first, get these right before expanding.
+  </p>
+  </li>
+</ul>
+
+<div class="headerLine">
+  <h1 id="engage">
+  Engage and Retain
+  </h1>
+
+  <hr>
+</div>
+
+<h3>
+  1. Keep users coming back
+</h3>
+
+<ul>
+  <li>
+  <p>
+    Use <a href="{@docRoot}google/play/billing/index.html">Google Play In-app
+    Billing</a> to offer subscriptions to extended features.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Hold competitions and offer promotions, then announce them through
+    <a href="{@docRoot}design/patterns/notifications.html">notifications</a>.
+  </p>
+  </li>
+</ul>
+
+<h3>
+  2. Earn users’ love
+</h3>
+
+<ul>
+  <li>
+  <p>
+    <a href=
+    "http://android-developers.blogspot.com/2013/05/all-google-play-developers-can-now.html">
+    Respond to reviews</a> and get valuable feedback from the community
+    you've built.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    <a href=
+    "http://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html">
+    Measure</a> your campaigns to see what is driving users to install your
+    apps.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    <a href=
+    "{@docRoot}distribute/essentials/optimizing-your-app.html#measuring-analyzing-responding">
+    Analyze in-app use</a> to steer content updates and prolong the life of
+    your apps.
+  </p>
+  </li>
+</ul>
+
+<div class="headerLine">
+  <h1 id="beyond">
+  Beyond the Basics
+  </h1>
+
+  <hr>
+</div>
+
+<ul>
+  <li>
+  <p>
+    After you’ve launched in your market of strength, <a href=
+    "{@docRoot}distribute/users/expand-to-new-markets.html">expand into other
+    markets</a> strategically and <a href=
+    "{@docRoot}distribute/tools/localization-checklist.html">localize</a>
+    your apps as you go.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Keep users engaged, and stay ahead of the competition, by continually
+    <a href=
+    "{@docRoot}distribute/essentials/optimizing-your-app.html">optimizing
+    your apps</a> to offer new and better features, or retire those that
+    users aren’t using.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Build educational apps: learn <a href=
+    "{@docRoot}distribute/googleplay/edu/start.html">how to make apps for
+    Google Play for Education</a>.
+  </p>
+  </li>
+</ul>
+
+<div class="headerLine">
+<h1 id="related-resources">Related Resources</h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/toolsreference/bestpractices/apps"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3,9x3"
+  data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/essentials/best-practices/games.jd b/docs/html/distribute/essentials/best-practices/games.jd
new file mode 100644
index 0000000..ac1df44
--- /dev/null
+++ b/docs/html/distribute/essentials/best-practices/games.jd
@@ -0,0 +1,259 @@
+page.title=Game Developer Best Practices
+page.image=/distribute/images/gp-games-practices.png
+page.metaDescription=Essential tips for launching successful games in Google Play.
+
+@jd:body
+
+<div id="qv-wrapper"><div id="qv">
+<h2>Best Practices</h2>
+<ol>
+<li><a href="#users">Get Users</a></li>
+<li><a href="#engage">Engage and Retain</a></li>
+<li><a href="#beyond">Beyond the Basics</a></li>
+<li><a href="#related-resources">Related Resources</a></li>
+</ol>
+</div></div>
+
+<p>
+  The following best practices have enabled developers worldwide to build
+  great, successful games for Google Play.
+</p>
+
+<div class="headerLine">
+  <h1 id="users">
+  Get Users
+  </h1>
+
+  <hr>
+</div>
+
+<h3>
+  1. Optimize for great ratings
+</h3>
+
+<ul>
+  <li>
+  <p>
+    <a href=
+    "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">Beta
+    test</a> to ensure your games are ready and poised for great ratings.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Optimize graphics, frame rates, and responsiveness with the <a href=
+    "http://android-developers.blogspot.com/2013/09/using-hardware-scaler-for-performance.html">
+    Hardware Scaler</a> and <a href=
+    "{@docRoot}training/graphics/opengl/index.html">OpenGL ES</a>.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Be sure your APK is small, then provide game content through over-the-air
+    downloads.
+  </p>
+  </li>
+</ul>
+
+<h3>
+  2. Build buzz
+</h3>
+
+<ul>
+  <li>
+  <p>
+    Build a community with social media, <a href=
+    "{@docRoot}distribute/users/build-community.html">communities</a> to get
+    and keep users talking.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Promote your games with official <a href=
+    "{@docRoot}distribute/tools/promote/badges.html">Google Play badges</a>
+    and <a href="{@docRoot}distribute/tools/promote/linking.html">links to
+    your products</a> on Google Play.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    If you ship on multiple platforms, doing so at the same time can maximize
+    your marketing impact.
+  </p>
+  </li>
+</ul>
+
+<h3>
+  3. Get Visibility
+</h3>
+
+<ul>
+  <li>
+  <p>
+    First impressions count: <a href=
+    "{@docRoot}distribute/users/your-listing.html">highlight</a> the game's
+    best features in screenshots, videos, and description.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Integrate Google Play Game Services, so your game is displayed in the
+    <a href=
+    "https://play.google.com/store/apps/details?id=com.google.android.play.games">
+    Google Play Games App</a>.
+  </p>
+  </li>
+</ul>
+
+<div class="headerLine">
+  <h1 id="engage">
+  Engage and Retain
+  </h1>
+
+  <hr>
+</div>
+
+<h3>
+  1. Keep users coming back
+</h3>
+
+<ul>
+  <li>
+  <p>
+    <a href=
+    "https://developers.google.com/games/services/common/concepts/achievements">
+    Achievements</a>, <a href=
+    "https://developers.google.com/games/services/common/concepts/leaderboards">
+    leaderboards</a>, <a href=
+    "https://developers.google.com/games/services/common/concepts/realtimeMultiplayer">
+    multiplayer</a>, and <a href=
+    "https://developers.google.com/games/services/common/concepts/cloudsave">cloud
+    save</a> help engage users and bring them back.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Hold tournaments and offer promotions, then announce them through
+    <a href="{@docRoot}design/patterns/notifications.html">notifications</a>.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Sign in users early, then automatically. Before their first sign-in, save
+    progress locally.
+  </p>
+  </li>
+</ul>
+
+<h3>
+  2. Give users a reason to invest their money
+</h3>
+
+<ul>
+  <li>
+  <p>
+    A majority of the top grossing games use in-app purchases. Use them to
+    unlock content and allow players to enhance their game play.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    <a href="{@docRoot}google/play/billing/index.html">Google Play In-app
+    Billing</a> makes purchasing easy with several forms of payment.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Provide content updates regularly to give users limited edition items to
+    win or purchase.
+  </p>
+  </li>
+</ul>
+
+<h3>
+  3. Earn players’ love
+</h3>
+
+<ul>
+  <li>
+  <p>
+    <a href=
+    "http://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html">
+    Measure</a> your campaigns to see what’s driving quality users to install
+    your games.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    <a href=
+    "{@docRoot}distribute/essentials/optimizing-your-app.html#measuring-analyzing-responding">
+    Analyze in-game use</a> to steer content updates and prolong the life of your
+    games.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    <a href=
+    "http://android-developers.blogspot.com/2013/05/all-google-play-developers-can-now.html">
+    Respond to reviews</a> and get valuable feedback from the community
+    you’ve built.
+  </p>
+  </li>
+</ul>
+
+<div class="headerLine">
+  <h1 id="beyond">
+  Beyond the Basics
+  </h1>
+
+  <hr>
+</div>
+
+<ul>
+  <li>
+  <p>
+    After you've launched in your market of strength, <a href=
+    "{@docRoot}distribute/users/expand-to-new-markets.html">expand into other
+    markets</a> strategically and <a href=
+    "{@docRoot}distribute/tools/localization-checklist.html">localize</a>
+    your apps as you go.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Provide content <a href=
+    "{@docRoot}distribute/engage/app-updates.html">updates on a regular
+    basis</a> to keep users engaged.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Building educational games? See the <a href=
+    "{@docRoot}distribute/essentials/gpfe-guidelines.html">Education
+    Guidelines</a>.
+  </p>
+  </li>
+</ul>
+
+<div class="headerLine">
+<h1 id="related-resources">Related Resources</h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/toolsreference/bestpractices/games"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3,9x3"
+  data-maxResults="6"></div>
diff --git a/docs/html/distribute/essentials/essentials_toc.cs b/docs/html/distribute/essentials/essentials_toc.cs
new file mode 100644
index 0000000..7084fdd
--- /dev/null
+++ b/docs/html/distribute/essentials/essentials_toc.cs
@@ -0,0 +1,44 @@
+<ul id="nav">
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/quality/core.html">
+            <span class="en">Core App Quality</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/quality/tablets.html">
+            <span class="en">Tablet App Quality</span>
+          </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/gpfe-guidelines.html">
+          <span class="en">Education Guidelines</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/optimizing-your-app.html">
+          <span class="en">Optimize Your App</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/best-practices/apps.html">
+          <span class="en">App Best Practices</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/best-practices/games.html">
+          <span class="en">Game Best Practices</span>
+        </a>
+    </div>
+  </li>
+
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
diff --git a/docs/html/distribute/essentials/gpfe-guidelines.jd b/docs/html/distribute/essentials/gpfe-guidelines.jd
new file mode 100644
index 0000000..8b47671
--- /dev/null
+++ b/docs/html/distribute/essentials/gpfe-guidelines.jd
@@ -0,0 +1,513 @@
+page.title=Education Guidelines
+page.metaDescription=These guidelines and requirements help you develop great apps for students, which offer compelling content and an intuitive user experience on Android tablets.
+page.image=/distribute/images/edu-guidelines.jpg
+Xnonavpage=true
+
+@jd:body
+
+
+<div id="qv-wrapper"><div id="qv">
+<h2>Guidelines</h2>
+<ol>
+<li><a href="#basic-reqts">Basic Requirements</a></li>
+<li><a href="#monetizing-ads">Monetizing and Ads</a></li>
+<li><a href="#e-value">Educational Value</a></li>
+<li><a href="#quality">App Quality</a></li>
+<li><a href="#related-resources">Related Resources</a></li>
+</ol>
+
+<h2>
+  Testing
+</h2>
+
+<ol>
+  <li>
+    <a href="#test-environment">Setting Up a Test Environment</a>
+  </li>
+</ol>
+
+</div></div>
+
+<div style="margin:0 0 1em 0;">
+  <img src="{@docRoot}distribute/images/edu-guidelines.jpg" style=
+  "width:274px;">
+</div>
+
+<p>
+  These guidelines and requirements help you develop great apps for students,
+  which offer compelling content and an intuitive user experience on Android
+  tablets.
+</p>
+
+<p>
+  You’ll also need to ensure that your apps comply with the terms of the
+  <a href=
+  "https://play.google.com/about/developer-distribution-agreement-addendum.html">
+  Google Play for Education Addendum</a>, <a href=
+  "http://play.google.com/about/developer-content-policy.html">Google Play
+  Developer Program Policies</a>, and <a href=
+  "http://play.google.com/about/developer-distribution-agreement.html">Developer
+  Distribution Agreement</a>.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="basic-reqts">
+    Basic Requirements
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  To participate, your apps must be designed for the K-12 market. The basic
+  requirements that your apps must meet are:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Apps and the ads they contain must not collect personally identifiable
+      information, other than user credentials or data required to operate and
+      improve the app.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Apps must not use student data for purposes unrelated to its educational
+      function.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Apps must have a content rating of "Everyone" or "Low Maturity" (apps
+      with a "Medium Maturity" rating are allowed, if they have that rating
+      solely because they allow communication between students).
+    </p>
+  </li>
+
+  <li>
+    <p>
+      App content, including ads displayed by the app, must be consistent with
+      the app's maturity rating. The app must not display any "offensive"
+      content, as described in the <a href=
+      "http://play.google.com/about/developer-content-policy.html">Google Play
+      Developer Program Policies</a> and <a href=
+      "https://support.google.com/googleplay/android-developer/answer/188189">content-rating
+      guidelines</a>.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Apps must comply with the Children’s Online Privacy Protection Act and
+      all other applicable laws and regulations.
+    </p>
+  </li>
+</ul>
+
+<div class="headerLine">
+  <h1 id="monetizing-ads">
+    Monetizing and Ads
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-edu-monetize.png">
+</div>
+
+<p>
+  In-app purchase is currently not supported with Google Play for Education, so
+  a student device will block any transactions. To avoid confusion, be sure to
+  remove any in-app purchase buttons and related UI elements from your apps.
+  We’re investigating additional purchase mechanisms to enable more flexible
+  pricing models for developers and schools.
+</p>
+
+<p>
+  If your apps are priced In Google Play for Education, you must allow Google
+  Play to offer teachers limited free trials before purchase (you provide this
+  through business terms only, no development work is needed.)
+</p>
+
+<p>
+  You can only choose not to remove in-app purchasing from your apps where all
+  content and services are sold through Google Play for Education using In-app
+  Billing. If you choose not to remove In-app Billing features, ensure that:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Users can access your apps’ core functionality for a classroom setting
+      without an in-app purchase.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      In-app purchases are clearly identifiable in your UI.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      You declare the use of in-app purchases at <a href=
+      "{@docRoot}distribute/googleplay/edu/start.html#publish">opt-in</a>.
+    </p>
+  </li>
+</ul>
+
+<p>
+  For each app that you publish, you can set a single price that applies to
+  both Google Play and Google Play for Education. You can’t set a different
+  price for a given app (based on a single package name) in Google Play for
+  Education.
+</p>
+
+<p>
+  If your apps display ads, you should disable the display of ads if possible,
+  or ensure that:
+</p>
+
+<ul>
+  <li>Ads are not distracting for students or teachers (this includes
+  Flash-based ads, video ads, and ads that flash or move)
+  </li>
+
+  <li>Interstitial ads are not served in the app
+  </li>
+
+  <li>Ad walls do not appear in the app UI
+  </li>
+
+  <li>Ads do not occupy a significant portion of the screen
+  </li>
+
+  <li>Ads content does not exceed the maturity rating of the app.
+  </li>
+
+  <li>
+    <p>
+      You declare the use of ads at <a href=
+      "{@docRoot}distribute/googleplay/edu/start.html#publish">opt-in</a>.
+    </p>
+  </li>
+</ul>
+
+<div class="headerLine">
+  <h1 id="e-value">
+    Educational Value
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-e-value.png" class="border-img">
+</div>
+
+<p>
+  Apps submitted to Google Play for Education will be evaluated by a
+  third-party educator network, which will review them based on alignment with
+  <a href="http://www.corestandards.org/">Common Core Standards</a> and other
+  educational considerations. This will help make your content more
+  discoverable for teachers and administrators as they browse by grade level,
+  subject, core curriculum, and other parameters.
+</p>
+
+<p>
+  Apps with highest educational value will have these characteristics:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Designed for use in K-12 classrooms.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Aligned with a common core standard or support common-core learning.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Simple, easy to use, and intuitive for the grade levels the apps are
+      targeting. Apps are relatively easy to navigate without teacher guidance.
+      Not distracting or overwhelming to students.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Enjoyable and interactive. Apps are engaging to students and lets them
+      control their experience.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Versatile. Apps have features that make them useful for more than one
+      classroom function or lesson throughout the school year.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Supports the "4Cs":
+    </p>
+
+    <ul>
+      <li>
+        <p>
+          <em>Creativity</em> &mdash; Allows students to create in order to
+          express understanding of the learning objectives, and try new
+          approaches, innovation, and invention to get things done.
+        </p>
+      </li>
+
+      <li>
+        <p>
+          <em>Critical thinking</em> &mdash; Allows students to look at
+          problems in a new way, linking learning across subjects and
+          disciplines.
+        </p>
+      </li>
+
+      <li>
+        <p>
+          <em>Collaboration</em> &mdash; Allows students and (if appropriate)
+          educators to work together to reach a goal.
+        </p>
+      </li>
+
+      <li>
+        <p>
+          <em>Communication</em> &mdash; Allows students to comprehend,
+          critique and share thoughts, questions, ideas, and solutions.
+        </p>
+      </li>
+    </ul>
+  </li>
+</ul>
+
+<p>
+  As you design and develop your apps, make sure they offer high educational
+  value by addressing as many of these characteristics as possible.
+</p>
+
+<div class="headerLine">
+  <h1 id="quality">
+    App Quality
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-edu-quality.png">
+</div>
+
+<p>
+  Your apps should be designed to perform well and look great on Android
+  tablets, and they should offer the best user experience possible.
+</p>
+
+<p>
+  High quality apps are engaging, intuitive, and offer compelling content.
+  Google Play for Education will highlight high-quality apps for easy discovery
+  in the store. Here are some recommendations for making your app easy for
+  students and teachers to enjoy:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Meet the Core Quality Guidelines:
+    </p>
+
+    <ul>
+      <li>
+        <p>
+          Follow <a href="{@docRoot}design/index.html">Android Design
+          Guidelines</a>. Pay special attention to the sections on <a href=
+          "{@docRoot}design/patterns/actionbar.html">Action Bar</a>, <a href=
+          "{@docRoot}design/patterns/navigation.html">Navigation</a>, and
+          <a href="{@docRoot}design/patterns/pure-android.html">Pure
+          Android</a>.
+        </p>
+      </li>
+
+      <li>
+        <p>
+          Test your apps against the <a href=
+          "{@docRoot}distribute/essentials/quality/core.html">Core Quality
+          Guidelines</a>.
+        </p>
+      </li>
+    </ul>
+  </li>
+
+  <li>
+    <p>
+      Meet the Tablet App Quality guidelines:
+    </p>
+
+    <ul>
+      <li>
+        <p>
+          Follow our best practices for tablet app development.
+        </p>
+      </li>
+
+      <li>
+        <p>
+          Review the <a href=
+          "{@docRoot}distribute/essentials/quality/tablets.html">Tablet App
+          Quality</a> guidelines and <a href=
+          "http://android-developers.blogspot.com/2012/11/designing-for-tablets-were-here-to-help.html">
+          blog post on designing for tablets.</a>
+        </p>
+
+        <ul>
+          <li>Check your Optimization Tips in the <a href=
+          "https://play.google.com/apps/publish/">Developer Console</a> (if
+          you've already uploaded your apps.)
+          </li>
+        </ul>
+      </li>
+
+      <li>
+        <p>
+          Strive for simplicity and highest usability for students:
+        </p>
+
+        <ul>
+          <li>
+            <p>
+              Design your app so that teachers and students can use all the
+              capabilities of your app without having to sign-in to multiple
+              accounts and remember multiple passwords.
+            </p>
+          </li>
+
+          <li>
+            <p>
+              Every student or teacher using a Google Play for Education tablet
+              will already be signed in with a Google account on the device.
+              You can take advantage of that to provide a simple, seamless
+              sign-in experience in your app. A recommended approach is to use
+              <a href="{@docRoot}google/play-services/auth.html">Google OAuth 2
+              authorization</a> through Google Play Services.
+            </p>
+          </li>
+        </ul>
+      </li>
+    </ul>
+  </li>
+</ul>
+
+<div class="headerLine">
+  <h1 id="test-environment">
+    Test Environment
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  To test your app and assess it against the guidelines in this document, it's
+  recommended that you <a href=
+  "{@docRoot}distribute/essentials/quality/tablets.html#test-environment">set
+  up a test environment</a> that replicates the actual environment in which
+  students and teachers will run your app.
+</p>
+
+<h3>
+  Test conditions
+</h3>
+
+<p>
+  Make sure to test your apps under conditions that simulate those of schools.
+  For example, Google Play for Education lets administrators <a href=
+  "https://support.google.com/a/answer/182442?hl=en">control or disable certain
+  capabilities</a> for students, so it's good to test your app with those
+  capabilities disabled. Below are some conditions to test your apps for, to
+  ensure best results in the Google Play for Education environment:
+</p>
+
+<ul>
+  <li>
+    <p>
+      <em>Android version</em> &mdash; Test the apps on devices running Android
+      4.2. Google Play for Education devices will be running Android 4.2 or
+      higher (API level 17+).
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <em>Proxy server</em> &mdash; Test the apps in a network environment that
+      uses proxies. Many schools use proxies.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <em>No location services</em> &mdash; Test the apps to make sure they
+      work properly with location services disabled. Many schools will disable
+      location services for student devices.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <em>No In-app Billing</em> &mdash; Test the apps to make sure they work
+      properly without access to In-app Billing. In-app purchases are blocked
+      on Google Play for Education devices.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <em>No Bluetooth</em> &mdash; Test the apps to make sure they work
+      properly when Bluetooth is disabled. Many schools will disable Bluetooth
+      on student devices.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <em>No access to network</em> &mdash; Test the app to make sure it works
+      properly when the device cannot connect to the internet.
+    </p>
+  </li>
+</ul>
+
+<div class="headerLine">
+<h1>Related Resources</h1><hr>
+</div>
+
+<div class="dynamic-grid">
+<h3>FOR DEVELOPERS</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+    data-query="collection:distribute/essentials/eduessentials/developers"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x3,6x3,6x3"
+    data-maxResults="6"></div>
+
+<h3>FOR TEACHERS AND EDUCATORS</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+    data-query="collection:distribute/essentials/eduessentials/educators"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x3,6x3,6x3"
+    data-maxResults="3"></div>
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/essentials/index.jd b/docs/html/distribute/essentials/index.jd
new file mode 100644
index 0000000..ca5442a
--- /dev/null
+++ b/docs/html/distribute/essentials/index.jd
@@ -0,0 +1,34 @@
+page.title=Essentials for a Successful App
+meta.tags="landing, quality"
+page.tags="guidelines", "tablet", "quality"
+section.landing=true
+nonavpage=true
+
+@jd:body
+
+<p>
+  A focus on quality should be part of your entire app delivery process: from
+  initial concept through app and UI design, coding and testing and onto a
+  process of monitoring feedback and making improvement after launch.
+</p>
+
+<div class="dynamic-grid">
+<div class="resource-widget resource-flow-layout landing col-16"
+  data-query="collection:distribute/essentials"
+  data-cardSizes="6x6"
+  data-maxResults="6">
+</div>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-16"
+  data-query="type:blog+tag:quality"
+  data-cardSizes="6x3"
+  data-maxResults="3">
+</div>
+<div class="resource-widget resource-flow-layout col-16"
+  data-query="type:youtube+tag:appquality"
+  data-cardSizes="6x3"
+  data-maxResults="3">
+</div>
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/essentials/optimizing-your-app.jd b/docs/html/distribute/essentials/optimizing-your-app.jd
new file mode 100644
index 0000000..3fe91b28
--- /dev/null
+++ b/docs/html/distribute/essentials/optimizing-your-app.jd
@@ -0,0 +1,517 @@
+page.title=Optimize Your App
+page.metaDescription=A look at how to get the most visibility and the highest ratings possible for your app or game. Optimizing the quality of your apps is a key strategy.
+page.image=/distribute/images/gp-optimize-card.jpg
+
+@jd:body
+
+<div id="qv-wrapper">           
+  <div id="qv">
+    <h2>Strategies</h2>
+    <ol>
+      <li><a href="#listen-to-your-users">Listen to Your Users</a></li>
+      <li><a href="#measuring-analyzing-responding">Measuring, Analyzing, and Responding to User Behavior</a></li>
+      <li><a href="#improve-stability">Improve Stability and Eliminate Bugs</a></li>
+      <li><a href="#improve-ui">Improve UI Responsiveness</a></li>
+      <li><a href="#improve-usability">Improve Usability</a></li>
+      <li><a href="#professional-appearance">Professional Appearance and Aesthetics</a></li>
+      <li><a href="#deliver-features">Deliver the Right Set of Features</a></li>
+      <li><a href="#integrate">Integrate with the System and Third-Party Apps</a></li>
+      <li><a href="#related-resources">Related Resources</a></li>
+    </ol>
+  </div>
+</div>
+
+<div class="top-right-float">
+  <img src="{@docRoot}images/gp-optimize.png" class="quality-top-image" style=
+  "width:239px;padding-left:1.5em;">
+</div>
+
+<p>
+  With thousands of new apps being published in Google Play every week, it's
+  important to look for ways to get the most visibility and the highest ratings
+  possible. Optimizing the quality of your apps is a key strategy.
+</p>
+
+<p>
+  A higher quality app can translate to higher user ratings, generally better
+  rankings, more downloads, and higher retention (longer install periods).
+  High-quality apps are much more likely to get positive publicity, such as
+  being featured in Google Play or generating social media buzz.
+</p>
+
+<p>
+  The quality of your apps is something you should consider addressing both
+  before and after launch. Gaining users after the launch of a poor quality app
+  can be hard and recovering costly. On the other hand, maintaining the ranking
+  of high-quality apps is made easier if there are continual improvements, a
+  practice that also fuels the impression-install-ranking cycle.
+</p>
+
+<p>
+  On this page you can find advice on a number of ways in which you can drive
+  improvements to your apps’ quality.
+</p>
+
+<div class="headerLine">
+  <h1 id="listen-to-your-users">
+    Listen to Your Users
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-optimizing-chat-bubbles.png">
+</div>
+
+<p>
+  Listening and hearing your users can be one of your best tools for success.
+  Start listening to your users before launching your apps and continue to
+  listen after launch.
+</p>
+
+<h3>
+  <strong>Listening before you launch</strong>
+</h3>
+
+<p>
+  You can listen to your users during the development of your apps. This
+  process can start with focus groups to review app features, continue into
+  user experience workshops, and onto alpha and beta releases. Listening at
+  these stages has two main benefits: <strong>you’ll build apps with features
+  users want</strong> and <strong>any issues they identify will be cheaper and
+  quicker to fix</strong> than they would be once the app is launched fully.
+</p>
+
+<p>
+  If the practicalities of focus groups and user workshops seem excessive in
+  relation to the development of a particular app, drawing on the feedback of
+  colleagues, friends, and family can be much more useful than getting no
+  feedback at all.
+</p>
+
+<p>
+  It's crucial to conduct user testing before releasing your apps to Google
+  Play. If you can only engage with colleagues, friends, and family you’re
+  already making a good start. For more extensive testing consider a public
+  alpha/beta test or creating your own trusted tester program. You can manage
+  app distribution yourself through email or your own website, or you can use
+  <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">beta-testing</a>
+  and <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#staged-rollouts">staged
+  rollouts</a> in conjunction with <a href=
+  "http://www.google.com/+/business/">Google+</a> or <a href=
+  "https://groups.google.com/forum/#!overview">Google Groups</a> to distribute
+  software and gather feedback to a subset of users. <strong>Users on alpha or
+  beta versions cannot leave reviews or ratings</strong>, so there is
+  <strong>no risk to your rating</strong> on Google Play.
+</p>
+
+<p>
+  Unless you have to, don’t restrict the users you involve in these stages in
+  the information they can share through their social networks and blogs -
+  users engaged in these early stages (and listened too) are likely to be great
+  ambassadors for your apps and will help create great social media buzz.
+</p>
+
+<h3>
+  Listening after launch
+</h3>
+
+<p>
+  Once you have launched, the most obvious way to listen to users is by reading
+  and addressing comments on Google Play. Although the comments aren't always
+  productive or constructive, some will provide valuable insight on aspects of
+  your apps. It's important to remember that users have the opportunity to
+  change their ratings and comments as much as they like.
+</p>
+
+<p>
+  There are more interactive ways you can reach users, help them address their
+  concerns, and gather more detailed feedback: by setting up support and
+  discussion forums. There are some great support tools out there that can put
+  you in touch with your users directly, from forums such as <a href=
+  "http://groups.google.com/">Google Groups</a> to comprehensive customer
+  support products and tools like UserVoice. Once you get set up with such a
+  tool, make sure to fill in the support link in your Google Play product
+  details page — users do click through to these.
+</p>
+
+<p>
+  Also don’t forget to use the <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">beta-testing</a>
+  and <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#staged-rollouts">staged
+  rollout</a> features of Google Play with app updates.
+</p>
+
+<div class="headerLine" id="measuring-analyzing-responding">
+  <h1>
+    Measuring, Analyzing, and Responding to User Behavior
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-optimize-analytics.png">
+</div>
+
+<p>
+  One of the best ways to spot issues to resolve is by measuring user behavior.
+  Optimizing your app becomes much easier when you analyze performance before
+  and after you launch. Drop off points, low ratings, and high percent of
+  uninstalls can be indicative that there’s a problem. Measuring and responding
+  to user-related metrics such as download sources, retention rates, and in-app
+  behavior regularly is critical to keeping and bringing back your hard earned
+  user base.
+</p>
+
+<p>
+  You can get data from tools in Google Play or third-parties to analyze user
+  behavior. You can identify details such as:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Where installs are coming from.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      The types of users you are acquiring.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      What is causing user churn and how to reduce it.
+    </p>
+  </li>
+</ul>
+
+<h3>
+  Statistics for analyzing installs and ratings
+</h3>
+
+<p>
+  Once you’ve published your app, Google Play makes it easy to see how it’s
+  doing. The <a href="https://play.google.com/apps/publish/">Developer
+  Console</a> gives you access to a variety of anonymized statistics and custom
+  charts that show you the app's installation performance and ratings.
+</p>
+
+<p>
+  You can view data and charts for active, daily, and total installs per unique
+  devices or users, as well as upgrades and uninstalls. You can also view the
+  app's daily average user rating and its cumulative user rating. To help you
+  analyze the data, you can view install and ratings statistics across a
+  variety of different dimensions such as Android version, device, country, app
+  version, and carrier.
+</p>
+
+<div>
+  <img class="border-img" src="{@docRoot}images/gp-dc-stats-mini.png">
+</div>
+
+<p>
+  You can see your app statistics on timeline charts, for all metrics and
+  dimensions. At a glance, the charts highlight your app’s installation and
+  ratings peaks and longer-term trends, which you can correlate to promotions,
+  app improvements, or other factors. You can even focus in on data inside a
+  dimension by highlighting specific data points (such as individual platform
+  versions or languages) on the timeline.
+</p>
+
+<p>
+  You can download all of your installation data as a CSV file for viewing in
+  the business program of your choice.
+</p>
+
+<h3>
+  Tracking and analyzing Marketing campaigns
+</h3>
+
+<p>
+  While you should consider monitoring user behavior data as a part of your
+  normal activities, it’s particularly important when you’re running any form
+  of marketing campaign, to make sure you’re getting the right users at the
+  lowest cost possible.
+</p>
+
+<p>
+  One way to track your marketing campaigns is to link <a href=
+  "http://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html">
+  Google Analytics with your Google Play account</a> to analyze activity from
+  source to install.
+</p>
+
+<div style="margin-top:1em;">
+  <img src="{@docRoot}images/gp-optimizing-image-4.jpg" class="border-img">
+</div>
+
+<p>
+  You can also use any of the variety of tools on the market to help track your
+marketing success and improvement ROI if you wish. There are also third parties
+who can help automate, measure, and optimize your mobile marketing.
+</p>
+
+<div class="headerLine">
+  <h1 id="improve-stability">
+    Improve Stability and Eliminate Bugs
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  There are many tools and techniques for testing and profiling your app on
+  different devices and user scenarios.
+</p>
+
+<p>
+  One noteworthy and yet relatively underused tool for catching stability
+  issues such as crashes is the <a href=
+  "{@docRoot}tools/help/monkey.html">UI/Application Exerciser Monkey</a>
+  (Monkey). Monkey will send random UI events to your app's activities,
+  allowing you to trigger user flows that can uncover stability problems.
+</p>
+
+<p>
+  Also, with the Google error-reporting features built into most Android
+  devices, users have a way to report application crashes to you. The error
+  reports show up in aggregate in the Google Play Developer Console. Make sure
+  to read these reports often and act on them appropriately.
+</p>
+
+<p>
+  Last, keep an external bug and feature request tracker and let users know how
+  to find it. This will enable them to engage with the app at a closer level,
+  by following features and bugs that affect them. User frustration with app
+  problems can be effectively managed with diligent issue tracking and
+  communication. Several community support tools offer issue tracking features,
+  and if your project is open source, most popular repository hosting sites
+  offer this as well.
+</p>
+
+<div class="headerLine">
+  <h1 id="improve-ui">
+    Improve UI Responsiveness
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-optimize-speed.png">
+</div>
+
+<p>
+  One sure-fire way to lose your users is to give them a slow, unresponsive UI.
+  Research has shown that <a href=
+  "http://googleresearch.blogspot.com/2009/06/speed-matters.html">speed
+  matters</a>, for any interface, on mobile, web, or desktop. In fact, the
+  importance of speed is amplified on mobile devices since users often need
+  their information on the go and in a hurry.
+</p>
+
+<p>
+  You can improve your apps' UI responsiveness by moving long-running
+  operations off the main thread to worker threads. Android offers built-in
+  debugging facilities such as StrictMode for analyzing your app's performance
+  and activities on the main thread. See more recommendations in <a href=
+  "http://www.youtube.com/watch?v=c4znvD-7VDA">Writing Zippy Android Apps</a>,
+  a developer session from Google I/O 2010.
+</p>
+
+<p>
+  A great way to improve UI performance is to minimize the complexity of your
+  layouts. If you open up <a href=
+  "{@docRoot}tools/help/hierarchy-viewer.html">hierarchyviewer</a> and see that
+  your layouts are more than 5 levels deep, it may be time to simplify your
+  layout. Consider refactoring those deeply nested <a href=
+  "{@docRoot}reference/android/widget/LinearLayout.html">LinearLayouts</a> into
+  <a href="{@docRoot}guide/topics/ui/layout/relative.html">RelativeLayout</a>.
+  The impact of View objects is cumulative — each one costs about 1 to 2 KB of
+  memory, so large view hierarchies can be a recipe for disaster, causing
+  frequent VM garbage collection passes which block the main (UI) thread. You
+  can learn more from the Google I/O session <a href=
+  "http://www.youtube.com/watch?v=wDBM6wVEO70">World of ListView</a>.
+</p>
+
+<p>
+  Lastly, as pointed out in the blog post <a href=
+  "http://android-developers.blogspot.com/2010/10/traceview-war-story.html">Traceview
+  War Story</a>, tools like <a href=
+  "{@docRoot}tools/help/traceview.html">traceview and ddms</a> can be your best
+  friends in improving your app by profiling method calls and monitoring VM
+  memory allocations, respectively.
+</p>
+
+<div class="headerLine">
+  <h1 id="improve-usability">
+    Improve Usability
+  </h1>
+
+  <hr>
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <p>
+      <strong>Tip:</strong> As you’re designing or evaluating your app's UI,
+      make sure to read and become familiar with the <a href=
+      "{@docRoot}design/index.html">Android Design</a> guidelines. Included are
+      many examples of UI patterns, styles, and building blocks, as well as
+      tools for the design process.
+    </p>
+  </div>
+</div>
+
+<p>
+  In usability and in app design too, you should listen carefully to your
+  users. Ask a handful of real Android device users (friends, family, etc.) to
+  try out your app and observe them as they interact with it. Look for cases
+  where they get confused, are unsure of how to proceed, or are surprised by
+  certain behaviors. Minimize these cases by rethinking some of the
+  interactions in your app. See the <a href=
+  "{@docRoot}design/patterns/index.html">Patterns section</a> for tips to
+  improve your design.
+</p>
+
+<p>
+  In the same vein, two problems that can plague some Android user interfaces
+  are small tap targets and excessively small font sizes. These are generally
+  easy to fix and can make a big impact on usability and user satisfaction. As
+  a general rule, optimize for ease of use and legibility, while minimizing, or
+  at least carefully balancing, information density.
+</p>
+
+<p>
+  Another way to incrementally improve usability, based on real-world data, is
+  to implement <a href=
+  "http://code.google.com/mobile/analytics/docs/">Analytics</a> throughout your
+  app to log the use of particular sections. Consider demoting infrequently
+  used sections to the overflow menu in the <a href=
+  "{@docRoot}design/patterns/actionbar.html">Action bar</a>, or removing them
+  altogether. For often-used sections and UI elements, make sure they're
+  immediately obvious and easily accessible in your app's UI so that users can
+  get to them quickly.
+</p>
+
+<div class="headerLine">
+  <h1 id="professional-appearance">
+    Professional Appearance and Aesthetics
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  There's no substitute for a real user interface designer — ideally one who's
+  well-versed in mobile and Android, and handy with both interaction and visual
+  design. One popular venue to post openings for designers is <a href=
+  "http://jobs.smashingmagazine.com/">jobs.smashingmagazine.com</a>, and
+  leveraging social networks can also surface great talent.
+</p>
+
+<p>
+  If you don't have the luxury of working with a UI designer, there are some
+  ways in which you can improve your app's appearance yourself. You can use
+  Adobe Photoshop, Adobe Fireworks, GIMP, Inkscape or other image editing
+  tools. Mastering the art of the pixel in these apps takes time, but honing
+  this skill can help build polish across your interface designs. Also, master
+  the resources framework by studying the framework UI assets and layouts and
+  reading through the <a href=
+  "{@docRoot}guide/topics/resources/index.html">resources documentation</a>.
+  Techniques such as 9-patches and resource directory qualifiers are somewhat
+  unique to Android, and are crucial in building flexible yet aesthetic UIs.
+</p>
+
+<p>
+  Before you get too far in designing your app and writing the code, make sure
+  to visit the <a href="{@docRoot}design/index.html">Android Design section</a>
+  and learn about the vision, the building blocks, and the tools of designing
+  beautiful and inspiring user interfaces.
+</p>
+
+<div class="headerLine">
+  <h1 id="deliver-features">
+    Deliver the Right Set of Features
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Having the <em>right</em> set of features in your app is important. It's
+  often easy to fall into the trap of feature-creep, building as much
+  functionality into your app as possible. Providing instant gratification by
+  immediately showing the most important or relevant information is crucial on
+  mobile devices. Providing too much information can be as frustrating (or even
+  more so) than not providing enough of it.
+</p>
+
+<p>
+  Again, listen to your users by collecting and responding to feature requests.
+  Be careful, though, to take feature requests with a grain of salt. Requests
+  can be very useful in aggregate, to get a sense of what kinds of
+  functionality you should be working on, but not every feature request needs
+  to be implemented.
+</p>
+
+<div class="headerLine">
+  <h1 id="integrate">
+    Integrate with the System and Third-Party apps
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  A great way to deliver a delightful user experience is to integrate tightly
+  with the operating system. Features like <a href=
+  "{@docRoot}guide/topics/appwidgets/index.html">Home screen widgets</a>,
+  <a href="{@docRoot}design/patterns/notifications.html">rich
+  notifications</a>, <a href="{@docRoot}guide/topics/search/index.html">global
+  search integration</a>, and <a href=
+  "{@docRoot}reference/android/widget/QuickContactBadge.html">Quick
+  Contacts</a> are fairly low-hanging fruit in this regard.
+</p>
+
+<p>
+  For some app categories, basic features like home screen widgets are
+  expected. Not including them is a sure-fire way to tarnish an otherwise
+  positive user experience. Some apps can achieve even tighter OS integration
+  with Android's contacts, accounts, and sync APIs.
+</p>
+
+<p>
+  Third-party integrations can provide even more user delight and give the user
+  a feeling of device cohesiveness. It's also a really nice way of adding
+  functionality to your app without writing any extra code (by leveraging other
+  apps' functionality). For example, if you're creating a camera app, you can
+  allow users to edit their photos in another app before saving them to their
+  collection, if they have that third-party application installed. More
+  information on this subject is available in the Android Training class
+  <a href="{@docRoot}training/basics/intents/index.html">Interacting with Other
+  Apps</a>.
+</p>
+
+<div class="headerLine">
+<h1 id="related-resources">Related Resources</h1><hr>
+</div>
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/optimizing, tag:addia"
+  data-sortOrder="-timestamp"
+  data-cardSizes="6x3"
+  data-maxResults="3"></div>
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="tag:adia"
+  data-sortOrder="-timestamp"
+  data-cardSizes="6x3"
+  data-maxResults="3"></div>
+
diff --git a/docs/html/distribute/essentials/quality/core.jd b/docs/html/distribute/essentials/quality/core.jd
new file mode 100644
index 0000000..558b030
--- /dev/null
+++ b/docs/html/distribute/essentials/quality/core.jd
@@ -0,0 +1,1170 @@
+page.title=Core App Quality
+page.metaDescription=App quality directly influences the long-term success of your app—in terms of installs, user rating and reviews, engagement, and user retention.
+page.image=/distribute/images/core-quality-guidelines.jpg
+@jd:body
+
+<div id="qv-wrapper"><div id="qv">
+<h2>Quality Criteria</h2>
+  <ol>
+    <li><a href="#ux">Design and Interaction</a></li>
+        <li><a href="#fn">Functionality</a></li>
+        <li><a href="#ps">Performance and Stability</a></li>
+        <li><a href="#listing">Google Play</a></li>
+
+  </ol>
+  
+  <h2>Testing</h2>
+  <ol>
+    <li><a href="#test-environment">Setting Up a Test Environment</a></li>
+        <li><a href="#tests">Test Procedures</a></li>
+        </ol>
+
+  <h2>You Should Also Read</h2>
+  <ol>
+    <li><a href="{@docRoot}distribute/essentials/quality/tablets.html">Tablet App Quality</a></li>
+        <li><a href="{@docRoot}distribute/essentials/optimizing-your-app.html">Optimize Your App</a></li>
+  </ol>
+  
+
+</div>
+</div>
+
+<div class="top-right-float">
+  <img src="{@docRoot}images/gp-core-quality.png" style="margin-left: 20px;">
+</div>
+
+<p>
+  Android users expect high-quality apps. App quality directly influences the
+  long-term success of your app—in terms of installs, user rating and reviews,
+  engagement, and user retention.
+</p>
+
+<p>
+  This document helps you assess basic aspects of quality in your app through a
+  compact set of core app quality criteria and associated tests. All Android
+  apps should meet these criteria.
+</p>
+
+<p>
+  Before publishing your apps, test them against these criteria to ensure that
+  they function well on many devices, meets Android standards for navigation
+  and design, and are prepared for promotional opportunities in the Google Play
+  store. Your testing will go well beyond what's described here—the purpose of
+  this document is to specify the essential quality characteristics all apps
+  should display, so that you can cover them in your test plans.
+</p>
+
+<p>
+  If you're creating apps for tablets and or Google Play for Education there
+  are additional quality criteria you should consider, which are defined in the
+  <a href="{@docRoot}distribute/essentials/quality/tablets.html">Tablet App
+  Quality</a> guidelines and <a href=
+  "{@docRoot}distribute/essentials/gpfe-guidelines.html">Education
+  Guidelines</a>.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="ux">
+  Visual Design and User Interaction
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  These criteria ensure that your app provides standard Android visual design
+  and interaction patterns where appropriate, for a consistent and intuitive
+  user experience.
+</p>
+
+<table>
+  <tr>
+    <th style="width:2px;">
+      Area
+    </th>
+    <th style="width:54px;">
+      ID
+    </th>
+    
+
+    <th>
+      Description
+    </th>
+    <th style="width:54px;">
+      Tests
+    </th>
+  </tr>
+  <tr id="UX-B1">
+  <td>Standard design</td>
+  <td>
+    UX-B1
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App follows <a href="{@docRoot}design/index.html">Android Design</a>
+    guidelines and uses common <a href=
+    "{@docRoot}design/patterns/index.html">UI patterns and icons</a>:
+    </p>
+
+    <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+    <li>App does not redefine the expected function of a system icon (such
+    as the Back button).
+    </li>
+
+    <li>App does not replace a system icon with a completely different icon
+    if it triggers the standard UI behavior.
+    </li>
+
+    <li>If the app provides a customized version of a standard system icon,
+    the icon strongly resembles the system icon and triggers the standard
+    system behavior.
+    </li>
+
+    <li>App does not redefine or misuse Android UI patterns, such that
+    icons or behaviors could be misleading or confusing to users.
+    </li>
+    </ol>
+  </td>
+  <td>
+    <a href="#core">CR-all</a>
+  </td>
+  </tr>
+
+  <tr>
+  <td rowspan="3">
+    Navigation
+  </td>
+  <td id="UX-N1">
+    UX-N1
+  </td>
+  <td>
+    <p>
+    App supports standard system <a href=
+    "{@docRoot}design/patterns/navigation.html">Back button navigation</a>
+    and does not make use of any custom, on-screen "Back button" prompts.
+    </p>
+  </td>
+  <td>
+    <a href="#core">CR-3</a>
+  </td>
+  </tr>
+
+  <tr>
+  <td id="UX-N2">
+    UX-N2
+  </td>
+  <td>
+    <p>
+    All dialogs are dismissable using the Back button.
+    </p>
+  </td>
+  <td>
+    <a href="#core">CR-3</a>
+  </td>
+  </tr>
+
+  <tr id="UX-N3">
+  <td>
+    UX-N3
+  </td>
+  <td>
+    Pressing the Home button at any point navigates to the Home screen of the
+    device.
+  </td>
+  <td>
+    <a href="#core">CR-1</a>
+  </td>
+  </tr>
+
+  <tr id="UX-S1">
+  <td rowspan="2">
+    Notifications
+  </td>
+  <td>
+    UX-S1
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    Notifications follow Android Design <a href=
+    "{@docRoot}design/patterns/notifications.html">guidelines</a>. In
+    particular:
+    </p>
+
+    <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+    <li>Multiple notifications are stacked into a single notification
+    object, where possible.
+    </li>
+
+    <li>Notifications are persistent only if related to ongoing events
+    (such as music playback or a phone call).
+    </li>
+
+    <li>Notifications do not contain advertising or content unrelated to
+    the core function of the app, unless the user has opted in.
+    </li>
+    </ol>
+  </td>
+  <td>
+    <a href="#core">CR-11</a>
+  </td>
+  </tr>
+
+  <tr id="UX-S2">
+  <td>
+    UX-S2
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App uses notifications only to:
+    </p>
+
+    <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+    <li>Indicate a change in context relating to the user personally (such
+    as an incoming message), or
+    </li>
+
+    <li>Expose information/controls relating to an ongoing event (such as
+    music playback or a phone call).
+    </li>
+    </ol>
+  </td>
+  <td>
+    <a href="#core">CR-11</a>
+  </td>
+  </tr>
+</table>
+
+<h3>
+  Related Resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/essentials/corequalityguidelines/visualdesign"
+data-sortorder="-timestamp" data-cardsizes="9x3,9x3,6x3,6x3,6x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="fn">
+  Functionality
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  These criteria ensure that your app provides expected functional behavior,
+  with the appropriate level of permissions.
+</p>
+
+<table>
+  <tr>
+  <th style="width:2px;">
+    Area
+  </th>
+  <th style="width:54px;">
+    ID
+  </th>
+  <th>
+    Description
+  </th>
+  <th style="width:54px;">
+    Tests
+  </th>
+  </tr>
+
+  <tr id="FN-P1">
+  <td rowspan="2">
+    Permissions
+  </td>
+  <td>
+    FN-P1
+  </td>
+  <td>
+    App requests only the <em>absolute minimum</em> permissions that it needs
+    to support core functionality.
+  </td>
+  <td rowspan="2">
+    <a href="#core">CR-11</a>
+  </td>
+  </tr>
+
+  <tr id="FN-P2">
+  <td>
+    FN-P2
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App does not request permissions to access sensitive data (such as
+    Contacts or the System Log) or services that can cost the user money
+    (such as the Dialer or SMS), unless related to a core capability of the
+    app.
+    </p>
+  </td>
+  </tr>
+
+  <tr id="FN-L1">
+  <td>
+    Install location
+  </td>
+  <td>
+    FN-L1
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App functions normally when installed on SD card (if supported by app).
+    </p>
+
+    <p style="margin-bottom:.25em;">
+    Supporting installation to SD card is recommended for most large apps
+    (10MB+). See the <a href=
+    "{@docRoot}guide/topics/data/install-location.html">App Install
+    Location</a> developer guide for information about which types of apps
+    should support installation to SD card.
+    </p>
+  </td>
+  <td>
+    <a href="#SD-1">SD-1</a>
+  </td>
+  </tr>
+
+  <tr id="FN-A1">
+  <td rowspan="4">
+    Audio
+  </td>
+  <td>
+    FN-A1
+  </td>
+  <td>
+    Audio does not play when the screen is off, unless this is a core feature
+    (for example, the app is a music player).
+  </td>
+  <td>
+    <a href="#core">CR-7</a>
+  </td>
+  </tr>
+
+  <tr id="FN-A2">
+  <td>
+    FN-A2
+  </td>
+  <td>
+    Audio does not <a href=
+    "http://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html">
+    play behind the lock screen</a>, unless this is a core feature.
+  </td>
+  <td>
+    <a href="#core">CR-8</a>
+  </td>
+  </tr>
+
+  <tr id="FN-A3">
+  <td>
+    FN-A3
+  </td>
+  <td>
+    Audio does not play on the home screen or over another app, unless this
+    is a core feature.
+  </td>
+  <td>
+    <a href="#core">CR-1,<br>
+    CR-2</a>
+  </td>
+  </tr>
+
+  <tr id="FN-A4">
+  <td>
+    FN-A4
+  </td>
+  <td>
+    Audio resumes when the app returns to the foreground, or indicates to the
+    user that playback is in a paused state.
+  </td>
+  <td>
+    <a href="#core">CR-1, CR-8</a>
+  </td>
+  </tr>
+
+  <tr id="FN-U1">
+  <td rowspan="3">
+    UI and Graphics
+  </td>
+  <td>
+    FN-U1
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App supports both landscape and portrait orientations (if possible).
+    </p>
+
+    <p style="margin-bottom:.25em;">
+    Orientations expose largely the same features and actions and preserve
+    functional parity. Minor changes in content or views are acceptable.
+    </p>
+  </td>
+  <td>
+    <a href="#core">CR-5</a>
+  </td>
+  </tr>
+
+  <tr id="FN-U2">
+  <td>
+    FN-U2
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App uses the whole screen in both orientations and does not letterbox
+    to account for orientation changes.
+    </p>
+
+    <p style="margin-bottom:.25em;">
+    Minor letterboxing to compensate for small variations in screen
+    geometry is acceptable.
+    </p>
+  </td>
+  <td>
+    <a href="#core">CR-5</a>
+  </td>
+  </tr>
+
+  <tr id="FN-U3">
+  <td>
+    FN-U3
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App correctly handles rapid transitions between display orientations
+    without rendering problems.
+    </p>
+  </td>
+  <td>
+    <a href="#core">CR-5</a>
+  </td>
+  </tr>
+
+  <tr id="FN-S1">
+  <td rowspan="2">
+    User/app state
+  </td>
+  <td>
+    FN-S1
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App should not leave any services running when the app is in the
+    background, unless related to a core capability of the app.
+    </p>
+
+    <p style="margin-bottom:.25em;">
+    For example, the app should not leave services running to maintain a
+    network connection for notifications, to maintain a Bluetooth
+    connection, or to keep the GPS powered-on.
+    </p>
+  </td>
+  <td>
+    <a href="#core">CR-6</a>
+  </td>
+  </tr>
+
+  <tr id="FN-S2">
+  <td>
+    FN-S2
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App correctly preserves and restores user or app state.
+    </p>
+
+    <p style="margin-bottom:.25em;">
+    App preserves user or app state when leaving the foreground and
+    prevents accidental data loss due to back-navigation and other state
+    changes. When returning to the foreground, the app must restore the
+    preserved state and any significant stateful transaction that was
+    pending, such as changes to editable fields, game progress, menus,
+    videos, and other sections of the app or game.
+    </p>
+
+    <ol style="margin-bottom:.25em;list-style-type:lower-alpha">
+    <li>When the app is resumed from the Recents app switcher, the app
+    returns the user to the exact state in which it was last used.
+    </li>
+
+    <li>When the app is resumed after the device wakes from sleep (locked)
+    state, the app returns the user to the exact state in which it was last
+    used.
+    </li>
+
+    <li>When the app is relaunched from Home or All Apps, the app restores
+    the app state as closely as possible to the previous state.
+    </li>
+
+    <li>On Back keypresses, the app gives the user the option of saving any
+    app or user state that would otherwise be lost on back-navigation.
+    </li>
+    </ol>
+  </td>
+  <td>
+    <a href="#core">CR-1, CR-3, CR-5</a>
+  </td>
+  </tr>
+</table>
+
+<h3>
+  Related Resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/essentials/corequalityguidelines/functionality"
+data-sortorder="-timestamp" data-cardsizes="6x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="ps">
+  Performance and Stability
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  These criteria ensure that apps provide the performance, stability, and
+  responsiveness expected by users.
+</p>
+
+<table>
+  <tr>
+  <th style="width:2px;">
+    Area
+  </th>
+  <th style="width:54px;">
+    ID
+  </th>
+  <th>
+    Description
+  </th>
+  <th style="width:54px;">
+    Tests
+  </th>
+  </tr>
+
+  <tr id="PS-S1">
+  <td>
+    Stability
+  </td>
+  <td>
+    PS-S1
+  </td>
+  <td>
+    App does not crash, force close, freeze, or otherwise function abnormally
+    on any targeted device.
+  </td>
+  <td>
+    <a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>, <a href=
+    "#HA-1">HA-1</a>
+  </td>
+  </tr>
+
+  <tr id="PS-P1">
+  <td rowspan="2">
+    Performance
+  </td>
+  <td>
+    PS-P1
+  </td>
+  <td>
+    App loads quickly or provides onscreen feedback to the user (a progress
+    indicator or similar cue) if the app takes longer than two seconds to
+    load.
+  </td>
+  <td>
+    <a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>
+  </td>
+  </tr>
+
+  <tr id="PS-P2">
+  <td>
+    PS-P2
+  </td>
+  <td>
+    With StrictMode enabled (see <a href="#strictmode">StrictMode
+    Testing</a>, below), no red flashes (performance warnings from
+    StrictMode) are visible when exercising the app, including during game
+    play, animations and UI transitions, and any other part of the app.
+  </td>
+  <td>
+    <a href="#PM-1">PM-1</a>
+  </td>
+  </tr>
+
+  <tr id="PS-M1">
+  <td>
+    Media
+  </td>
+  <td>
+    PS-M1
+  </td>
+  <td>
+    Music and video playback is smooth, without crackle, stutter, or other
+    artifacts, during normal app usage and load.
+  </td>
+  <td>
+    <a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>, <a href=
+    "#HA-1">HA-1</a>
+  </td>
+  </tr>
+
+  <tr id="PS-V1">
+  <td rowspan="2">
+    Visual quality
+  </td>
+  <td>
+    PS-V1
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App displays graphics, text, images, and other UI elements without
+    noticeable distortion, blurring, or pixelation.
+    </p>
+
+    <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+    <li>App provides high-quality graphics for all targeted screen sizes
+    and form factors, including for <a href=
+    "{@docRoot}distribute/essentials/quality/tablet.html">larger-screen
+    devices such as tablets</a>.
+    </li>
+
+    <li>No aliasing at the edges of menus, buttons, and other UI elements
+    is visible.
+    </li>
+    </ol>
+  </td>
+  <td rowspan="2">
+    <a href="#core">CR-all</a>
+  </td>
+  </tr>
+
+  <tr id="PS-V2">
+  <td>
+    PS-V2
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App displays text and text blocks in an acceptable manner.
+    </p>
+
+    <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+    <li>Composition is acceptable in all supported form factors, including
+    for larger-screen devices such as tablets.
+    </li>
+
+    <li>No cut-off letters or words are visible.
+    </li>
+
+    <li>No improper word wraps within buttons or icons are visible.
+    </li>
+
+    <li>Sufficient spacing between text and surrounding elements.
+    </li>
+    </ol>
+  </td>
+  </tr>
+</table>
+
+<h3>
+  Related Resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/essentials/core/performance" data-sortorder="-timestamp"
+data-cardsizes="6x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="listing">
+  Google Play
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  These criteria ensure that your apps are ready to publish on Google Play.
+</p>
+
+<table>
+  <tr>
+  <th style="width:2px;">
+    Area
+  </th>
+  <th style="width:54px;">
+    ID
+  </th>
+  <th>
+    Description
+  </th>
+  <th style="width:54px;">
+    Tests
+  </th>
+  </tr>
+
+  <tr id="GP-P1">
+  <td rowspan="2">
+    Policies
+  </td>
+  <td>
+    GP-P1
+  </td>
+  <td>
+    App strictly adheres to the terms of the <a href=
+    "http://play.google.com/about/developer-content-policy.html">Google Play
+    Developer Content Policy</a> and does not offer inappropriate content,
+    does not use intellectual property or brand of others, and so on.
+  </td>
+  <td>
+    <a href="#gp">GP-all</a>
+  </td>
+  </tr>
+
+  <tr id="GP-P2">
+  <td>
+    GP-P2
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App maturity level is set appropriately, based on the <a href=
+    "http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=188189">
+    Content Rating Guidelines</a>.
+    </p>
+
+    <p style="margin-bottom:.25em;">
+    Especially, note that apps that request permission to use the device
+    location cannot be given the maturity level "Everyone".
+    </p>
+  </td>
+  <td>
+    <a href="#gp">GP-1</a>
+  </td>
+  </tr>
+
+  <tr id="GP-D1">
+  <td rowspan="3">
+    App&nbsp;Details Page
+  </td>
+  <td>
+    GP-D1
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App feature graphic follows the guidelines outlined in this <a href=
+    "http://android-developers.blogspot.com/2011/10/android-market-featured-image.html">
+    blog post</a>. Make sure that:
+    </p>
+
+    <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+    <li>The app listing includes a high-quality feature graphic.
+    </li>
+
+    <li>The feature graphic does not contain device images, screenshots, or
+    small text that will be illegible when scaled down and displayed on the
+    smallest screen size that your app is targeting.
+    </li>
+
+    <li>The feature graphic does not resemble an advertisement.
+    </li>
+    </ol>
+  </td>
+  <td>
+    <a href="#gp">GP-1, GP-2</a>
+  </td>
+  </tr>
+
+  <tr id="GP-D2">
+  <td>
+    GP-D2
+  </td>
+  <td>
+    App screenshots and videos do not show or reference non-Android devices.
+  </td>
+  <td rowspan="2">
+    <a href="#gp">GP-1</a>
+  </td>
+  </tr>
+
+  <tr id="GP-D3">
+  <td>
+    GP-D3
+  </td>
+  <td>
+    App screenshots or videos do not represent the content and experience of
+    your app in a misleading way.
+  </td>
+  </tr>
+
+  <tr id="GP-X1">
+  <td>
+    User Support
+  </td>
+  <td>
+    GP-X1
+  </td>
+  <td>
+    Common user-reported bugs in the Reviews tab of the Google Play page are
+    addressed if they are reproducible and occur on many different devices.
+    If a bug occurs on only a few devices, you should still address it if
+    those devices are particularly popular or new.
+  </td>
+  <td>
+    <a href="#gp">GP-1</a>
+  </td>
+  </tr>
+</table>
+
+<h3>
+  Related Resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/essentials/core/play" data-sortorder="-timestamp"
+data-cardsizes="6x3,6x3,6x3,6x3,6x3,6x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="test-environment">
+  Setting Up a Test Environment
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  To assess the quality of your app, you need to set up a suitable hardware or
+  emulator environment for testing.
+</p>
+
+<p>
+  The ideal test environment would include a small number of actual hardware
+  devices that represent key form factors and hardware/software combinations
+  currently available to consumers. It's not necessary to test on
+  <em>every</em> device that's on the market &mdash; rather, you should focus
+  on a small number of representative devices, even using one or two devices
+  per form factor.
+</p>
+
+<p>
+  If you are not able to obtain actual hardware devices for testing, you should
+  <a href="{@docRoot}tools/devices/index.html">set up emulated devices
+  (AVDs)</a> to represent the most common form factors and hardware/software
+  combinations.
+</p>
+
+<p>
+  To go beyond basic testing, you can add more devices, more form factors, or
+  new hardware/software combinations to your test environment. You can also
+  increase the number or complexity of tests and quality criteria.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="tests">
+  Test Procedures
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  These test procedures help you discover various types of quality issues in
+  your app. You can combine the tests or integrate groups of tests together in
+  your own test plans. See the sections above for references that associate
+  specific criteria with specific tests.
+</p>
+
+<table>
+  <tr>
+  <th style="width:2px;">
+    Type
+  </th>
+  <th style="width:54px;">
+    Test
+  </th>
+  <th>
+    Description
+  </th>
+  </tr>
+
+  <tr>
+  <td rowspan="12" id="core">
+    Core Suite
+  </td>
+  <td>
+    CR-0
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    Navigate to all parts of the app &mdash; all screens, dialogs,
+    settings, and all user flows.
+    </p>
+
+    <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+    <li>If the application allows for editing or content creation, game
+    play, or media playback, make sure to enter those flows to create or
+    modify content.
+    </li>
+
+    <li>While exercising the app, introduce transient changes in network
+    connectivity, battery function, GPS or location availability, system
+    load, and so on.
+    </li>
+    </ol>
+  </td>
+  </tr>
+
+  <tr id="tg2">
+  <td id="core2">
+    CR-1
+  </td>
+  <td>
+    From each app screen, press the device's Home key, then re-launch the app
+    from the All Apps screen.
+  </td>
+  </tr>
+
+  <tr id="CR-2">
+  <td>
+    CR-2
+  </td>
+  <td>
+    From each app screen, switch to another running app and then return to
+    the app under test using the Recents app switcher.
+  </td>
+  </tr>
+
+  <tr id="CR-3">
+  <td>
+    CR-3
+  </td>
+  <td>
+    From each app screen (and dialogs), press the Back button.
+  </td>
+  </tr>
+
+  <tr id="CR-5">
+  <td>
+    CR-5
+  </td>
+  <td>
+    From each app screen, rotate the device between landscape and portrait
+    orientation at least three times.
+  </td>
+  </tr>
+
+  <tr id="CR-6">
+  <td>
+    CR-6
+  </td>
+  <td>
+    Switch to another app to send the test app into the background. Go to
+    Settings and check whether the test app has any services running while in
+    the background. In Android 4.0 and higher, go to the Apps screen and find
+    the app in the "Running" tab. In earlier versions, use "Manage
+    Applications" to check for running services.
+  </td>
+  </tr>
+
+  <tr id="CR-7">
+  <td>
+    CR-7
+  </td>
+  <td>
+    Press the power button to put the device to sleep, then press the power
+    button again to awaken the screen.
+  </td>
+  </tr>
+
+  <tr id="CR-8">
+  <td>
+    CR-8
+  </td>
+  <td>
+    Set the device to lock when the power button is pressed. Press the power
+    button to put the device to sleep, then press the power button again to
+    awaken the screen, then unlock the device.
+  </td>
+  </tr>
+
+  <tr id="CR-9">
+  <!-- Hardware features -->
+
+  <td>
+    CR-9
+  </td>
+  <td>
+    For devices that have slide-out keyboards, slide the keyboard in and out
+    at least once. For devices that have keyboard docks, attach the device to
+    the keyboard dock.
+  </td>
+  </tr>
+
+  <tr id="CR-10">
+  <td>
+    CR-10
+  </td>
+  <td>
+    For devices that have an external display port, plug-in the external
+    display.
+  </td>
+  </tr>
+
+  <tr id="CR-11">
+  <td>
+    CR-11
+  </td>
+  <td>
+    Trigger and observe in the notications drawer all types of notifications
+    that the app can display. Expand notifications where applicable (Android
+    4.1 and higher), and tap all actions offered.
+  </td>
+  </tr>
+
+  <tr id="CR-12">
+  <td>
+    CR-12
+  </td>
+  <td>
+    Examine the permissions requested by the app by going to Settings &gt;
+    App Info.
+  </td>
+  </tr>
+
+  <tr id="tg3">
+  <td>
+    Install on SD Card
+  </td>
+  <td>
+    SD-1
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    Repeat <em>Core Suite</em> with app installed to <a href=
+    "{@docRoot}guide/topics/data/install-location.html">device SD card</a>
+    (if supported by app).
+    </p>
+
+    <p style="margin-bottom:.25em;">
+    To move the app to SD card, you can use Settings &gt; App Info &gt;
+    Move to SD Card.
+    </p>
+  </td>
+  </tr>
+
+  <tr id="tg32">
+  <td>
+    Hardware acceleration
+  </td>
+  <td>
+    HA-1
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    Repeat <em>Core Suite</em> with hardware acceleration enabled.
+    </p>
+
+    <p style="margin-bottom:.25em;">
+    To force-enable hardware acceleration (where supported by device), add
+    <code>hardware-accelerated="true"</code> to the
+    <code>&lt;application&gt;</code> in the app manifest and recompile.
+    </p>
+  </td>
+  </tr>
+
+  <tr id="tg33">
+  <td>
+    Performance Monitoring
+  </td>
+  <td>
+    PM-1
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    Repeat <em>Core Suite</em> with StrictMode profiling enabled <a href=
+    "#strictmode">as described below</a>.
+    </p>
+
+    <p style="margin-bottom:.25em;">
+    Pay close attention to garbage collection and its impact on the user
+    experience.
+    </p>
+  </td>
+  </tr>
+
+  <tr id="gp">
+  <td rowspan="3">
+    Google Play
+  </td>
+  <td>
+    GP-1
+  </td>
+  <td>
+    Sign into the <a href="https://play.google.com/apps/publish/">Developer
+    Console</a> to review your developer profile, app description,
+    screenshots, feature graphic, maturity settings, and user feedback.
+  </td>
+  </tr>
+
+  <tr id="GP-2">
+  <td>
+    GP-2
+  </td>
+  <td>
+    Download your feature graphic and screenshots and scale them down to
+    match the display sizes on the devices and form factors you are
+    targeting.
+  </td>
+  </tr>
+
+  <tr id="GP-3">
+  <td>
+    GP-3
+  </td>
+  <td>
+    Review all graphical assets, media, text, code libraries, and other
+    content packaged in the app or expansion file download.
+  </td>
+  </tr>
+
+  <tr id="GP-4">
+  <td>
+    Payments
+  </td>
+  <td>
+    GP-4
+  </td>
+  <td>
+    Navigate to all screens of your app and enter all in-app purchase flows.
+  </td>
+  </tr>
+</table>
+
+<h3 id="strictmode">
+  Testing with StrictMode
+</h3>
+
+<p>
+  For performance testing, we recommend enabling {@link android.os.StrictMode}
+  in your app and using it to catch operations on the main thread and other
+  threads that could affect performance, network accesses, file reads/writes,
+  and so on.
+</p>
+
+<p>
+  You can set up a monitoring policy per thread using {@link
+  android.os.StrictMode.ThreadPolicy.Builder} and enable all supported
+  monitoring in the <code>ThreadPolicy</code> using {@link
+  android.os.StrictMode.ThreadPolicy.Builder#detectAll()}.
+</p>
+
+<p>
+  Make sure to enable <strong>visual notification</strong> of policy violations
+  for the <code>ThreadPolicy</code> using {@link
+  android.os.StrictMode.ThreadPolicy.Builder#penaltyFlashScreen()
+  penaltyFlashScreen()}.
+</p>
diff --git a/docs/html/distribute/essentials/quality/tablets.jd b/docs/html/distribute/essentials/quality/tablets.jd
new file mode 100644
index 0000000..7dfab48
--- /dev/null
+++ b/docs/html/distribute/essentials/quality/tablets.jd
@@ -0,0 +1,867 @@
+page.title=Tablet App Quality
+page.metaDescription=Tablets are a fast-growing part of the Android installed base that offers new opportunities for your apps.
+page.image=/distribute/images/tablet-guidelines-color.jpg
+Xnonavpage=true
+
+@jd:body
+<div id="qv-wrapper"><div id="qv">
+<h2>Checklist</h2>
+<ol>
+<li><a href="#core-app-quality">1. Test for Basic Tablet App Quality</a></li>
+<li><a href="#optimize-layouts">2. Optimize Layouts</a></li>
+<li><a href="#use-extra-space">3. Use Extra Screen Area</a></li>
+<li><a href="#use-tablet-icons">4. Use Assets Designed for Tablets</a></li>
+<li><a href="#adjust-font-sizes">5. Adjust Fonts and Touch Targets</a></li>
+<li><a href="#adjust-widgets">6. Adjust Homescreen Widgets</a></li>
+<li><a href="#offer-full-feature-set">7. Offer Full Feature Set</a></li>
+<li><a href="#android-versions">8. Target Android Versions Properly</a></li>
+<li><a href="#hardware-requirements">9. Declare Dependencies Properly</a></li>
+<li><a href="#support-screens">10. Declare Support for Tablet Screens</a></li>
+<li><a href="#google-play">11. Showcase Your Tablet UI</a></li>
+<li><a href="#google-play-best-practices">12. Follow Best Practices for Publishing in Google Play</a></li>
+
+</ol>
+<h2>Testing</h2>
+<ol>
+<li><a href="#test-environment">Setting Up a Test Environment</a></li>
+</ol>
+</div></div>
+
+<div class="todp-right-float" style="padding-right:0;margin-bottom:1em;">
+  <img src="{@docRoot}distribute/images/tablet-guidelines-color.jpg" style="width:480px;">
+</div>
+
+<p>
+  Tablets are a growing part of the Android installed base and offer new
+  opportunities for <a href="{@docRoot}distribute/stories/tablets.html">user
+  engagement and monetization</a>. The guidelines in this document will help
+  you meet the expectations of tablet users through compelling features and an
+  intuitive, well-designed UI.
+</p>
+
+<p>
+  Although the guidelines are numbered, you can approach them in any order. You
+  should address each guideline’s recommendations to the extent that they’re
+  appropriate for your app, but &mdash; in the interest of delivering the best
+  product to your customers &mdash; follow them to the greatest extent
+  possible.
+</p>
+
+<p>
+  Through the document you'll find links to resources that can
+  help you address each recommendation included.
+</p>
+
+<div class="headerLine"><h1 id="core-app-quality">1. Test for Basic Tablet App Quality</h1><hr></div>
+
+<p>The first step in delivering a great tablet app experience is making sure
+that it meets the <em>core app quality criteria</em> for all of the devices
+and form factors that the app is targeting. For complete information, see the <a
+href="{@docRoot}distribute/essentials/quality/core.html">Core App Quality Guidelines</a>. 
+</p>
+
+<p>
+Before publishing, also ensure that your app passes the basic technical checks and launch criteria, such as:
+</p>
+
+<ul>
+  <li><a href="#android-versions">Targets appropriate Android versions</a></li>
+  <li><a href="#hardware-requirements">Specifies any hardware dependencies properly</a></li>
+  <li><a href="#support-screens">Declares support for appropriate screens</a></li>
+  <li><a href="#use-extra-space">Uses all of the available screen space</a></li>
+  <li><a href="#google-play">Screenshots are uploaded to Google Play</a></li>
+</ul>
+
+<p>If your app is already uploaded to the Google Play Developer Console, you
+  can see how it is doing against these checks  
+  by visiting the <a href="#google-play-optimization-tips">Optimization
+  Tips page</a>.</p>
+
+
+<div class="headerLine clearfloat">
+<h1 id="optimize-layouts">2. Optimize Layouts for Larger Screens</h1><hr></div>
+
+<p>
+  Android makes it easy to develop an app that runs well on a wide range of
+  device screen sizes and form factors. This broad compatibility works in your
+  favor, since it helps you design a single app that you can distribute widely
+  to all of your targeted devices. However, to give your users the best
+  possible experience on each screen configuration &mdash; in particular on
+  tablets &mdash; you need to optimize your layouts and other UI components for
+  each targeted screen configuration. On tablets, optimizing your UI lets you
+  take full advantage of the additional screen available, such as to offer new
+  features, present new content, or enhance the experience in other ways to
+  deepen user engagement.
+</p>
+
+<p>
+  If you developed your app for handsets and now want to distribute it to
+  tablets, you can start by making minor adjustments to your layouts, fonts,
+  and spacing. In some cases &mdash; such as for 7-inch tablets or for a game
+  with large canvas &mdash; these adjustments may be all you need to make your
+  app look great. In other cases, such as for larger tablets, you can redesign
+  parts of your UI to replace "stretched UI" with an efficient multipane UI,
+  easier navigation, and additional content.
+</p>
+
+
+<div style="width:500px;margin:1.5em;margin-top:-16px;">
+<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-bad.png"
+style="padding:4px;margin-bottom:0em;">
+<p class="img-caption"><span
+style="font-weight:500;">Get rid of "stretched" UI</span>: On tablets, single-pane
+layouts lead to awkward whitespace and excessive line lengths. Use padding to
+reduce the width of UI elements and consider using multi-pane layouts.</p>
+</div>
+
+<p>Here are some suggestions:</p>
+
+
+<ul>
+  <li>Provide custom layouts as needed for <code>large</code> and
+  <code>xlarge</code> screens. You can also provide layouts that are loaded
+  based on the screen's <a href=
+  "{@docRoot}guide/practices/screens_support.html#NewQualifiers">shortest
+  dimension</a> or the <a href=
+  "{@docRoot}guide/practices/screens_support.html#NewQualifiers">minimum
+  available width and height</a>.
+  </li>
+
+  <li>At a minimum, customize dimensions such as font sizes, margins, spacing
+  for larger screens, to improve use of space and content legibility.
+  </li>
+
+  <li>Adjust positioning of UI controls so that they are easily accessible to
+  users when holding a tablet, such as toward the sides when in landscape
+  orientation.
+  </li>
+
+  <li>Padding of UI elements should normally be larger on tablets than on
+  handsets. A <a href="{@docRoot}design/style/metrics-grids.html#48dp-rhythm">
+    48dp rhythm</a> (and a 16dp grid) is recommended.
+  </li>
+
+  <li>Adequately pad text content so that it is not aligned directly along
+  screen edges. Use a minimum <code>16dp</code> padding around content near
+  screen edges.
+  </li>
+</ul>
+
+<p>In particular, make sure that your layouts do not appear "stretched"
+across the screen:</p>
+
+<ul>
+<li>Lines of text should not be excessively long &mdash; optimize for a maximum
+100 characters per line, with best results between 50 and 75.</li>
+<li>ListViews and menus should not use the full screen width.</li>
+<li>Use padding to manage the widths of onscreen elements or switch to a
+multi-pane UI for tablets (see next section).</li>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines/optimize"
+  data-sortOrder="-timestamp"
+  data-cardSizes="6x3"
+  data-maxResults="6"></div>
+
+
+<div class="headerLine clearfloat"><h1 id="use-extra-space">3. Take Advantage of Extra Screen Area</h1><hr></div>
+
+<div style="width:340px;float:right;margin:1.5em;margin-bottom:0;margin-top:0;">
+<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-good.png"
+style="padding:4px;margin-bottom:0em;">
+<p class="img-caption"><span
+style="font-weight:500;">Multi-pane layouts</span> result in a better visual
+balance on tablet screens, while offering more utility and legibility.</p>
+</div>
+
+<p>Tablet screens provide significantly more screen real estate to your app,
+especially when in landscape orientation. In particular, 10-inch tablets offer a
+greatly expanded  area, but even 7-inch tablets give you more space for
+displaying content and engaging users. </p>
+
+<p>As you consider the UI of your app when running on tablets, make sure that it
+is taking full advantage of extra screen area available on tablets. Here are
+some suggestions:</p>
+
+<ul>
+<li>Look for opportunities to include additional content or use an alternative
+treatment of existing content.</li>
+<li>Use <a href="{@docRoot}design/patterns/multi-pane-layouts.html">multi-pane
+layouts</a> on tablet screens to combine single views into a compound view. This
+lets you use the additional screen area more efficiently and makes it easier for
+users to navigate your app. </li>
+<li>Plan how you want the panels of your compound views to reorganize when
+screen orientation changes.</li>
+
+<div style="width:490px;margin:1.5em auto 1.5em 0;">
+<div style="">
+<img src="{@docRoot}images/ui-ex-single-panes.png"
+style="width:490px;padding:4px;margin-bottom:0em;" align="middle">
+<img src="{@docRoot}images/ui-ex-multi-pane.png" style="width:490px;padding:4px;margin-bottom:0em;">
+<p class="image-caption" style="padding:.5em"><span
+style="font-weight:500;">Compound views</span> combine several single views from a
+handset UI <em>(above)</em> into a richer, more efficient UI for tablets
+<em>(below)</em>. </p>
+</div>
+</div>
+
+<li>While a single screen is implemented as an {@link android.app.Activity}
+subclass, consider implementing individual content panels as {@link
+android.app.Fragment} subclasses. This lets you
+maximize code reuse across different form factors and across screens that
+share content.</li>
+<li>Decide on which screen sizes you'll use a multi-pane UI, then provide the
+different layouts in the appropriate screen size buckets (such as
+<code>large</code>/<code>xlarge</code>) or minimum screen widths (such as
+<code>sw600dp</code>/<code>sw720</code>).</li>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines/extrascreen"
+  data-sortOrder="-timestamp"
+  data-cardSizes="6x3,6x3,6x3"
+  data-maxResults="6"></div>
+
+<div class="headerLine clearfloat"><h1 id="use-tablet-icons">4. Use Assets Designed for Tablet Screens</h1><hr></div>
+
+<div><img src="{@docRoot}design/media/devices_displays_density@2x.png"></div>
+
+<p>To ensure your app looks its best, provide icons and other bitmap
+assets for each density in the range commonly supported by tablets. Specifically, you should
+design your icons for the action bar, notifications, and launcher according to the
+<a href="{@docRoot}design/style/iconography.html">Iconography</a> guidelines and
+provide them in multiple densities, so they appear at the appropriate size on all screens
+without blurring or other scaling artifacts.</p>
+
+<p class="table-caption"><strong>Table 1</strong>. Raw asset sizes for icon types.<table>
+<tr>
+<th>Density</th>
+<th>Launcher</th>
+<th>Action Bar</th>
+<th>Small/Contextual</th>
+<th>Notification</th>
+</tr>
+<tr>
+<td><code>mdpi</code></td>
+<td>48x48 px</td>
+<td>32x32 px</td>
+<td>16x16 px</td>
+<td>24x24 px</td>
+</tr>
+<tr>
+<td><code>hdpi</code></td>
+<td>72x72 px</td>
+<td>48x48 px</td>
+<td>24x24 px</td>
+<td>36x36 px</td>
+</tr>
+<tr>
+<td><code>tvdpi</code></td>
+<td><em>(use hdpi)</em></td>
+<td><em>(use hdpi)</em></td>
+<td><em>(use hdpi)</em></td>
+<td><em>(use hdpi)</em></td>
+</tr>
+<tr>
+<td><code>xhdpi</code></td>
+<td>96x96 px</td>
+<td>64x64 px</td>
+<td>32x32 px</td>
+<td>48x48 px</td>
+</tr>
+<tr>
+<td><code>xxhdpi</code></td>
+<td>144x144 px</td>
+<td>96x96 px</td>
+<td>48x48 px</td>
+<td>72x72 px</td>
+</tr>
+
+</table>
+
+<p>
+  As a minimum, supply a version of each icon and bitmap asset that's optimized
+  for <strong>at least one</strong> the following common tablet screen
+  densities:
+</p>
+<ul>
+  <li><code>hdpi</code></li>
+  <li><code>xhdpi</code></li>
+  <li><code>xxhdpi</code></li>
+</ul>
+
+<p>Other tips:</p>
+
+<ul>
+<li>Use vector shapes when designing icons, so they scale without loss of either detail or edge crispness.</li>
+<li>Use density-specific <a
+href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">
+resource qualifiers</a> to ensure that the proper icons are loaded for each screen density.</li>
+<li>Tablets and other large screen devices often request a launcher icon that is one density
+size larger than the device's actual density, so you should provide your launcher
+icon at the highest density possible. For example, if a tablet has an {@code xhdpi} screen,
+it will request the {@code xxhdpi} version of the launcher icon.</li>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines/assets"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
+
+<div class="headerLine clearfloat"><h1 id="adjust-font-sizes">5.
+Adjust Font Sizes and Touch Targets</h1><hr></div>
+
+<p>To make sure your app is easy to use on tablets, take some time to adjust the
+font sizes and touch targets in your tablet UI, for all of the screen
+configurations you are targeting. You can adjust font sizes through <a
+href="{@docRoot}guide/topics/ui/themes.html">styleable attributes</a> or <a
+href="{@docRoot}guide/topics/resources/more-resources.html#Dimension">dimension
+resources</a>, and you can adjust touch targets through layouts and bitmap
+drawables, as discussed above. </p>
+
+<p>Here are some considerations:</p>
+<ul>
+<li>Text should not be excessively large or small on tablet screen sizes and
+densities. Make sure that labels are sized appropriately for the UI elements they
+correspond to, and ensure that there are no improper line breaks in labels,
+titles, and other elements.</li>
+<li>The recommended touch-target size for onscreen elements is 48dp (32dp
+minimum) &mdash; some adjustments may be needed in your tablet UI. Read <a
+href="{@docRoot}design/style/metrics-grids.html">Metrics and
+Grids
+</a> to learn about implementation strategies to help most of your users. To
+meet the accessibility needs of certain users, it may be appropriate to use
+larger touch targets. </li>
+<li>When possible, for smaller icons, expand the touchable area to more than
+48dp using {@link android.view.TouchDelegate}
+or just centering the icon within the transparent button.</li>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines/fonts"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3,9x3,6x3,6x3,6x3"
+  data-maxResults="6"></div>
+
+<div class="headerLine clearfloat"><h1 id="adjust-widgets">6. Adjust Sizes of Home Screen Widgets</h1><hr></div>
+
+<p>If your app includes a home screen widget, here are a few points to consider
+to ensure a great user experience on tablet screens: </p>
+
+<ul>
+<li>Set the widget's default height and width appropriately
+for tablet screens, as well as the minimum and maximum resize height and width.
+</li>
+<li>The widget should be resizable to 420dp or more, to span 5 or more home
+screen rows (if this is a vertical or square widget) or columns (if this is a
+horizontal or square widget). </li>
+<li>Make sure that 9-patch images render correctly.</li>
+<li>Use default system margins.</li>
+<li>Set the app's <code>targetSdkVersion</code> to 14 or higher, if
+possible.</li>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines/widgets"
+  data-sortOrder="-timestamp"
+  data-cardSizes="6x3"
+  data-maxResults="6"></div>
+
+
+<div class="headerLine clearfloat"><h1 id="offer-full-feature-set">7. Full Feature Set for Tablet Users</h1><hr></div>
+
+<div class="centered-full-image" style="width:600px;margin:1.5em"><img src="{@docRoot}images/gp-tablets-full-feature-set.png" alt="Tablet feature sets"></div>
+
+<p>Let your tablet users experience the best features of your app. Here are
+some recommendations:</p>
+
+<ul>
+  <li>Design your app to offer at least the same set of features on tablets as
+  it does on phones.
+  </li>
+
+  <li>In exceptional cases, your app might omit or replace certain features on
+  tablets if they are not supported by the hardware or use-case of most
+  tablets. For example:
+    <ul>
+      <li>If the handset uses telephony features but telephony is not available
+      on the current tablet, you can omit or replace the related functionality.
+      </li>
+
+      <li>Many tablets have a GPS sensor, but most users would not normally
+      carry their tablets while running. If your phone app provides
+      functionality to let the user record a GPS track of their runs while
+      carrying their phones, the app would not need to provide that
+      functionality on tablets because the use-case is not compelling.
+      </li>
+    </ul>
+  </li>
+
+  <li>If you will omit a feature or capability from your tablet UI, make sure
+  that it is not accessible to users or that it offers “graceful degradation”
+  to a replacement feature (also see the section below on hardware features).
+  </li>
+</ul>
+
+<div class="headerLine clearfloat"><h1 id="android-versions">8. Target Android Versions Properly</h1><hr></div>
+
+<p>
+  To ensure the broadest possible distribution to tablets, make sure that your
+  app properly targets the Android versions that support tablets. Initial
+  support for tablets was added in <a href=
+  "{@docRoot}about/versions/android-3.0.html">Android 3.0</a> (API level 11).
+  Unified UI framework support for tablets, phones, and other devices was
+  introduced in <a href="{@docRoot}about/versions/android-4.0.html">Android
+  4.0</a>
+</p>
+
+<p>
+  You can set the app's range of targeted Android versions in the manifest
+  file, in the <a href=
+  "{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code>&lt;uses-sdk&gt;</code></a>
+  element. In most cases, you can target Android versions properly by setting
+  the element's <code>targetSdkVersion</code> attribute to the highest API
+  level available.
+</p>
+
+<p style="margin-bottom:.5em;">
+  At a minimum, check the <a href=
+  "{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code>&lt;uses-sdk&gt;</code></a>
+  element to make sure that:
+</p>
+
+<ol style="list-style-type:lower-alpha;margin-top:0em;">
+  <li>
+    <code>targetSdkVersion</code> is declared with value 11 or higher (14 or
+    higher is recommended), OR
+  </li>
+
+  <li>
+    <code>minSdkVersion</code> is declared with value 11 or higher.
+  </li>
+
+  <li>If a <code>maxSdkVersion</code> attribute is declared, it must have a
+  value of 11 or higher. Note that, in general, the use of
+  <code>maxSdkVersion</code> is <em>not recommended</em>.
+  </li>
+</ol>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines/versions"
+  data-sortOrder="-timestamp"
+  data-cardSizes="6x3"
+  data-maxResults="6"></div>
+
+<div class="headerLine clearfloat"><h1 id="hardware-requirements">9. Declare Hardware Feature Dependencies Properly</h1><hr></div>
+
+<p>
+  Handsets and tablets typically offer slightly different hardware support for
+  sensors, camera, telephony, and other features. For example, many tablets are
+  available in a "Wi-Fi" configuration that does not include telephony support.
+</p>
+
+<p>
+  So that you can distribute a single APK broadly across your full customer
+  base of phones and tablets, make sure that your app doesn't declare
+  requirements for hardware features that aren't commonly available on tablets.
+  Instead, properly declare the hardware features as <em>not required</em> in the app
+  manifest, as described below.
+</p>
+
+<ul>
+<li>In your app manifest, locate any <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a>
+elements. In particular, look for hardware features that might not be
+available on some tablets, such as:
+
+<ul>
+<li><code>android.hardware.telephony</code></li>
+<li><code>android.hardware.camera</code> (refers to back camera), or</li>
+<li><code>android.hardware.camera.front</code></li>
+</ul></li>
+
+<li>Declare the <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a>
+elements as <em>not required</em> by including the <code>android:required=”false”</code>
+attribute.
+
+<p>
+  For example, here's the proper way to declare a dependency on
+  <code>android.hardware.telephony</code>, such that you can still
+  distribute the app broadly, even to devices that don't offer telephony:
+</p>
+
+<pre>&lt;uses-feature android:name="android.hardware.telephony" android:required="false" /&gt;</pre></li>
+
+<li>Similarly, check the manifest for <a href="{@docRoot}guide/topics/manifest/permission-element.html"><code>&lt;permission&gt;</code></a> elements that 
+<a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#permissions">imply hardware
+feature requirements</a> that not be appropriate for tablets. If you find such
+permissions, make sure to explicitly declare a corresponding
+<code>&lt;uses-feature&gt;</code> element for the features and includes the
+<code>android:required=”false”</code> attribute.</li>
+</ul>
+
+
+<p>
+  After declaring hardware features as <em>not required</em>, make sure to test
+  your app on a variety of devices. The app should function normally when the
+  hardware features it uses are not available, and it should offer "graceful
+  degradation" and alternative functionality where appropriate.
+</p>
+
+<p>
+  For example, if an app normally uses GPS to set the location but GPS is not
+  supported on the device, the app could let the user set the location manually
+  instead. The app can check for device hardware capabilities at runtime and handle
+  as needed.
+</p>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines/hardware"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
+
+<div class="headerLine clearfloat"><h1 id="support-screens">10. Declare Support for Tablet Screens</h1><hr></div>
+
+<p>To ensure that you can distribute your app to a broad range of tablets, your app should
+declare support for tablet screen sizes in its manifest file, as follows:</p>
+
+<ul>
+  <li>A
+  <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code>&lt;supports-screens&gt;</code></a>
+  element, if declared, must not specify <code>android:largeScreens="false"</code>
+  or <code>android:xlargeScreens="false"</code>.</li>
+  <li>For apps targeting <code>minSdkVersion</code> value less than 13, a
+  <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code>&lt;supports-screens&gt;</code></a>
+  element must be declared with both <code>android:largeScreens="true"</code> and
+  <code>android:xlargeScreens="true"</code>.</li>
+</ul>
+
+<p>If the app declares a
+<a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html"><code>&lt;compatible-screens&gt;</code></a>
+element in the manifest, the element should include attributes that specify
+<em>all of the size and density combinations for tablet screens</em> that the
+app supports. Note that, if possible, you should avoid using the
+<a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html"><code>&lt;compatible-screens&gt;</code></a>
+element in your app.</p>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines/tabletscreens"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3,6x3,6x3"
+  data-maxResults="6"></div>
+
+
+<div class="headerLine clearfloat"><h1 id="google-play">11. Showcase Your Tablet UI in Google Play</h1><hr></div>
+
+<p>
+  After you've done the work to create an rich, optimized UI for your tablet
+  app, make sure that you let your customers know about it! Here are some key
+  ways to promote your tablet app to users on Google Play.
+</p>
+
+<div><img class="border-img" src="{@docRoot}images/gp-tablet-quality-4.jpg"></div>
+
+
+<h4>
+  Upload screenshots of your tablet UI
+</h4>
+
+<p>
+  Tablet users want to know what your app is like on a tablet device, not on a
+  phone. If you developed a tablet app, make sure to upload screenshots
+  of your tablet UI to the Google Play Developer Console. Here are some guidelines:
+  </p>
+
+<ul style="margin-top:0;">
+  <li>Show the core functionality of your app, not a
+  startup or sign-in page. Wherever users will spend most of their time, that's
+  what you should show in your screenshots.
+  </li>
+
+  <li>Add screenshots taken on both 7-inch and 10-inch tablets.
+  </li>
+
+  <li>Add screenshots taken in both landscape and
+  portrait orientations, if possible.
+  </li>
+
+  <li>Use screen captures if possible. Avoid showing actual device hardware in your
+  screenshots.</li>
+
+  <li>The recommended resolution of your tablet screenshots is <strong>1280 x 720</strong>
+  or higher in each orientation.
+  </li>
+
+  <li>Upload as many as 8 screenshots of your tablet UI for 7-inch tablets
+  and an additional 8 for 10-inch tablets.
+  </li>
+</ul>
+
+<h4>
+  Update your app description and release notes
+</h4>
+
+<ul>
+  <li>In your app description, make sure to highlight that your app offers
+  tablet-optimized UI and great features for tablet users. Add some
+  detail about how your tablet UI works and why users will like it.
+  </li>
+
+  <li>Include information about tablet support in the app's release notes and
+  update information.
+  </li>
+</ul>
+
+<h4>
+  Update your promotional video
+</h4>
+
+<p>
+  Many users view an app's promotional video to get an idea of what the app is
+  like and whether they'll enjoy it. For tablet users, capitalize on this
+  interest by highlighting your app's tablet UI in your promotional video. Here
+  are some tips and guidelines:
+</p>
+
+<ul>
+  <li>Add one or more shots of your app running on a tablet. To engage with
+  tablet users most effectively, it's recommended that you promote your tablet
+  UI in approximately equal proportion to your phone UI.
+  </li>
+
+  <li>Show your tablet UI as early as possible in the video. Don't assume that
+  tablet users will wait patiently through a feature walkthrough on a phone UI.
+  Ideally, you should engage them immediately by showing the tablet UI within
+  the first 10 seconds, or at the same point that you introduce the phone UI.
+  </li>
+
+  <li>To make it clear that you are showing a tablet UI, include shots of your
+  app running on a hand-held tablet device.
+  </li>
+
+  <li>Highlight your app's tablet UI in the video's narrative or voiceover.
+  </li>
+</ul>
+
+<h4>
+  Feature your tablet UI in your promotional campaigns
+</h4>
+
+<p>
+  Make sure to let tablet users know about your tablet UI in your promotional
+  campaigns, web site, social posts, advertisements, and elsewhere. Here are
+  some suggestions:
+</p>
+
+<ul>
+  <li>Plan a marketing or advertising campaign that highlights the use of your
+  app on tablets.</li>
+
+  <li>Show your tablet app at its best in your promotional campaigns&mdash;use the <a href=
+  "{@docRoot}distribute/tools/promote/device-art.html">Device Art Generator</a> to
+  quickly generate a high-quality promotional image of your app running on a
+  7-inch or 10-inch tablet, in the orientation of your choice, with or without
+  drop-shadow and screen glare. It's as simple as capture, drag, and drop.
+  </li>
+
+  <li>Include a Google Play badge in your online promotions to let users link
+  directly to your app's store listing. You can generate a badge in a variety
+  of languages using the <a href=
+  "{@docRoot}distribute/tools/promote/badges.html">Badge Generator</a>.
+  </li>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines/showcase"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3,9x3,9x3,9x3"
+  data-maxResults="6"></div>
+
+<div class="headerLine clearfloat">
+  <h1 id="google-play-best-practices">
+    12. Follow Best Practices for Publishing in Google Play
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Here are some best practices for delivering a successful tablet app on Google
+  Play.
+</p>
+
+<div>
+  <img class="border-img" src="{@docRoot}images/gp-tablet-quality-5.jpg" style=
+  "1px solid #ddd">
+</div>
+
+<h4 id="google-play-optimization-tips">
+  Check out your app's Optimization Tips
+</h4>
+
+<p>The Google Play Developer Console now offers an Optimization Tips page that
+lets you quickly check how your app is doing against basic guidelines for tablet app
+distribution and quality. To visit the page, sign into the Developer Console,
+load the app from All Applications, and click Optimization Tips in
+the left navigation.</p>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<h2>How to send feedback</h2>
+
+<p>Please use the link below to send
+feedback or request a manual review of your Optimization Tips.</p>
+
+<p>Make sure to read the relevant sections of the Tablet App Quality
+Guidelines prior to sending feedback.</p>
+
+<p><strong><a href="https://support.google.com/googleplay/android-developer/contact/tabletq"
+target="_googleplay" style="white-space:nowrap">Designed for Tablets Contact Form &raquo;</a></strong></p>
+</div>
+</div>
+
+<p>The Developer Console creates your app's Optimization Tips page
+by running a series of checks to verify basic quality
+criteria. If it finds any issues, it alerts you to them as "To Do"
+items in the Optimization Tips page.</p>
+
+<p>If you've developed a tablet experience for your app, make sure
+to visit the Optimization Tips page to see how your app is doing
+against the basic checks.  If there are any issues listed, we
+recommend addressing them in your app and uploading a new binary for
+distribution, if needed. </p>
+
+<p>If the Optimization Tips page lists "To Do" issues that you feel don't
+apply to your app or affect its quality on tablets, please notify us
+using the <a href="https://support.google.com/googleplay/android-developer/contact/tabletq"
+target="_googleplay" style="white-space:nowrap">Designed for Tablets Contact Form &raquo;</a>. We
+will review your app and update your Optimization Tips page as
+appropriate.</p>
+
+
+<h4>Confirm the app's filtering</h4>
+
+<p>
+  After you've uploaded the app to the <a href=
+  "https://play.google.com/apps/publish/">Developer Console</a>, check the
+  APK's Supported Devices list to make sure that the app is not filtered from
+  tablet devices that you want to target.
+</p>
+
+<h4>Distribute as a single APK</h4>
+
+<p>
+  It's recommended that you publish your app as a single APK for all screen
+  sizes (phones and tablets), with a single Google Play listing. This approach
+  has several important advantages.
+</p>
+
+<ul style="margin-top:.25em;">
+  <li>Easier for users to find your app from search, browsing, or promotions
+  </li>
+
+  <li>Easier for users to restore your app automatically if they get a new
+  device.
+  </li>
+
+  <li>Your ratings and download stats are consolidated across all devices.
+  </li>
+
+  <li>Publishing a tablet app in a second listing can dilute ratings for your
+  brand.
+  </li>
+</ul>
+
+<p>
+  If necessary, you can alternatively choose to deliver your app using <a href=
+  "{@docRoot}google/play/publishing/multiple-apks.html">Multiple APK Support</a>,
+  although in most cases using a single APK to reach all devices is strongly
+  recommended.
+</p>
+
+<h3 class="clearfloat">Related resources</h3>
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines/googleplay"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
+
+
+<div class="headerLine clearfloat">
+  <h1 id="test-environment">
+    Setting Up a Test Environment for Tablets
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Assess the quality of your app on tablets — both for core app quality and
+  tablet app quality &mdash; with a suitable hardware or emulator environment
+  for testing.
+</p>
+
+<p>
+  Compared to the <a href=
+  "{@docRoot}distribute/essentials/quality/core.html#test-environment">recommended
+  test environment</a> for testing against the core app quality criteria,
+  include mid-size tablets and tablets with more or fewer hardware/software
+  features.
+</p>
+
+<p class="table-caption"><strong>Table 1</strong>. A typical tablet test environment might
+include one or two devices from each row in the table below, with one of the
+listed platform versions, screen configurations, and hardware feature configurations.</p>
+
+<table>
+<tr>
+<th>Type</th>
+<th>Size</th>
+<th>Density</th>
+<th>Version</th>
+<th>AVD Skin</th>
+</tr>
+
+<tr>
+<td>7-inch tablet</td>
+<td><span style="white-space:nowrap"><code>large</code> or</span><br /><code>-sw600</code></td>
+<td><code>hdpi</code>,<br /><code>tvdpi</code></td>
+<td>Android 4.0+ (API level 14 and higher)</td>
+<td>WXGA800-7in</td>
+</tr>
+<tr>
+<td><span style="white-space:nowrap">10-inch</span> tablet</td>
+<td><span style="white-space:nowrap"><code>xlarge</code> or</span><br /><code>-sw800</code></td>
+<td><code>mdpi</code>,<br /><code>hdpi</code>,<br /><code>xhdpi</code></td>
+<td>Android 3.2+ (API level 13 and higher)</td>
+<td>WXGA800</td>
+</tr>
+</table>
+
+<div class="headerLine clearfloat"><h1 id="related-resources">Related Resources</h1><hr></div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/about.jd b/docs/html/distribute/googleplay/about.jd
new file mode 100644
index 0000000..cf0c6d2
--- /dev/null
+++ b/docs/html/distribute/googleplay/about.jd
@@ -0,0 +1,369 @@
+page.title=The Google Play Opportunity
+meta.tags="visibility, growth, distributing"
+page.tags="play, apps, distributing, publishing"
+page.metaDescription=Billons of downloads a month and growing. Get your apps in front of users at Google's scale.
+page.image=/distribute/images/about-play.jpg
+
+@jd:body
+
+    <div id="qv-wrapper">           
+  <div id="qv">
+  <h2>About Google Play</h2>
+    <ol style="list-style-type:none;">
+      <li><a href="#reach">Worldwide Reach, Rapid Growth</a></li>
+      <li><a href="#ratings-reviews">User Ratings and Reviews</a></li>
+      <li><a href="#category-browsing">Category Browsing</a></li>
+      <li><a href="#search">Search</a></li>
+      <li><a href="#top-charts-and-lists">Top Charts and Lists</a></li>
+      <li><a href="#featured-staff-picks">Featured, Staff Picks, Collections, and Badges</a></li>
+      <li><a href="#product-detail-pages">Store Listing Pages</a></li>
+      <li><a href="#related-resources">Related Resources</a></li>
+    </ol>
+  </div>
+</div>
+
+<p>
+  Google Play is the premier store for distributing Android apps. When you
+  publish on Google Play, you put your apps in front of Android's huge base of
+  active customers, in more than 130 countries and territories across the
+  world.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-about-0.jpg" alt="Google Play on an Android Tablet"
+  style="width:480px;position:relative" />
+</div>
+
+<p>
+  Google Play is a central part of the Android experience. New users
+  personalize their devices with apps, games, and other Google Play content.
+  Existing users return regularly to see what's trending and new. Downloading
+  new apps is extremely convenient and fast&mdash; Google Play pushes apps to
+  the user's devices instantly, over the air.
+</p>
+
+<p>
+  Google Play is also a top destination for web users. Anyone with a browser
+  can explore Google Play on the web. Android users can even buy and install
+  the apps they want and Google Play pushes them automatically to their devices
+  with no cables required.
+</p>
+
+<p>
+  The accessibility and convenience of the Google Play web site give you new
+  ways to drive traffic to your products from many sources, such as online ads,
+  web search and cross-linking. Google Play is designed to connect users with
+  great apps and games. It provides key channels to get your app noticed and
+  gain traction in the marketplace.
+</p>
+
+<div class="headerLine">
+  <h1 id="ratings-reviews">
+    User Ratings and Reviews
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Prospective users look at ratings and reviews as key benchmarks of app
+  quality. By rating apps from one to five stars and posting reviews, Android
+  users show their appreciation for the apps they have downloaded.
+</p>
+
+<p>
+  <strong>Your app's rating is one of the most important factors influencing
+  its ranking</strong> in the Google Play lists and search results. It's also
+  one of the key metrics that the editorial staff looks for when curating apps
+  and games for promotion in the store.
+</p>
+
+<div class="img" style="padding: 1em auto;width:96%;">
+  <img src="{@docRoot}images/gp-rating-web.png" style="border:1px solid #ddd;">
+</div>
+
+<div class="headerLine">
+  <h1 id="category-browsing">
+    Category Browsing
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  When you publish an app in Google Play, you pick the category where you want
+  users to find your app. More than 30 categories are available. Inside each
+  category, apps are ranked based on a combination of ratings, reviews,
+  downloads, country, and other factors.
+</p>
+
+<div class="headerLine">
+  <h1 id="search">
+    Search
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Search on Google Play lets users pinpoint an app or game quickly. Search uses
+  powerful heuristics to suggest terms as the user types, and it offers direct
+  links to apps as suggestions. In results, users find the most relevant, most
+  popular apps at the top.
+</p>
+
+<div class="headerLine">
+  <h1 id="top-charts-and-lists">
+    Top Charts and Lists
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-about-top.jpg">
+</div>
+
+<p>
+  Top charts keep users in touch with what’s popular and trending with Android
+  users, right from the Apps and Games home pages. The charts stay fresh,
+  updating several times each day based on recent download activity. As an
+  app's ratings and download activity grow, it can move up in the charts.
+</p>
+
+<p>
+  To make the charts as relevant as possible for users across the world, they
+  are also country-specific in Google Play's most popular countries. As your
+  apps get traction and build momentum in downloads and ratings, they’ll climb
+  one or more of the top charts and gain even more exposure.
+</p>
+
+<table style="width:50%;">
+  <tr>
+    <td>
+      Top Free
+    </td>
+    <td>
+      Free apps and free games lists
+    </td>
+  </tr>
+
+  <tr>
+    <td>
+      Top Paid
+    </td>
+    <td>
+      Paid apps and paid games lists
+    </td>
+  </tr>
+
+  <tr>
+    <td>
+      Top Grossing
+    </td>
+    <td>
+      Gross proceeds, free or paid
+    </td>
+  </tr>
+
+  <tr>
+    <td>
+      Top New Free
+    </td>
+    <td>
+      Less than 30 days old
+    </td>
+  </tr>
+
+  <tr>
+    <td>
+      Top New Paid
+    </td>
+    <td>
+      Less than 30 days old
+    </td>
+  </tr>
+
+  <tr>
+    <td>
+      Trending
+    </td>
+    <td>
+      New arrivals growing quickly in installs
+    </td>
+  </tr>
+</table>
+
+<div class="headerLine">
+  <h1 id="featured-staff-picks">
+    Featured, Staff Picks, Collections, and Badges
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  The Google Play editorial team is dedicated to bringing the best apps to the
+  attention of users and setting the tone for app quality throughout the store.
+  It constantly reviews apps from across Google Play to find not only the
+  best-known apps and games, but also the "diamonds in the rough" that they
+  want more people to see. The team promotes great apps in the
+  <em>Featured</em>, <em>Staff Picks</em>, and other collections.
+</p>
+
+<p>
+  You can't nominate your app for featuring, but the team is always monitoring
+  Google Play for great apps. If you build an app that users love and that
+  looks great on Android devices, the editorial team will notice.
+</p>
+
+<h3 id="featured-staff-picks2">
+  Featured and Staff Picks
+</h3>
+
+<p>
+  Each week the Google Play editorial staff selects a new set of apps to
+  promote in its popular <em>Featured</em> and <em>Staff Picks</em>
+  collections.
+</p>
+
+<p>
+  The <em>Featured</em> collections highlight the latest and greatest app and
+  game titles available for Android. The list also includes the best and most
+  popular apps in the top categories are also featured. <em>Staff Picks</em>
+  collects all recently featured apps and games on Google Play. To focus on
+  tablet users, A special <em>Staff Picks</em> collection highlights the best
+  apps for Android tablets.
+</p>
+
+<table style="text-align:center;margin:1.5em 0;">
+  <tr>
+    <td style="border:none;">
+      <img src="{@docRoot}images/gp-about-picks1.jpg">
+      <p>
+        Featured
+      </p>
+    </td>
+    <td style="border:none;">
+      <img src="{@docRoot}images/gp-about-picks2.jpg">
+      <p>
+        Collection
+      </p>
+    </td>
+    <td style="border:none;">
+      <img src="{@docRoot}images/gp-about-picks3.jpg">
+      <p>
+        Editors' Choice
+      </p>
+    </td>
+  </tr>
+</table>
+
+<h3 id="collections">
+  App collections
+</h3>
+
+<p>
+  From time to time the editorial staff puts together a collection of apps and
+  games based on a theme or seasonal event. Users frequently use these lists to
+  select apps, attracted by the timeliness of the collection.
+</p>
+
+<p>
+  The editorial staff chooses apps for collection promotions &mdash;
+  high-quality apps that show the best of Android on phones and tablets. The
+  staff also looks for apps that can make an interesting or unique contribution
+  to the collection as a whole.
+</p>
+
+<h3 id="editors-choice">
+  <img style="margin-right:.25em;margin-bottom:.5em;" src=
+  "{@docRoot}images/editorschoice_ann.png"> Editors' Choice
+</h3>
+
+<p>
+  <em>Editors’ Choice</em> is a curated collection of apps that highlights some
+  of the very best apps available on Android. Editors choose these apps for
+  quality and great user interface, long-term popularity and innovative use of
+  Android features.
+</p>
+
+<p>
+  Apps chosen for <em>Editors’ Choice</em> also receive a badge that is
+  displayed wherever the app name is seen in Google Play.
+</p>
+
+<h3 id="top-developer">
+  <img style="margin-right:.25em;margin-bottom:.5em;" src=
+  "{@docRoot}images/topdev_ann.png"> Top Developer
+</h3>
+
+<p>
+  Top Developer is a badge recognizing established, respected developers for
+  their commitment to launching high-quality and innovative apps on Android.
+  The Google Play editorial staff awards a Top Developer badge from
+  time-to-time based on the cumulative work of the developer.
+</p>
+
+<p>
+  The Top Developer badge appears next to the developer name wherever it is
+  displayed in Google Play. The badge means long-term recognition of all of the
+  developer’s apps. It signifies an additional level of trust and confidence
+  users have in a developer’s products.
+</p>
+
+<div class="headerLine">
+  <h1 id="product-detail-pages">
+    Store Listing Pages
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-about-listing.jpg">
+</div>
+
+<p>
+  Your app’s Google Play storefront is its <em>store listing page</em>: a rich
+  and colorful page that lets you promote your app, highlight its ratings and
+  reviews, and show what your app can do.
+</p>
+
+<p>
+  Your store listing is where your users come to find out everything about your
+  app. When they see your app listed in search results, top charts, category
+  listings, and collections, one tap takes them directly to your store listing.
+</p>
+
+<p>
+  Manage your product details page through the <a href=
+  "https://play.google.com/apps/publish/">Google Play Developer Console</a>
+  from any web browser. Sign in to upload or update your brand assets, and
+  enter your product details in the languages of your markets.
+</p>
+
+<p>
+  When you publish, Google Play adds your app’s ratings, reviews, links to your
+  other products, and more. It also makes sure your store listing page looks
+  great on phones, tablets, and in a web browser.
+</p>
+
+<p>
+  You can link web users directly to your product details page from outside
+  Google Play, such as from your web site, an ad campaign, reviews, social
+  media posts, and more. See <a href=
+  "{@docRoot}distribute/tools/promote/linking.html">Linking to Your
+  Products</a> to find out how.
+</p>
+
+<div class="headerLine clearfloat">
+<h1>Related Resources</h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/googleplay"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="4"></div>
+    </div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/about/distribution.jd b/docs/html/distribute/googleplay/about/distribution.jd
deleted file mode 100644
index 8020110..0000000
--- a/docs/html/distribute/googleplay/about/distribution.jd
+++ /dev/null
@@ -1,167 +0,0 @@
-page.title=Distribution Control
-page.metaDescription=Reach the users you want, whenever you want.
-
-@jd:body
-
-<p>Deliver your apps to the users you want, on the devices you want, on <em>your</em> schedule. </p>
-
-<h2 id="instant">Instant publishing, instant updates</h2>
-
-<p>On Google Play, you can publish your products to customers instantly. Just
-upload and configure your product in the <span style="font-weight:500;">Google Play Developer Console</span>
-and press the Publish button&mdash;your app appears in the store listings within
-hours, not weeks.</p>
-
-<p>Once your app is published, you can update it as often as you want. You can
-change prices, configuration, and distribution options at any time through the
-Google Play Developer Console, without needing to update your app
-binary.</p>
-
-<p>Later, as you add features or address code issues, you can publish an updated
-binary at any time. Google Play makes the new version available almost immediately and
-notifies existing customers that an update is ready for download. To streamline
-the rollout across your customer base, Google Play also lets users accept
-automatic updates of your app, so that your updates are delivered and installed
-as soon as you publish them.</p>
-
-
-<h2 id="targeting">Reaching the customers you want</h2>
-
-<div class="figure-right" style="width:400px;">
-<img src="{@docRoot}images/gp-dc-countries.png" class="frame">
-</div>
-
-<p>Google Play does more than connect your app with users&mdash;it helps you
-reach the broadest possible distribution across the Android ecosystem, while
-making sure that your app is only available to the audience that you want to
-reach.</p>
-
-<h3 id="geotargeting">Geographic targeting</h3>
-
-<p>You can use controls in the Google Play Developer Console to easily
-manage the geographic distribution of your apps, without any changes in your
-application binary. You can specify which countries and territories you want to
-distribute to, and even which carriers (for some countries). </p>
-
-<p>When users visit the store, Google Play makes sure that they are in one of
-your targeted countries before downloading your app. You can change your country
-and carrier targeting at any time just by saving changes in the Google Play
-Developer Console.</p>
-
-<div class="figure-right" style="width:400px;">
-<img src="{@docRoot}images/gp-supported-dev-requirements.png" class="frame">
-</div>
-
-<p>To help you market to users around the world, you
-can <a href="{@docRoot}distribute/googleplay/publish/preparing.html#localize">localize
-your store listing</a>, including app details and description,
-promotional graphics, screenshots, and more.</p>
-
-<h3 id="captargeting">Capabilities targeting</h3>
-
-<p>Google Play also lets you control distribution according to device features
-or capabilities that your app depends on. There are several types of
-dependencies that the app can define in its manifest, such as hardware features,
-OpenGL texture compression formats, libraries, Android platform versions, and
-others.</p>
-
-<p>When you upload your app, Google Play reads the dependencies and sets up any
-necessary distribution rules. For technical information about declaring
-dependencies, read <a href="{@docRoot}google/play/filters.html">Filters on 
-Google Play</a>. </p>
-
-<p>For pinpoint control over distribution, Google Play lets you see all of the
-devices your app is available to based on its dependencies (if any). From the
-Google Play Developer Console, you can list the supported devices and
-even exclude specific devices if needed.</p>
-
-<h2 id="stats">Statistics for analyzing installs and ratings</h2>
-
-<p>Once you’ve published your app, Google Play makes it easy to see how it’s
-doing. The Google Play Developer Console gives you access to a variety
-of anonymized statistics and custom charts that show you the app's installation
-performance and ratings.</p>
-
-<p>You can view data and charts for active, daily, and total installs 
-per unique devices or users, as well as upgrades and uninstalls.
-You can also view the app's daily average user rating and its cumulative
-user rating. To help you analyze the data, you can view install
-and ratings statistics across a variety of different dimensions such as Android 
-version, device, country, app version, and carrier.</p>
-
-<div class="figure-left">
-  <img src="{@docRoot}images/gp-dc-stats-mini.png" class="frame">
-</div>
-<p>You can see your app statistics on timeline charts, for
-all metrics and dimensions. At a glance, the charts highlight your app’s
-installation and ratings peaks and longer-term trends, which you can correlate
-to promotions, app improvements, or other factors. You can even focus in on
-data inside a dimension by highlighting specific data points (such as
-individual platform versions or languages) on the timeline.</p>
-
-<p>So that you can “take your data with you”, you can download all of your
-installation data as a CSV file for viewing in the business program of your
-choice.</p>
-
-
-<h2 id="advanced">Advanced delivery options</h2>
-
-<p>Google Play offers convenient options for managing how your apps are
-delivered to users.</p>
-
-<h3 id="abc">Alpha and beta testing, staged rollouts</h3>
-
-<p>It's always valuable to get real-world feedback from users, especially before
-launch. Google Play makes it easy to distribute pre-release versions of your app
-to alpha and beta test groups anywhere in the world. You can start with a small
-group of alpha testers, then move to a larger group of beta testers. Once users
-are added, they access your app's store listing and install the app. User
-feedback from alpha and beta testers goes directly to you and is not posted as
-public reviews. </p>
-
-<p>To help you ensure quality and protect your app ratings, you can choose a
-staged rollout when launching an app or an update. With staged rollout, you
-distribute the production version of your app to a percentage of users. You can
-adjust the percentage as you go, starting small and increasing until your app is
-available to all users.</p>
-
-<h3 id="multiple-apk">Multiple APK support</h3>
-
-<p>In most cases, it’s easy to create an app that supports all of your targeted
-screen sizes and platform versions from a single APK. Distributing a single APK
-to all of your users is a highly recommended approach, because it’s the easiest
-way to manage and maintain the app. If you need to deliver a different APK to
-devices, Google Play provides a way to do that. </p>
- 
-<p>An option called Multiple APK support lets you create multiple APK packages
-that use the same package name but differ in their OpenGL texture compression
-formats, screen-size support, or Android platform versions supported. You can
-upload all of the APKs to Google Play under a single product listing and Google
-Play selects the best APK to deliver to users, based on the characteristics of
-their devices.  </p>
-
-<p>The APK Expansion Files option lets you upload up to two secondary downloads
-for each published APK, including multiple APKs. Each of the two expansion files
-can be up to 2GB each and can contain any type of code or assets. When you
-upload the expansion files, Google Play hosts them for free and handles the
-download of the files as part of the normal APK installation.</p>
-
-<h2 id="licensing">Protecting your app</h2>
-
-<p>Google Play provides two key features to help you protect your application
-against piracy &mdash; Google Play Licensing and app encryption.</p>
-
-<p> Google Play Licensing is a network-based service that you implement in your
-app. The service lets your app query a trusted licensing server at runtime, to
-determine whether the app is licensed to the current device user. You can use
-the licensing service to protect any app, even apps that you distribute for
-free. For an overview of the service, see <a
-href="{@docRoot}google/play/licensing/index.html">Application
-Licensing</a>.</p>
-
-<p>Additionally, Google Play offers app encryption to help protect your priced
-apps. When delivering your priced apps to devices running Android 4.1 or higher,
-Google encrypts the app binary so that it can be run only by the user who
-downloaded it, on the device to which it was originally downloaded. Your priced
-apps benefit from app encryption automatically &mdash; there's no extra
-development work or configuration needed.</p>
diff --git a/docs/html/distribute/googleplay/about/monetizing.jd b/docs/html/distribute/googleplay/about/monetizing.jd
deleted file mode 100644
index 9a5c6d7..0000000
--- a/docs/html/distribute/googleplay/about/monetizing.jd
+++ /dev/null
@@ -1,162 +0,0 @@
-page.title=Flexible Monetizing and Business Tools
-page.metaDescription=
-
-@jd:body
-   
-<div style="float:right;margin-left:18px;padding:1.5em;">
-<img src="{@docRoot}images/gp-details-ww.png" style="width:180px">
-<img src="{@docRoot}images/gp-details-ww-purchase.png" style="width:180px">
-</div>
-    
-<p>Sell your app in more than 130 countries. Flexible monetization options with
-in-app purchase, subscriptions, and more. </p>
-
-<h2>Streamlined purchase flow for users</h2>
-
-<p>When users find your app, they can purchase it instantly with a streamlined,
-consistent purchasing process and convenient payment methods.</p>
-
-<h3>Instant purchase from device or web</h3>
-
-<p>Google Play makes it fast and easy for your customers to buy your products,
-whether from a phone, a tablet, or a desktop computer. When users find an app or
-game that they want to buy, they can purchase it in as few as two steps&mdash;one
-to initiate the purchase and another to accept purchase details and permissions
-and complete the transaction.</p>
-
-<p>Google Play's convenient purchase experience is the same familiar process for
-all products everywhere across Google Play&mdash;apps, games, in-app products and
-subscriptions, and other digital content.</p>
-
-<h3 id="cloud-connected-purchase">Cloud-connected</h3>
-
-<p>Purchasing is even more convenient on Google Play because it’s
-cloud-connected. Users can find and purchase your products from anywhere&mdash;from
-their Android phones or using any web browser on any host computer. </p>
-
-<p>When users find an app or game they want to buy, they purchase it and download
-it instantly to their devices over-the-air. Users who sign in to the Google Play web site can also buy apps and games
-and push them instantly to their phones, tablets, or other devices. Google Play
-manages the application download.</p>
-
-<h3 id="payment-methods">Convenient payment options</h3>
-
-<p>Users can purchase your products on Google Play using several convenient
-payment methods&mdash;credit cards, Direct Carrier Billing, gift cards, and Google Play balance.</p>
-
-<p><span style="font-weight:500">Credit card</span> is the most common method of payment. Users can pay using any credit card
-that they’ve registered in Google Play. To make it easy for users to get started,
-registration is offered as a part of initial device setup process.</p>
-
-<div class="sidebox-wrapper" style="float:right;">
-<div class="sidebox">
-<h2>Payment methods on Google Play</h2>
-<ul>
-<li>Credit card</li>
-<li>Direct Carrier Billing</li>
-<li>Gift card</li>
-<li>Google Play balance (stored value)</li>
-</ul>
-</div>
-</div>
-
-<p>Subscribers on many popular carrier networks worldwide can charge purchases
-to their monthly mobile phone bills through <span style="font-weight:500">Direct
-Carrier Billing</span>. This form of payment is convenient and simple and is
-extremely popular in regions where credit cards are less common. More than 75
-million users in key markets around the world can purchase
-your products through Direct Carrier Billing. Many more will get the option in
-the months ahead.</p>
-
-<p><span style="font-weight:500">Google Play balance</span> is a stored account
-balance in Google Play. Users can increase their balance through promotions and
-offers in the store, and they can use their balanace to make purchases of apps,
-games, or other content. 
-
-<p>The payment methods available to users worldwide may vary, based on
-location, carrier network, and other factors.</p>
-
-<div style="float:left;margin-right:2em;margin-top:3em;margin-bottom:1em;width:220px;">
-<img src="{@docRoot}images/gp-subs.png" style="width:220px">
-</div>
-
-<h2 id="billing-models" style="margin-top:1.5em;">Choice of billing models</h2>
-
-<p>Google Play gives you a choice of billing models to let you monetize your
-products. </p>
-
-<p>You can offer apps to all users for free, or
-you can set an initial price for the app, paid before download. You can also
-sell one-time purchases and auto-renewing subscriptions from inside the app, and
-you can take advantage of AdMob integration to monetize your app through
-targeted advertising.</p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>Billing models on Google Play</h2>
-<ul>
-<li>Free (no charge to download)</li>
-<li>Priced (user charged before download)</li>
-<li>In-app products and subscriptions</li>
-</ul>
-</div>
-</div>
-
-<p>You can combine these billing models in different ways, based on your business
-needs or market conditions. </p>
-
-<p>For example, you can use a freemium or ad-supported model by distributing
-your app for free and selling in-app products or advertising. Alternatively you
-could set a nominal price for your app at download and sell value add-ons,
-gameplay levels, and upgrades as in-app products. The only restriction is that
-free apps must remain free (to download) for the life of the app.</p>
-
-<p>For details about in-app products or subscriptions,
-see <a href="{@docRoot}google/play/billing/index.html">Google Play In-app Billing</a>.</p>
-
-<h2 id="buyer-currency" style="margin-top:1.5em;">Flexible pricing in the currencies of your customers</h2>
-
-<div class="figure-right" style="width:250px;">
-<img src="{@docRoot}images/gp-buyer-currency.png" class="frame">
-</div>
-
-<p>Google Play gives you complete control over how you price your products. You
-can set prices in more than 130 countries, for millions of
-users around the world. When users browse your app’s product page or initiate a
-purchase, Google Play shows them the price they will be charged <em>in
-their local currency</em>.</p>
-
-<p>You can set and adjust your prices at any time, in any available currency. 
-Your prices in available currencies are independent, so you can adjust one
-price without affecting others. This gives you the ability to run
-short-term promotions and discounts in specific countries and more easily
-manage shifts in exchange rates.</p>
-
-<p>You can set and manage prices for your apps and in-app products from the
-Google Play Developer Console.</p>
-
-<h2 id="payouts">Monthly payouts in your local currency</h2>
-
-<p>To sell products in Google Play, all you have to do is register for a Google
-Wallet merchant account and link it to your Google Play Android Developer
-Console account (see <a
-href="{@docRoot}distribute/googleplay/publish/register.html">Get Started with
-Publishing</a> for details). Once you’ve set up your account and published your
-apps, Google Play makes monthly payouts of sales proceeds to your merchant
-account, in your local currency.</p>
-
-<h2 id="reporting">Detailed financial reporting</h2>
-
-<p>When you sell priced apps or in-app products on Google Play, you get a
-variety of financial reports to help you track and project sales, optimize your
-marketing campaigns, and support your customers.</p>
-
-<p>To help you keep up-to-date with the current activity, you can download daily
-reports summarizing recent purchases of your products. The reports include
-estimated sales amounts and include a variety of other data for each
-transaction.</p>
-
-<p>At the close of the month, you can download a complete sales report that
-gives you the final details of all transactions that closed in the month,
-including the payout amounts and other data. Additional financial reports are
-available in your Google Wallet merchant account.</p>
diff --git a/docs/html/distribute/googleplay/about/visibility.jd b/docs/html/distribute/googleplay/about/visibility.jd
deleted file mode 100644
index 18f60e9..0000000
--- a/docs/html/distribute/googleplay/about/visibility.jd
+++ /dev/null
@@ -1,246 +0,0 @@
-page.title=Visibility for Your Apps
-page.metaDescription=
-
-@jd:body
-    
-<div style="float:right;margin:0px 0px 24px 0px;">
-  <img src="{@docRoot}images/gp-tab.png" style="width:420px" alt="" />
-</div>
-
-<p>A billion downloads a month and growing. Get your apps in front of millions
-of users at Google's scale. </p>  
-
-
-<h2 id="reach">Worldwide reach, rapid growth</h2>
-
-<p>Google Play is the premier store for distributing Android apps. It’s
-preinstalled on more than 400 million devices worldwide, a number growing by
-more than a million every day. Android users have downloaded
-more than <strong style="text-wrap:none;">25 billion apps</strong> from Google
-Play, growing at a rate of more than 1.5 billion per month.</p>
-
-<p>When you publish on Google Play, you put your apps in front of Android's huge
-base of active customers, in more than 130 countries and territories across the
-world. </p>
-
-<p>Google Play is a central part of the Android experience. New users
-personalize their devices with apps, games, and other Google Play content.
-Existing users return regularly to see what's trending and new. Downloading new
-apps is extremely convenient and fast&mdash; Google Play pushes  apps to the
-user's devices instantly, over the air. No cable or sync is ever needed.</p>
-
-<div style="float:left;margin:0px 20px 0px 0px;width:374px;">
-<div  style="width:378px;padding:2px;">
-<img src="{@docRoot}images/gp-growth-downloads.png" style="width:600px;margin-bottom:0em;">
-</div>
-<p class="image-caption" style="padding:.5em"><span
-style="font-weight:500;">Growth in app consumption</span>: Users download more than
-1.5 billion apps from Google Play each month.</p>
-</div>
-
-<div>
-<p>Google Play is also a top destination for visitors from the web. Anyone
-with a browser can explore everything that Google Play has to offer from its <a
-href="http://play.google.com/store">web site</a>. Android users can even buy and
-install the apps they want and Google Play pushes them automatically to their
-devices over the air. </p>
-
-<p>The accessiblility and convenience of the Google Play web
-site give you new ways to drive traffic to your products from online ads, web
-search, cross-linking, and more.</p>
-</div>
-
-   <div style="clear:both;">
-<h2>Built for app discovery</h2>
-
-<p>Google Play is designed to connect users with great apps and games. It
-provides key channels to help your app get noticed and gain traction in the
-marketplace.</p>
-
-<h3 id="ratings">User ratings and reviews</h3>
-
-<p>When you develop a great app, Android users show their appreciation through
-ratings and reviews. They rate your app (out of 5 stars) after downloading it
-and can post a short description of their experience. When other users are
-considering your app, they look at the ratings and reviews as key benchmarks of
-the app’s quality. </p>
-
-   </div>
-
-<p>Your app’s rating is one of the most important factors influencing its
-ranking in the various lists and search results in Google Play. It's also one of
-the key signals that the editorial staff looks for, when curating apps and games
-for promotion in the store.</p>
-
-<div style="border:1px solid #DDD;padding:1px;margin-left:110px;width:504px;">
-<img src="{@docRoot}images/gp-rating-web.png" style="width:500px;padding:0;margin:0;">
-</div>
-
-<h3 id="category" stdle="padding-top:2em;">Category browsing</h3>
-
-<p>When you publish an app in Google Play, you pick the category in which you
-want users to find your app. More than 30 categories are available. Inside each
-category, apps are ranked based on a combination of ratings, reviews, downloads,
-country, and other factors. Many popular categories also start with a collection
-of featured apps selected by the Google Play editorial staff.</p>
-
-<div style="clear:both;margin-top:2em;margin-left:10%;width:560px;">
-<div style="clear:both;margin-top:2em;">
-<img src="{@docRoot}images/gpp-cat-feature280-puzzle.png" style="width:180px">
-<img src="{@docRoot}images/gpp-cat-feature280-photo.png" style="width:180px">
-<img src="{@docRoot}images/gpp-cat-feature280-sports.png" style="width:180px">
-</div>
-<p class="image-caption"><span style="font-weight:500;">Featuring in
-categories</span>: Most app and game categories include a featured list curated
-by the editorial team.</p>
-</div>
-
-<h3 id="search">Search</h3>
-
-<p>Search on Google Play lets users pinpoint an app or game quickly. Search uses
-powerful heuristics to suggest terms as the user types, and it offers direct
-links to apps as suggestions. In results, users find the most relevant, most
-popular apps at the top. </p>
-
-<div style="float:left;margin:12px 24px 0px 0px;">
-<img src="{@docRoot}images/gp-top-new-paid.png" style="width:250px">
-</div>
-
-<h3 id="top-charts" style="padding-top:1em">Top charts and lists</h3>
-
-<p>Top charts keep users in touch with what’s popular and trending with Android
-users, right from the Apps and Games home pages. The charts are generated
-several times each day based on recent download activity, keeping them fresh and
-allowing new apps to move upward in the charts. To make the charts as relevant
-as possible for users across the world, they are also country-specific in
-Google Play's most popular countries.</p>
-
-<p>As your apps get traction and build momentum in downloads and ratings,
-they’ll climb one or more of the top charts and gain even more exposure.</p>
-
-<div>
-<table style="width:440px">
-<tr>
-<td style="width:100px">Top Free</td><td>Free apps and games</td></tr>
-<td style="width:140px">Top Paid</td><td>Priced apps and games</td></tr>
-<td>Top New Free</td><td>Less than 30 days old</td></tr>
-<td>Top New Paid</td><td>Less than 30 days old</td></tr>
-<td>Top Grossing</td><td>Gross proceeds, free or priced</td></tr>
-<td>Best Selling</td><td>Popular priced games</td></tr>
-<td>Trending</td><td>New arrivals growing quickly in installs</td>
-</tr>
-</table>
-</div>
-
-<div style="clear:both">
-<h4 id="featured" style="padding-top:2.5em;">Featured, Staff Picks, Collections,
-and Badges</h4>
-
-
-<div style="float:right;margin-left:18px;">
-<img src="{@docRoot}images/gp-apps-home.png" style="width:180px">
-<img src="{@docRoot}images/gp-games-home.png" style="width:180px">
-</div>
-
-<p>The Google Play editorial team is dedicated to bringing the best apps to the
-attention of users and setting the tone for app quality throughout the store. 
-It constantly reviews apps from across Google Play to find
-not only the best-known apps and games, but also the “diamonds in the rough” that
-they want more people to see. </p>
-
-<p>When the team finds great apps and games, it uses the <em>Featured</em>,
-<em>Staff Picks</em>, and other collections to promote them to users.</p>
-
-<p>You can't nominate your app for featuring, but the team is always
-on the lookout for great apps through a number of signals and indicators. 
-If you build an app that users love and that looks great on Android devices,
-the editorial team will notice.</p>
-</div>
-
-<h4>Featured and Staff Picks</h4>
-
-<p>Each week the Google Play editorial staff selects a new set of apps to
-promote in its popular <em>Featured</em> and <em>Staff Picks</em> collections.
-</p>
-
-The <em>Featured</em> collections highlight the latest and greatest app and game
-titles available for Android. Category featuring highlights the best and most
-popular apps in the top categories.
-
-<em>Staff Picks</em> collects all recently featured apps and games on Google
-Play. To better reach tablet users, there’s a special <em>Staff Picks</em>
-collection that highlights the best apps for Android tablets.</p>
-
-<div style="float:left;margin-right:18px;">
-<img src="{@docRoot}images/gp-collectibles.png" stydle="width:180px">
-
-</div>
-
-<h4>App collections</h4>
-
-<p>From time to time the editorial staff puts together a collection of apps and
-games based on a theme or seasonal event. The collections are popular with
-customers because they are timely and relevant, and they provide a new way to
-showcase great Android apps to users.</p>
-
-<p>The editorial staff chooses apps for collection promotions in a similar way
-as for featuring&mdash;high-quality apps that show the best of Android on phones
-and tablets. For collections the staff also looks for apps that can make an
-interesting or unique contribution to the collection as a whole. </p>
-
-<h4><img style="margin-right:.25em;margin-bottom:.5em;"
-src="{@docRoot}images/editorschoice_ann.png"> EDITORS' CHOICE</h4>
-
-<p><em>Editors’ Choice</em> is a curated collection of apps that highlights some
-of the very best apps available on Android. These apps are chosen for high
-quality and great UI, long-term popularity, and innovative use of Android
-features.</p>
-
-<p>Apps chosen for <em>Editors’ Choice</em> also receive a badge that is
-displayed wherever the app name is seen in Google Play.</p>
-
-<h4><img style="margin-right:.25em;margin-bottom:.5em;"
-src="{@docRoot}images/topdev_ann.png"> TOP DEVELOPER</h4>
-
-<p>Top Developer is a badge recognizing established, respected developers for
-their commitment to launching high-quality and innovative apps on
-Android. The Google Play editorial staff selects developers awards a Top
-Developer badge from time to time, based on the cumulative work of the
-developer.</p>
-
-<p>The Top Developer badge appears next to the developer name wherever it is
-displayed in Google Play. For a developer, the badge means long-term recognition
-of all of your apps. For users, the badge signifies an additional level of trust
-and confidence in your products.</p>
-
-<h3 id="details">Rich, colorful product pages</h3>
-
-<p>In Google Play, your app’s storefront is its <em>product details page</em>
-&mdash; a rich and colorful page that lets you promote your app, highlight its
-ratings and reviews, and show what your app can do. 
-
-<p>Your product details page is the one page where your users come to find out
-everything about your app. When they see your app listed in search results, top
-charts, category listings, and collections, one tap takes them directly to your 
-product details page.</p>
-
-<div style="float:right;margin-left:10px;">
-<img src="{@docRoot}images/gp-details-pages-magicpiano.png" style="width:500px">
-</div>
-
-<p>You can manage your product details page through the <span
-style="font-weight:500">Google Play Android Develeper Console</span>, from any
-web browser. Just sign in, upload or update your brand assets, and enter your
-product details in the languages of your markets. </p>
-
-<p>When you publish, Google Play adds your app’s ratings, reviews, links to your
-other products, and more, and makes sure your product details page looks great
-on phones, tablets, or in a web browser.</p>
-
-<p>You can link web users directly to your product details page from outside
-Google Play, such as from your web site, an ad campaign, reviews, social media
-posts, and more. See <a href="{@docRoot}distribute/googleplay/promote/linking.html">Linking
-to Your Products</a> to find out how. </p>
-
-<p>To learn more about how to create your product details page, see
-<a href="{@docRoot}distribute/googleplay/publish/index.html">Publishing on Google Play</a>.</p>
diff --git a/docs/html/distribute/googleplay/developer-console.jd b/docs/html/distribute/googleplay/developer-console.jd
new file mode 100644
index 0000000..6263431
--- /dev/null
+++ b/docs/html/distribute/googleplay/developer-console.jd
@@ -0,0 +1,600 @@
+page.title=Developer Console
+page.metaDescription=Learn about the Developer Console, your home for app publishing on Google Play.
+page.image=/distribute/images/developer-console.jpg
+Xnonavpage=true
+
+@jd:body
+    
+    <div id="qv-wrapper">           
+  <div id="qv">
+    <h2>Publishing Features</h2>
+    <ol>
+      <li><a href="#allapps">All Applications</a></li>
+      <li><a href="#account-details">Your Account Details</a></li>
+      <li><a href="#merchant-account">Linking Your Merchant Account</a></li>
+      <li><a href="#multiple-user-accounts">Multiple User Accounts</a></li>
+      <li><a href="#alpha-beta">Alpha and Beta Testing</a></li>
+      <li><a href="#staged-rollouts">Staged Rollouts</a></li>
+      <li><a href="#multiple-apk">Multiple APK Support</a></li>
+      <li><a href="#selling-pricing-your-products">Selling and Pricing</a></li>
+      <li><a href="#in-app-products">In-App Products</a></li>
+      <li><a href="#distribution-controls">Distribution Controls</a></li>
+      <li><a href="#reviews-reports">User Reviews, Crash Reports</a></li>
+      <li><a href="#app-stats">App Stats</a></li>
+      <li><a href="#related-resources">Related Resources</a></li>
+    </ol>
+  </div>
+</div>
+
+<p>
+  The <a href="https://play.google.com/apps/publish/">Google Play Developer
+  Console</a> is your home for publishing operations and tools.
+</p>
+<!-- <img src="{@docRoot}images/gp-dc-startscreen.jpg" style="width:480px;" /> -->
+<img src="{@docRoot}images/gp-devconsole-home.png" style="width:480px;">
+<p>
+  Upload apps, build your product pages, configure prices and distribution, and
+  publish. You can manage all phases of publishing on Google Play through the
+  Developer Console, from any web browser.
+</p>
+
+<p>
+  Once you've <a href=
+  "{@docRoot}distribute/googleplay/start.html">registered</a> and received
+  verification by email, you can sign in to your Google Play Developer Console.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="allapps">
+    All Applications
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Start in All Applications, which gives you a quick overview of your apps,
+  lets you jump to stats, reviews, and product details, or upload a new app.
+</p>
+
+<div style="padding:1em 0em 0em 0em;">
+  <img src="{@docRoot}images/gp-dc-home.png" class="border-img">
+</div>
+
+<div class="headerLine clearfloat" style="margin-top:-6px">
+  <h1 id="account-details">
+    Your Account Details
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Specify basic developer profile information about yourself or your company on
+  the accounts detail page. This identifies you to Google Play and your
+  customers. You can go back at any time to edit the information and change
+  your settings.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-dc-profile.png" class="frame">
+</div>
+
+<p>
+  Your developer profile contains:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Developer name &mdash; displayed on your store listing page and elsewhere
+      on Google Play.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Contact information &mdash; used by Google only, it isn't seen by your
+      customers.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Web site URL &mdash; displayed on your store listing page.
+    </p>
+  </li>
+</ul>
+
+<p>
+  On the account details page you can also add restricted access for marketers
+  and other teams, register for a merchant account, or set up test accounts for
+  Google Play licensing.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="merchant-account">
+    Linking Your Merchant Account
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  If you want to sell apps or in-app products, link your Google Wallet Merchant
+  Account to your developer profile. Google Play uses the linked merchant
+  account for financial and tax identification, as well as for monthly payouts
+  from sales.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="multiple-user-accounts">
+    Multiple User Accounts
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Set up user accounts for other team members to access different parts of your
+  Developer Console.
+</p>
+
+<div style="width:550px;">
+  <img src="{@docRoot}images/gp-dc-invite.png" class="frame">
+</div>
+
+<p>
+  The first account registered is the <em>account owner</em>, with full access
+  to all parts of the console. The owner can add <em>user accounts</em> and
+  manage console access.
+</p>
+
+<p>
+  For example, an owner can grant users access to publishing and app
+  configuration, but not to financial reports. Learn how to <a href=
+  "https://support.google.com/googleplay/android-developer/answer/2528691">set
+  up multiple accounts</a> now.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="store-listing-details">
+    Store Listing Details
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Use the Developer Console to set up a <em>Store Listing page</em>. This is
+  the home for your app in Google Play. It's the page users see on their mobile
+  phones or on the web to learn about your app and download it.
+</p>
+
+<p>
+  Upload custom brand assets, screenshots, and videos to highlight what's great
+  about your app. Provide a localized description, add notes about the latest
+  version, and more. You can update your store listing at any time.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-dc-details.png" class="frame">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="upload-instantly-publish">
+    Upload and Instantly Publish
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  From the Developer Console you can quickly upload and publish a release-ready
+  Android application package file. The app is a <em>draft</em> until you
+  publish it, at which time Google Play makes your store listing page and app
+  available to users&mdash;your app appears in the store listings within hours,
+  not weeks.
+</p>
+
+<p>
+  Once your app is published, you can update it as often as you want: Change
+  prices, configuration, and distribution options at any time, without needing
+  to update your app binary.
+</p>
+
+<p>
+  As you add features or address code issues, you can publish an updated binary
+  at any time. The new version is available almost immediately and existing
+  customers are notified that an update is ready for download. Users can also
+  accept automatic updates to your app, so that your updates are delivered and
+  installed as soon as you publish them. You can unpublish your apps app at any
+  time.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="alpha-beta">
+    Alpha and Beta Testing
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  It's always valuable to get real-world feedback from users, especially before
+  launch. Google Play makes it easy to distribute pre-release versions of your
+  app to alpha and beta test groups anywhere in the world.
+</p>
+
+<p>
+  In the <strong>APK</strong> section of your Google Play Developer Console
+  you’ll find the <strong>Alpha Testing</strong> and <strong>Beta
+  Testing</strong> tabs. Here you can upload versions of your apps’ APK files
+  and define a list of testers as a <a href=
+  "https://support.google.com/groups/answer/46601">Google Group</a> or <a href=
+  "https://support.google.com/plus/topic/2888488">Google+ Community</a>. Once
+  this is done you’ll receive a URL that you forward to your testers, from
+  which they can opt-in to the testing program.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-dc-ab.png" class="frame">
+</div>
+
+<p>
+  After opting-in, your testers then go to your app’s product page and when
+  they download the app Google Play will deliver them the alpha or beta version
+  as appropriate. Incidentally, if a user happens to be opted-in to both your
+  testing groups, Google Play will always deliver them the alpha test version.
+</p>
+
+<p>
+  Note that users cannot provide feedback and reviews on alpha and beta
+  versions of your apps. To gather feedback you could used the <a href=
+  "https://support.google.com/groups/answer/46601">Google Group</a> or <a href=
+  "https://support.google.com/plus/topic/2888488">Google+ Community</a>, or
+  setup an email address or your own website.
+</p>
+
+<p>
+  You can use these testing programs to <a href=
+  "{@docRoot}distribute/essentials/optimizing-your-app.html">optimize your
+  apps</a>, help with <a href=
+  "{@docRoot}distribute/users/expand-to-new-markets.html">rollout to new
+  markets</a>, and start <a href=
+  "{@docRoot}distribute/users/build-community.html">building your
+  community</a>. There is also more information on using beta test in the
+  <a href="{@docRoot}distribute/tools/launch-checklist.html">Launch
+  Checklist</a> and <a href=
+  "{@docRoot}distribute/tools/localization-checklist.html">Localization
+  Checklist</a>.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="staged-rollouts">
+    Staged Rollouts
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  You can also stage the rollout of your apps using the Production tab in the
+  APK section of your Google Play Developer Console. Here you can define the
+  percentage of user who’ll be able to download your app.
+</p>
+
+<p>
+  Staging your rollout will help limit the impact of unexpected bugs or server
+  load and enable you to gauge user feedback with an unbiased sample of users.
+  Users can rate and review your apps during staged roll outs, so if you’re
+  hesitant, start your rollout to a small percentage of users. Be sure to watch
+  for and respond to any negative reviews.
+</p>
+
+<p>
+  Note that rollbacks aren’t supported due to the <a href=
+  "{@docRoot}tools/publishing/versioning.html">app versioning requirements</a>
+  of the Android platform. If you need to rollback, consider launching a
+  previous APK with a new version number. However, this practice should be used
+  only as a last resort, as users will lose access to new features and your old
+  app may not be forward-compatible with your server changes or data formats,
+  so be sure to run <a href="#alpha-beta">alpha and beta tests</a> of your
+  updates.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="multiple-apk">
+    Multiple APK Support
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  In most cases, a single app package (APK) is all you need, and it’s usually
+  the easiest way to manage and maintain the app. However, if you need to
+  deliver a different APK to different devices, Google Play provides a way to
+  do that.
+</p>
+
+<p>
+  <em>Multiple APK support</em> lets you create multiple app packages that use
+  the same package name but differ in their OpenGL texture compression formats,
+  screen-size support, or Android platform versions supported. You can simply
+  upload all the APKs under a single product listing and Google Play selects
+  the best ones to deliver to users, based on the characteristics of their
+  devices.
+</p>
+
+<p>
+  You can also upload up to two secondary downloads for each published APK,
+  including multiple APKs, using the <em>APK Expansion Files</em> option. Each
+  expansion file can be up to 2GB and contain any type of code or assets.
+  Google Play hosts them for free and handles the download of the files as part
+  of the normal app installation.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="selling-pricing-your-products">
+    Selling and Pricing Your Products
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure-right">
+  <img src="{@docRoot}images/gp-buyer-currency.png" class="frame">
+</div>
+
+<p>
+  You have tools to set prices for your apps and in-app products. Your app can
+  be free to download or priced, requiring payment before download.
+</p>
+
+<ul>
+  <li>If you publish your app as free, it must <strong>remain free for the life
+  of the app</strong>. Free apps can be downloaded by all users in Google Play.
+  </li>
+
+  <li>If you publish it as priced, you can later change it to free. Priced apps
+  can be purchased and downloaded only by users who have registered a form of
+  payment in Google Play.
+  </li>
+</ul>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <p>
+      See <a href=
+      "http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&amp;answer=138294&amp;topic=2365624&amp;ctx=topic">
+      Supported locations for distributing applications</a> for a list of
+      countries where you can distribute or sell your apps.
+    </p>
+  </div>
+</div>
+
+<p>
+  You can also offer in-app products and subscriptions, whether the app is free
+  or priced. Set prices separately for priced apps, in-app products, and
+  subscriptions.
+</p>
+
+<p>
+  When users browse your app product pages or initiate a purchase, Google Play
+  shows them the price they’ll be charged in their local currency.
+</p>
+
+<p>
+  For each product, you initially set a default price in your own currency. If
+  you do no more, Google Play will automatically set local prices once a month
+  based on the US-Dollar price for your app.
+</p>
+
+<p>
+  However, Google Play gives you complete control over how you price your
+  products in each country. To start you can manually set fixed local prices
+  from the default price, using the <strong>auto-convert prices now</strong>
+  feature. You can then review these prices and set new ones for any countries
+  you wish &mdash; the price for each country is independent, so you can adjust
+  one price without affecting others. For most countries, the price you set is
+  the final price charged to users, including taxes.
+</p>
+
+<p>
+  For more on pricing your apps, see <a href=
+  "{@docRoot}distribute/users/expand-to-new-markets.html#localize-your-google-play-listing">
+  Expand into New Markets</a>.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="in-app-products">
+    In-app Products
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  You can sell in-app products and subscriptions using <a href=
+  "{@docRoot}google/play/billing/index.html">Google Play In-app Billing</a> as
+  a way to monetize your apps. In-app products are one-time purchases, while
+  subscriptions are recurring charges on a monthly or annual basis.
+</p>
+
+<p>
+  In the <strong>In-app Products</strong> section for a specific published or
+  draft APK you:
+</p>
+
+<ul>
+  <li>Create product lists for in-app products and subscriptions.
+  </li>
+
+  <li>Set prices.
+  </li>
+
+  <li>Publish the products with the app or withdraw obsolete products.
+  </li>
+</ul>
+
+<p>
+  For details on how to implement In-app Billing, see the <a href=
+  "{@docRoot}google/play/billing/index.html">In-app Billing</a> developer
+  documentation. You make use of in-app products in the <a href=
+  "{@docRoot}distribute/monetize/premium.html">Premium</a>, <a href=
+  "{@docRoot}distribute/monetize/freemium.html">Freemium</a>, and <a href=
+  "{@docRoot}distribute/monetize/subscriptions.html">Subscription</a>
+  monetization models
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="distribution-controls">
+    Distribution Controls
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Manage which countries and territories your apps will distribute to. For some
+  countries, you can choose which carriers you want to target. You can also see
+  the list of devices your app is available for, based on any distribution
+  rules declared in its manifest file.
+</p>
+
+<h3 id="geotargeting">
+  Geographic targeting
+</h3>
+
+<p>
+  You can use controls in the Google Play Developer Console to easily manage
+  the geographic distribution of your apps, without any changes in your
+  application binary. You can specify which countries and territories you want
+  to distribute to, and even which carriers (for some countries).
+</p>
+
+<p>
+  When users visit the store, Google Play makes sure that they are in one of
+  your targeted countries before downloading your app. You can change your
+  country and carrier targeting at any time just by saving changes in the
+  Google Play Developer Console.
+</p>
+
+<div class="figure-right" style="width:500px;">
+  <img src="{@docRoot}images/gp-supported-dev-requirements.png" class="frame">
+</div>
+
+<p>
+  To help you market to users around the world, you can <a href=
+  "{@docRoot}distribute/tools/launch-checklist.html#start-localization">localize
+  your store listing</a>, including app details and description, promotional
+  graphics, screenshots, and more.
+</p>
+
+<h3 id="captargeting">
+  Capabilities targeting
+</h3>
+
+<p>
+  Google Play also lets you control distribution according to device features
+  or capabilities that your app depends on. There are several types of
+  dependencies that the app can define in its manifest, such as hardware
+  features, OpenGL texture compression formats, libraries, Android platform
+  versions, and others.
+</p>
+
+<p>
+  When you upload your app, Google Play reads the dependencies and sets up any
+  necessary distribution rules. For technical information about declaring
+  dependencies, read <a href="{@docRoot}google/play/filters.html">Filters on
+  Google Play</a>.
+</p>
+
+<p>
+  For pinpoint control over distribution, Google Play lets you see all of the
+  devices your app is available to based on its dependencies (if any). From the
+  Google Play Developer Console, you can list the supported devices and even
+  exclude specific devices if needed.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="reviews-reports">
+    User Reviews and Crash Reports
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure-right" style="width:500px;">
+  <img src="{@docRoot}images/gp-dc-reviews.png" class="frame">
+  <p class="img-caption">
+    The User reviews section gives you access to user reviews for a specific
+    app. You can filter reviews in a number of ways to locate issues more
+    easily and support your customers more effectively.
+  </p>
+</div>
+
+<p>
+  Google Play makes it easy for users to submit reviews of your app for the
+  benefit of other users. The reviews give you usability feedback, support
+  requests, and details of important functionality issues direct from your
+  customers.
+</p>
+
+<p>
+  Use crash reports for debugging and improving your app. You can see crash
+  reports with stack trace and other data, submitted automatically from Android
+  devices.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="app-stats">
+    App Statistics
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure" style="width:500px">
+  <img src="{@docRoot}images/gp-dc-stats.png">
+  <p class="img-caption">
+    <b>App statistics page</b>: Shows you a variety of statistics about a
+    specific app's installation performance.
+  </p>
+</div>
+
+<p>
+  You get detailed statistics on the install performance of your app.
+</p>
+
+<p>
+  See installation metrics measured by unique users as well as by unique
+  devices. View active installs, total installs, upgrades, daily installs and
+  uninstalls, and metrics about ratings.
+</p>
+
+<p>
+  Zoom into the installation numbers by metric, including Android platform
+  version, device, country, language, app version, and carrier. View the
+  installation data for each dimension on timeline charts.
+</p>
+
+<p>
+  These charts highlight your app’s installation peaks and longer-term trends.
+  They help you learn your user’s adoption behavior, correlate statistics to
+  promotions, see the effect of app improvements, and other factors. Focus in
+  on data inside a dimension by adding specific points to the timeline.
+</p>
+
+<div class="dynamic-grid">
+<div class="headerLine clearfloat">
+<h1 id="related-resources">Related Resources</h1><hr/>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/googleplay/developerconsole"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
+  </div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/edu/about.jd b/docs/html/distribute/googleplay/edu/about.jd
index 20a0d4d..3944909 100644
--- a/docs/html/distribute/googleplay/edu/about.jd
+++ b/docs/html/distribute/googleplay/edu/about.jd
@@ -1,103 +1,131 @@
-page.title=About Google Play for Education
-page.metaDescription=How Google Play for Education helps you reach a new audience of educators.
-excludeFromSuggestions=true
+page.title=Google Play for Education
+page.image=/distribute/images/about-play-education.jpg
+page.metaDescription=Distribute your educational app directly to educators and schools.
+meta.tags="gpfe, googleplay, distribution, edu"
+page.tags="education"
+Xnonavpage=true
+
 @jd:body
 
-    <div style="position:absolute;margin-left: 636px;
-            margin-top:-76px;color:#777;">If you're interested<br>
-            <a href="{@docRoot}distribute/googleplay/edu/contact.html"
-            class="go-link"
-            style="display: block;text-align: right;">SIGN UP</a></div>
+<p>
+  Google Play for Education is an extension of Google Play designed for
+  schools. Here educators can discover apps approved by teachers for teachers,
+  as well as educational videos and a collection of classic books for their
+  classroom.
+</p>
 
-    <div style="float:right;margin:0px 0px 24px 44px;">
-  <img src="{@docRoot}images/gp-edu-apps-n7.jpg" style="width:420px" alt="" />
-</div>
+<p>
+  Teachers can search for approved apps by grade, subject and standard,
+  including Common Core State Standards. They can bulk purchase and pay using a
+  purchase order, then instant distribution let educators bring your apps
+  directly to classrooms and schools.
+</p>
 
-<p>Introducing Google Play for Education, the online destination where schools
-can find the right tablet content and tools for their students and teachers.</p>
 
-<p>With easy bulk ordering for groups, schools can purchase and
-instantly distribute your apps, and videos right to their students’
-devices.</p>
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/googleplay/gpfe/highlight"
+  data-sortOrder="-timestamp"
+  data-cardSizes="18x6,"
+  data-maxResults="1"></div>
 
-<p>Google Play for Education can help your innovative educational apps
-gain visibility with the right audiences, without having to knock on school doors. </p>
 
-<p><a class="landing-page-link" style="text-align:right;" href="#video">Watch a Video</a></p>
+<!-- <div class="center-img"><img src="{@docRoot}images/gp-edu-hero14.jpg" class="" /></div> -->
 
-<div class="landing-docs">
-  <div class="col-6 normal-links">
-    <h3 style="clear:left">For Developers</h3>
+<p>
+  If you have an educational app, include it in Google Play for Education.
+  Google Play for Education can help your innovative educational apps gain
+  visibility with the right audiences, without having to knock on school doors.
+</p>
 
-<h4>Get discovered</h4>
+<div style="margin:30px 0 20px 0;" class="clearfloat dynamic-grid">
+  <div style="width:48%; margin-right:2%; float:left;">
+    <div class="centered-full-image">
+      <img src="{@docRoot}images/gpfe-developer.png">
+    </div>
 
-<p>With Google Play for Education, teachers and administrators can
-browse content by curriculum, grade, and standard &mdash; discovering the right
-content for their students. If your app offers an exciting new
-way to learn sixth grade algebra, math educators will be able to find,
-purchase, and distribute your app to their classes in a few clicks.</p>
-
-<h4>Reach more schools and students</h4>
-
-<p>Over 30 million students, faculty, and staff are already using
-Google Apps for Education and other Google services. Many of these schools are
-excited to take advantage of tablets with Google Play for Education and they
-look to bringing your apps into their classrooms,
-especially apps using Google sign-on.</p>
-
-<h4>Monetize effectively</h4>
-<p>With Google Play for Education, educators are able to make high-volume purchases
-using standard institutional payment mechanisms and distribute them to the students
-they want &mdash; whether it is a class of 20 or a district of 20,000.</p>
-<code></code>
+    <h3>
+      FOR DEVELOPERS
+    </h3>
+    <b>Get discovered</b>
+    <p>
+      With Google Play for Education, teachers and administrators can browse
+      content by curriculum, grade, and standard &mdash; discovering the right
+      content for their students. If your app offers an exciting new way to
+      learn sixth grade algebra, math educators will be able to find, purchase,
+      and distribute your app to their classes in a few clicks.
+    </p>
+    <b>Reach more schools and students</b>
+    <p>
+      Millions of students, faculty, and staff are using Google Apps for
+      Education and other Google services. Many of these schools are excited to
+      take advantage of tablets with Google Play for Education and they are
+      looking to bring your apps into their classrooms, especially apps using
+      Google sign-on.
+    </p>
+    <b>Monetize effectively</b>
+    <p>
+      With Google Play for Education, educators are able to make high-volume
+      purchases using standard institutional payment mechanisms and then
+      distribute apps to the students who need them — whether it’s a class of
+      20 or a district of 20,000.
+    </p>
   </div>
 
-  <div class="col-6 normal-links">
-    <h3 style="clear:left">For Educators</h3>
-    <h4>Android tablets in the classroom</h4>
-    <p>Google Play for Education brings the innovation of Android technology
-into classrooms. School districts can set up and deploy large numbers of devices in
-just minutes or hours rather than days.</p>
+  <div style="width:48%; margin-left:2%; float:left;">
+    <div class="centered-full-image">
+      <img src="{@docRoot}images/gpfe-educator.png">
+    </div>
 
-    <h4>Curriculum-based discovery</h4>
-    <p>Powerful browsing tools let educators quickly discover apps,
-videos, and other content&mdash;with many recommended by teachers and
-categorized according to familiar Core Curriculum standards.  
-
-    <h4>Bulk purchase with institutional payment</h4>
-    <p>Convenient purchasing and delivery tools let educators buy apps in bulk
-using purchase orders and other payment methods that are easy for schools to
-manage.</p>
-
-    <h4>Over-the-air delivery to student devices</h4>
-
-      <p>After finding apps they want to use, educators can push them instantly
-to student devices over the air. They can send the apps to individuals or groups
-of any size, across classrooms, schools, or even districts. </p>
-
+    <h3>
+      FOR EDUCATORS
+    </h3>
+    <b>Android tablets in the classroom</b>
+    <p>
+      Google Play for Education brings the innovation of Android technology
+      into classrooms. School districts can set up and deploy large numbers of
+      devices in just minutes or hours, rather than days.
+    </p>
+    <b>Curriculum-based discovery</b>
+    <p>
+      Powerful browsing tools let educators quickly discover apps, videos, and
+      other content—with many recommended by teachers and categorized according
+      to familiar Core Curriculum standards.
+    </p>
+    <b>Bulk purchase with institutional payment</b>
+    <p>
+      Convenient purchasing and delivery tools let educators buy apps in bulk,
+      using purchase orders and other payment methods that are easy for schools
+      to manage.
+    </p>
+    <b>Over-the-air delivery to student devices</b>
+    <p>
+      After finding apps they want, educators can push them instantly to
+      student devices over the air. They can send the apps to individuals or
+      groups of any size, across classrooms, schools, or even districts.
+    </p>
   </div>
-
-
 </div>
-<div id="video" style="background: #F0F0F0;
-            border-top: 1px solid #DDD;
-            padding: 0px 0 24px 0;
-            overflow: auto;
-            clear:both;
-            margin-bottom:40px;
-            margin-top:30px;">
-   <div style="padding:0 0 0 29px;">
-        <h4>Introducing Google Play for Education</h4>
 
-          <div style="width:700px;">
-          <p style="margin-top:26px;
-                    margin-bottom:12px;">
-          Hear how Google Play for Education works and how developers can leverage the unique business opportunities in creating educational apps for the K-12 market. There's a demo at 4m10s.</p>
-           </div>
-           <iframe style="float:left;
-             margin-right:24px;
-             margin-top:14px;" width="700" height="394" src=
-             "http://www.youtube.com/embed/haEmsMo0f3w?HD=1;rel=0;origin=developer.android.com;" frameborder="0" allowfullscreen>
-           </iframe>
-   </div> 
+<div class="headerLine clearfloat">
+<h1>Related Resources</h1><hr>
 </div>
+
+<div class="dynamic-grid">
+
+<h3>For Developers</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+    data-query="collection:distribute/googleplay/gpfe/dev/about"
+    data-sortOrder="-timestamp"
+    data-cardSizes="9x3"
+    data-maxResults="6"></div>
+
+<h3>For Teachers and Educators</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+    data-query="collection:distribute/googleplay/aboutgpfe/educators/about"
+    data-sortOrder="-timestamp"
+    data-cardSizes="9x3"
+    data-maxResults="3"></div>
+
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/edu/contact.jd b/docs/html/distribute/googleplay/edu/contact.jd
index ca83438..042a92b 100644
--- a/docs/html/distribute/googleplay/edu/contact.jd
+++ b/docs/html/distribute/googleplay/edu/contact.jd
@@ -7,32 +7,29 @@
 bring your first-class educational content into schools across the United
 States, and to a broader international audience in the future. </p>
 
-<div class="vspace size-1">
-  &nbsp;
-</div>
 
-<div class="layout-content-row">
-  <div class="layout-content-col span-6">
-    <h4>
-      For Developers
-    </h4>
-    <p>
+<div style="margin:0 0 20px 0;" class="clearfloat dynamic-grid">
+  <div style="width:48%; margin-right:2%; float:left;">
+
+    <h3>
+      FOR DEVELOPERS
+    </h3>
+ <p>
 Whether you have an existing educational app or are developing a fresh idea that
 will unlock learning in the classroom &mdash; sign up to receive information about
-the upcoming launch of Google Play for Education. To get your apps ready, read our
-<a href="{@docRoot}distribute/googleplay/edu/guidelines.html">guidelines</a> for building
-educational apps.</p>
-    </p><a href="http://developer.android.com/edu/signup">Developer Sign Up »</a>
+Google Play for Education. To get your apps ready, read our
+<a href="{@docRoot}distribute/essentials/gpfe-guidelines.html">guidelines for building
+educational apps</a>.</p>
+    </p><a href="http://developer.android.com/edu/signup">Developer Sign Up »</a>    </p>
   </div>
-  <div class="layout-content-col span-6">
-    <h4>
-      For Educators
-    </h4>
-    <p>
+
+  <div style="width:48%; margin-left:2%; float:left;">
+
+    <h3>
+      FOR EDUCATORS
+    </h3>
+     <p>
 If you're a school or system interested in tablets and Google Play for Education,
 complete the expression of interest form at <a href="http://www.google.com/edu/android">www.google.com/edu/android</a>.
-  </p><a href="http://www.google.com/edu/android">School Interest Form »</a>
-  </div>
-</div>
-
-
+  </p><a href="http://www.google.com/edu/android">School Interest Form »</a>  </div>
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/edu/faq.jd b/docs/html/distribute/googleplay/edu/faq.jd
index 0c3b185..0866da5 100644
--- a/docs/html/distribute/googleplay/edu/faq.jd
+++ b/docs/html/distribute/googleplay/edu/faq.jd
@@ -1,372 +1,433 @@
-page.title=Google Play for Education FAQ
-page.metaDescription=Questions and answers about Google Play for Education.
-excludeFromSuggestions=true
+page.title=Education FAQ
+meta.tags="gpfe, edu"
+page.metaDescription=Answers to frequent questions about Google Play for Education.
+page.image=/distribute/images/gpfe-faq.jpg
+
 @jd:body
 
-     <div style="position:absolute;margin-left: 636px;
-            margin-top:-76px;color:#777;">If you're interested<br>
-            <a href="{@docRoot}distribute/googleplay/edu/contact.html"
-            class="go-link"
-            style="display: block;text-align: right;">SIGN UP</a></div>
-    
- 
-    <style>
-  dt {
-    font-weight:bold;
-  }
-  </style>
-  
 <div id="qv-wrapper">
-<ol id="qv">
-<h2>In this document</h2>
-<ol>
-  <li><a href="#business">Business Model</a></li>
-  <li><a href="#free_trials">Free Trials</a></li>
-  <li><a href="#discovery">Discovery</a></li>
-  <li><a href="#reviews">App Review Process</a></li>
-  <li><a href="#features">App Features</a></li>
-  <li><a href="#marketing">Marketing and ROI</a></li>
-  <li><a href="#devices">Devices</a></li>
-  <li><a href="#accounts">Accounts</a></li>
-</ol>
+  <div id="qv">
+  <h2>
+    Topics
+  </h2>
+
+  <ol>
+    <li>
+    <a href="#business-model-and-monetization">Business Model and
+    Monetization</a>
+    </li>
+
+    <li>
+    <a href="#free-trials">Free Trials</a>
+    </li>
+
+    <li>
+    <a href="#discovery">Discovery</a>
+    </li>
+
+    <li>
+    <a href="#app-review-process">App Review Process</a>
+    </li>
+
+    <li>
+    <a href="#app-features">App Features</a>
+    </li>
+
+    <li>
+    <a href="#marketing-and-roi">Marketing and ROI</a>
+    </li>
+
+    <li>
+    <a href="#devices">Devices</a>
+    </li>
+
+    <li>
+    <a href="#accounts">Accounts</a>
+    </li>
+
+    <li>
+    <a href="#related-resources">Related Resources</a>
+    </li>
+  </ol>
+  </div>
 </div>
 
 <p>
-  The sections below provide more information about Google Play for Education
-  and answer common questions that you might have about it.
+  This page provides answers to common questions that you might have about
+  Google Play for Education.
 </p>
 
+<div class="headerLine">
+  <h1 id="business-model-and-monetization">
+  Business Model and Monetization
+  </h1>
 
-<h2 id="business">Business Model and Monetization</h2>
+  <hr>
+</div>
 
-<dl>
-  <dt>
-    What is Google Play for Education?
-  </dt>
+<p>
+  <strong>What is Google Play for Education?</strong>
+</p>
 
-  <dd>
-    Google Play for Education is a new online destination designed for schools.
-    Teachers can discover educational apps, books, and videos to meet the needs
-    of a single student, a classroom, or a whole district. Educators can browse
-    apps by grade, subject, keyword, or standard including common core.
-    Purchasing is done via PO with no credit card required. Apps are
-    distributed to tablets instantly via the cloud.
-  </dd>
+<p>
+  Google Play for Education is a new online destination designed for schools.
+  Teachers can discover educational apps, books, and videos to meet the needs
+  of a single student, a classroom, or a whole district. Educators can browse
+  apps by grade, subject, keyword, or standard including Common Core State
+  Standards. Purchasing is done using a PO with no credit card required. Apps
+  are distributed to tablets instantly through the cloud.
+</p>
 
-  <dt>
-    Is Google Play for Education primarily for students or educators?
-  </dt>
+<p>
+  <strong>Is Google Play for Education primarily for students or
+  educators?</strong>
+</p>
 
-  <dd>
-    The store on Google Play for Education is for educators, but its content is
-    for both educators and students. Teachers and administrators have the
-    ability to make purchases and control who within their school has access to
-    the purchase flows.
-  </dd>
+<p>
+  The store on Google Play for Education is for educators, but its content is
+  for both educators and students. Teachers and administrators have the ability
+  to make purchases and control who within their school has access to the
+  purchase flows.
+</p>
 
-  <dt>
-    Will Google Play for Education support subscription purchases?
-  </dt>
+<div class="figure">
+  <img src="{@docRoot}distribute/images/gpfe-faq.jpg" style=
+  "width:480px;margin:1em 0em 1.5em 1.5em;">
+</div>
 
-  <dd>
-    Currently, Google Play for Education supports one-time purchases. We are
-    investigating additional purchase mechanisms to enable more flexible
-    pricing models for developers and schools.
-  </dd>
+<p>
+  <strong>Will Google Play for Education support subscription
+  purchases?</strong>
+</p>
 
-  <dt>
-    Why is it recommended to disable in-app purchases?
-  </dt>
+<p>
+  Currently, Google Play for Education supports one-time purchases. We’re
+  investigating additional purchase mechanisms to enable more flexible pricing
+  models for developers and schools.
+</p>
 
-  <dd>
-    In-app purchase is currently not supported with Google Play for Education,
-    and a student device will block the Play transaction if a student attempts
-    to make an in-app purchase. To avoid student confusion in the classroom,
-    also recommend not including any in-app purchase buttons and other UI in
-    your application. We are investigating additional purchase mechanisms to
-    enable more flexible pricing models for developers and schools.
-  </dd>
+<p>
+  <strong>Why is it recommended that in-app purchase features are
+  removed?</strong>
+</p>
 
-  <dt>
-    Is Google Play for Education restricted so only its users can purchase from
-    the Google Play for Education? Or will anyone be able to purchase from it?
-  </dt>
+<p>
+  In-app Billing is currently not supported with Google Play for Education, and
+  a student device will block the Google Play transaction if a student attempts
+  to make an in-app purchase. To avoid confusing students, we recommend not
+  including any in-app purchase buttons and other UI in your apps. We’re
+  investigating additional purchase mechanisms to enable more flexible pricing
+  models for developers and schools.
+</p>
 
-  <dd>
-    Currently, only schools that are signed up for Google Play for Education
-    can make purchases on it.
-  </dd>
+<p>
+  <strong>Is Google Play for Education restricted so only its users can
+  purchase from the Google Play for Education? Or will anyone be able to
+  purchase from it?</strong>
+</p>
 
-  <dt>
-    Is there a way to differentiate an app's pricing between Google Play for
-    Education and Google Play?
-  </dt>
+<p>
+  Currently, only schools that are signed up for Google Play for Education can
+  make purchases on it.
+</p>
 
-  <dd>
-    For each app that you publish, you can set a single price that applies to
-    both Google Play and Google Play for Education &mdash. You can’t set a
-    different price for a given app (based on a single package name) in Google
-    Play for Education.
-  </dd>
-</dl>
+<p>
+  <strong>Can I set different prices for my apps in Google Play for Education
+  and Google Play?</strong>
+</p>
 
+<p>
+  You set a single price for each app that applies to both Google Play and
+  Google Play for Education. You can’t set a different price for a given app
+  (based on a single package name) in Google Play for Education.
+</p>
 
-<h2 id="free_trials">Free Trials</h2>
+<div class="headerLine">
+  <h1 id="free-trials">
+  Free Trials
+  </h1>
 
-<dl>
-  <dt>
-    Can I offer free trials through Google Play for Education?
-  </dt>
+  <hr>
+</div>
 
-  <dd>
-    Google Play for Education doesn't currently support free trials. If you
-    want, you can offer a free version of your app with limited functionality
-    in Google Play for Education, but that app would need to be separate from
-    your paid app and be reviewed separately for educational content.
-  </dd>
+<p>
+  <strong>Can I offer free trials through Google Play for Education?</strong>
+</p>
 
-  <dt>
-    Can I offer a free trial through Google Play's "In-app Subscriptions with
-    Free Trials" feature?
-  </dt>
+<p>
+  Google Play for Education doesn't currently support free trials. If you want,
+  you can offer a free version of your app with limited functionality in Google
+  Play for Education, but that app would need to be separate from your paid app
+  and be reviewed separately for educational content.
+</p>
 
-  <dd>
-    Google Play for Education does not currently support In-app Billing or
-    In-app Subscriptions with free trials.
-  </dd>
-</dl>
+<p>
+  <strong>Can I offer a free trial through Google Play's "In-app Subscriptions
+  with Free Trials" feature?</strong>
+</p>
 
+<p>
+  Google Play for Education doesn’t currently support In-app Billing or In-app
+  Subscriptions with free trials.
+</p>
 
-<h2 id="discovery">Discovery</h2>
+<div class="headerLine">
+  <h1 id="discovery">
+  Discovery
+  </h1>
 
-<dl>
-  <dt>
-    What are the categories in Google Play for Education?
-  </dt>
+  <hr>
+</div>
 
-  <dd>
-    Google Play for Education includes categories for all grade levels from
-    Kindergarten to 12 and the following subjects: English Language Arts, World
-    Languages, Mathematics, Science, Social Science, Elective, OER (Open
-    Education Resources), and Tools.
-  </dd>
+<p>
+  <strong>What are the categories in Google Play for Education?</strong>
+</p>
 
-  <dt>
-    I created an app specifically for Google Play for Education and do not want
-    it to show up in Google Play. Is this possible?
-  </dt>
+<p>
+  Google Play for Education includes categories for all grade levels from
+  Kindergarten to 12 and the following subjects: English Language Arts, World
+  Languages, Mathematics, Science, Social Science, Elective, Open Education
+  Resources (OER), and Tools.
+</p>
 
-  <dd>
-    Currently, it is not possible to publish an app Google Play for Education
-    and make it unavailable on Google Play.
-  </dd>
+<p>
+  <strong>I created an app specifically for Google Play for Education and don’t
+  want it to show up in Google Play. Is this possible?</strong>
+</p>
 
-  <dt>
-    If my app offers content for every level of education, how will it fit the
-    common-core standard filters?
-  </dt>
+<p>
+  Currently, it’s not possible to publish an app on Google Play for Education
+  and make it unavailable on Google Play.
+</p>
 
-  <dd>
-    If your app applies to multiple levels of education, then the app will show
-    up filtered results for in multiple levels.
-  </dd>
-</dl>
+<p>
+  <strong>If my app offers content for every level of education, how will it
+  fit the Common Core State Standard filters?</strong>
+</p>
 
+<p>
+  If your app applies to multiple levels of education, then the app will show
+  up in filtered results for multiple levels.
+</p>
 
-<h2 id="reviews">App Review Process</h2>
+<div class="headerLine">
+  <h1 id="app-review-process">
+  App Review Process
+  </h1>
 
-<dl>
-  <dt>
-    How are apps being reviewed? By whom and with what criteria?
-  </dt>
+  <hr>
+</div>
 
-  <dd>
-    Apps are being reviewed by a third party network of educators. These
-    educators assign the appropriate subject, grade, and common core standards
-    metadata, as well as evaluating whether the app meets the Google Play for
-    Education <a href=
-    "{@docRoot}distribute/googleplay/edu/guidelines.html">criteria for
-    classroom use</a>. You can learn more about the submission process and
-    criteria at <a href=
-    "http://developer.android.com/edu">developer.android.com/edu</a>.
-  </dd>
+<p>
+  <strong>How are apps being reviewed? By whom and against what
+  criteria?</strong>
+</p>
 
-  <dt>
-    How do I update my apps in Google Play for Education?
-  </dt>
+<p>
+  Apps are being reviewed by a third-party network of educators. These
+  educators assign the appropriate subject, grade, and Common Core State
+  Standards metadata, as well as evaluating whether the app meets the Google
+  Play for Education <a href=
+  "{@docRoot}distribute/essentials/gpfe-guidelines.html">criteria for classroom
+  use</a>.
+</p>
 
-  <dd>
-    Developers can update their apps on Google Play for Education in the same
-    manner that they do for Google Play. App updates will not be reviewed prior
-    to being made available through Play for Education. However, we will
-    periodically review updated apps for quality.
-  </dd>
+<p>
+  <strong>How do I update my apps in Google Play for Education?</strong>
+</p>
 
-  <dt>
-    Does the app maturity rating reflect solely what a user can do within my
-    Android app, or does the web version of my app influence the rating as
-    well?
-  </dt>
+<p>
+  You can update your apps on Google Play for Education in the same manner you
+  do on Google Play. App updates will not be reviewed prior to being made
+  available through Google Play for Education. However, we will periodically
+  review updated apps for quality.
+</p>
 
-  <dd>
-    The maturity rating that you set for your Android app refers only to the
-    content displayed in that application.
-  </dd>
-</dl>
+<p>
+  <strong>Does the app maturity rating reflect solely on what a user can do
+  within my Android app, or does the web version of my app influence the rating
+  as well?</strong>
+</p>
 
+<p>
+  The maturity rating that you set for an Android app refers only to the
+  content displayed in that app.
+</p>
 
-<h2 id="features">App Features</h2>
+<div class="headerLine">
+  <h1 id="app-features">
+  App Features
+  </h1>
 
-<dl>
-  <dt>
-    Do I need separate builds of my phone and tablet apps for Google Play for
-    Education, or is it the exact same app that lives on Google Play?
-  </dt>
+  <hr>
+</div>
 
-  <dd>
-    We recommend you create one app and use it in both Google Play and Google
-    Play for Education.
-  </dd>
+<p>
+  <strong>Do I need separate builds of my phone and tablet apps for Google Play
+  for Education, or is it the exact same app that lives on Google
+  Play?</strong>
+</p>
 
-  <dt>
-    What is the best way to get students’ work within apps sent back to their
-    teachers?
-  </dt>
+<p>
+  We recommend you create one app and use it in both Google Play and Google
+  Play for Education.
+</p>
 
-  <dd>
-    Many teachers have mentioned that the way apps treat this now is via an
-    email from a third party, which is not optimal for schools. As many schools
-    use Google Apps for Education, consider integrating your app with Google
-    Drive using the SDK which can be found here: <a class="external-link" href=
-    "https://developers.google.com/drive/about-sdk">developers.google.com/drive/about-sdk</a>.
-  </dd>
+<p>
+  <strong>What is the best way to get students’ work within apps sent back to
+  their teachers?</strong>
+</p>
 
-  <dt>
-    How can developers test the teacher experience in Google Play for
-    Education? Is there a way to get an account to test it?
-  </dt>
+<p>
+  Teachers have mentioned that many apps achieve this by email from a third
+  party, which isn’t optimal for schools. As many schools use Google Apps for
+  Education, consider integrating your apps with Google Drive using the
+  <a href="https://developers.google.com/drive/about-sdk">SDK</a>.
+</p>
 
-  <dd>
-    Currently, we are unable to provide developers with a test account to test
-    the Google Play for Education user experience. We are investigating ways to
-    allow developers to simulate the environment.
-  </dd>
+<p>
+  <strong>How can developers test the teacher experience in Google Play for
+  Education? Is there a way to get an account to test it?</strong>
+</p>
 
-  <dt>
-    If I already have an app in the Chrome Apps Pack will I get some help
-    migrating this to Android?
-  </dt>
+<p>
+  Currently, we are unable to provide developers with a test account to test
+  the Google Play for Education user experience. We’re investigating ways to
+  allow developers to simulate the environment.
+</p>
 
-  <dd>
-    If you’d like to reach tablet users in schools we encourage you
-    to build a native app for the optimal user experience. Considerations for
-    building your app and instructions for registering it can be found at
-    <a href="http://developer.android.com/edu">developer.android.com/edu</a>.
-  </dd>
-</dl>
+<p>
+  <strong>If I already have an app in the Chrome Apps Pack will I get some help
+  migrating this to Android?</strong>
+</p>
 
+<p>
+  If you’d like to reach tablet users in schools we encourage you to build a
+  native app for the optimal user experience. Considerations for building your
+  apps can be found in the <a href=
+  "{@docRoot}distribute/essentials/gpfe-guidelines.html">Google Play for
+  Education Guidelines</a>.
+</p>
 
-<h2 id="marketing">Marketing and ROI</h2>
+<div class="headerLine">
+  <h1 id="marketing-and-roi">
+  Marketing and ROI
+  </h1>
 
-<dl>
-  <dt>
-    What are you doing to promote these apps to educators?
-  </dt>
+  <hr>
+</div>
 
-  <dd>
-    Google Play for Education is an extension of Google Play targeting schools
-    and making discovery easier for educational apps. It helps your apps gain
-    visibility with the right audiences, without having to knock on school
-    doors. We are constantly referring to the highest quality apps in our
-    educator outreach. We have also developed a series of collections to help
-    educators quickly browse apps for the most common use cases.
-  </dd>
+<p>
+  <strong>What are you doing to promote these apps to educators?</strong>
+</p>
 
-  <dt>
-    How many installs have similar apps had on Play? How much can I expect to
-    make if I do an ROI analysis?
-  </dt>
+<p>
+  Google Play for Education is an extension of Google Play targeting schools
+  and making the discovery of educational apps easier. It helps your apps gain
+  visibility with the right audiences, without having to knock on school doors.
+  We’re constantly referring to the highest quality apps in our educator
+  outreach. We’ve also developed a series of collections to help educators
+  quickly browse apps for the most common use cases.
+</p>
 
-  <dd>
-    While we cannot disclose specific numbers, Google Play app listings provide
-    app download ranges for all apps.
-  </dd>
+<p>
+  <strong>How many installs have similar apps had on Google Play for Education?
+  How much can I expect to make if I do an ROI analysis?</strong>
+</p>
 
-  <dt>
-    What is the seasonality like for the education market? What are the key
-    timing considerations for app developers?
-  </dt>
+<p>
+  While we cannot disclose specific numbers, Google Play app listings provide
+  app download ranges for all apps.
+</p>
 
-  <dd>
-    In the United States, school districts’ budget decisions go through a
-    planning phase in the Spring with budgets being released on July 1. We have
-    observed high purchase-volumes in the second quarter of the calendar year,
-    using up end-of-year budgets. New budget purchases begin in the third
-    quarter of the calendar year.
-  </dd>
+<p>
+  <strong>What is the seasonality like for the education market? What are the
+  key timing considerations for app developers?</strong>
+</p>
 
-  <dt>
-    Is there a way to offer a special deal, such as a discount, only on Google
-    Play for Education and not on Google Play?
-  </dt>
+<p>
+  In the United States, school districts’ budget decisions go through a
+  planning phase in the Spring with budgets being released on July 1. We’ve
+  observed high purchase-volumes in the second quarter of the calendar year, to
+  use up end-of-year budgets. New budget purchases begin in the third quarter
+  of the calendar year.
+</p>
 
-  <dd>
-    No, this is not possible. Pricing, including special offers, must be the
-    same between Google Play for Education and Google Play.
-  </dd>
-</dl>
+<p>
+  <strong>Is there a way to offer a special deal, such as a discount, only on
+  Google Play for Education and not on Google Play?</strong>
+</p>
 
+<p>
+  No, this isn’t possible. Pricing, including special offers, must be the same
+  between Google Play for Education and Google Play.
+</p>
 
-<h2 id="devices">Devices</h2>
+<div class="headerLine">
+  <h1 id="devices">
+  Devices
+  </h1>
 
-<dl>
-  <dt>
-    Which devices are available in the program? Will more be available?
-  </dt>
+  <hr>
+</div>
 
-  <dd>
-    Nexus 7 is available for shipment now, and the Asus Transformer and HP
-    Slate 8 Pro will be available in early 2014. We look forward to welcoming
-    more Android devices into the Google in Education family soon.
-  </dd>
+<p>
+  <strong>Which devices are available in the program? Will more be
+  available?</strong>
+</p>
 
-  <dt>
-    Can the devices be shared among many students?
-  </dt>
+<p>
+  Nexus 7 is available for shipment now, and the Asus Transformer, HP Slate 8
+  Pro, and Galaxy Tab for Education will be available in early 2014. We look
+  forward to welcoming more Android devices into the Google in Education family
+  soon.
+</p>
 
-  <dd>
-    No. Currently, this program is for one-to-one usage. Each student can login
-    to one specific tablet that is allocated to them.
-  </dd>
-</dl>
+<p>
+  <strong>Can the devices be shared among many students?</strong>
+</p>
 
+<p>
+  No. Currently, this program is for one-to-one use. Each student can login to
+  one specific tablet that is allocated to them.
+</p>
 
-<h2 id="accounts">
+<div class="headerLine">
+  <h1 id="accounts">
   Accounts
-</h2>
+  </h1>
 
-<dl>
-  <dt>
-    Will an app know whether a user is a teacher or student?
-  </dt>
+  <hr>
+</div>
 
-  <dd>
-    No, the app has no mechanism for knowing if it is running on a teacher’s
-    device or a student’s device. We recommend developers use their own user
-    database to enable this feature, where logins can be based on Google
-    Account information.
-  </dd>
+<p>
+  <strong>Will an app know whether a user is a teacher or student?</strong>
+</p>
 
-  <dt>
-    What log-in method do you recommend for an app on Google Play for
-    Education?
-  </dt>
+<p>
+  No, the app has no mechanism for knowing if it’s running on a teacher’s
+  device or a student’s device. We recommend developers use their own user
+  database to enable this feature, where logins can be based on Google Account
+  information.
+</p>
 
-  <dd>
-    One of the key pieces of feedback we have heard multiple times from various
-    schools is that they prefer apps that offer Google Single Sign-on, so that
-    teachers and students do not need to remember multiple log-in credentials.
-    As schools in the program use Google Accounts and Google Apps for
-    Education, offering Google Single Sign-on is ideal.
-  </dd>
-</dl>
\ No newline at end of file
+<p>
+  <strong>What log-in method do you recommend for an app on Google Play for
+  Education?</strong>
+</p>
+
+<p>
+  One of the key pieces of feedback we’ve heard multiple times from various
+  schools is that they prefer apps that offer Google Single Sign-on, so that
+  teachers and students don’t need to remember multiple log-in credentials. As
+  schools in the program use Google Accounts and Google Apps for Education,
+  offering Google Single Sign-on is ideal.
+</p>
+<div class="headerLine"><h1 id="related-resources">Related Resources</h1><hr></div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/toolsreference/gpfefaq"
+  data-sortOrder="-timestamp"
+  data-cardSizes="6x3,6x3,6x3,9x3,9x3,9x3"
+  data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/googleplay/edu/guidelines.jd b/docs/html/distribute/googleplay/edu/guidelines.jd
deleted file mode 100644
index 8427044..0000000
--- a/docs/html/distribute/googleplay/edu/guidelines.jd
+++ /dev/null
@@ -1,244 +0,0 @@
-page.title=Guidelines for Apps
-page.metaDescription=Get your apps ready for Google Play for Education.
-excludeFromSuggestions=true
-@jd:body
-
-   <div style="position:absolute;margin-left: 636px;
-            margin-top:-76px;color:#777;">If you're interested<br>
-            <a href="{@docRoot}distribute/googleplay/edu/contact.html"
-            class="go-link"
-            style="display: block;text-align: right;">SIGN UP</a></div>
-
-<div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">You
-can now include your educational apps in the recently launched Google Play for Education program,
-getting it into the hands of participating schools and key influencers in the education technology
-community. See <a href="start.html">Get Started</a> to
-learn how to participate. </div>
-
-<p>The sections below list the guidelines and requirements for apps
-participating in Google Play for Education.
-
-<p>Before you include your app in Google Play for Education, set up a <a
-href="#test-environment">test environment</a> and make sure your app meets all
-of the safety, usability, and quality guidelines given here. You can use the
-linked resources to help
-you develop a great app for students that offers compelling content and an
-intuitive user experience on Android tablets.</p>
-
-<p>In addition, ensure that your app complies with the terms of a <a
-href="https://play.google.com/about/developer-distribution-agreement-addendum.html"
-target="_policies">Google Play for Education Addendum</a>, as well as
-the standard  <a
-href="http://play.google.com/about/developer-content-policy.html"
-target="_policies">Google Play Developer Program Policies</a> and <a
-href="http://play.google.com/about/developer-distribution-agreement.html"
-target="_policies">Developer Distribution Agreement</a>.</p>
-
-
-<h2 id="requirements">Safety First</h2>
-
-<p>To participate, your apps must be designed to be appropriate for
-the K-12 market. The basic requirements that your apps must meet are:</p>
-
-<ol>
-  <li>Apps and the ads they contain must not collect personally identifiable
-information other than user credentials or data required to operate and improve
-the app.</li>
-  <li>Apps must not use student data for purposes unrelated to its educational
-function.</li>
-  <li>Apps must have a content rating of "Everyone" or "Low Maturity" (apps with
-a "Medium Maturity" rating are allowed, if they have that rating solely because
-they allow communication between students).</li>
-  <li>App content, including ads displayed by the app, must be consistent with
-the app's maturity rating. The app must not display any “offensive” content, as
-described in the <a
-href="http://play.google.com/about/developer-content-policy.html">Google Play
-Developer Program Policies</a> and <a
-href="https://support.google.com/googleplay/android-developer/answer/188189">
-content-rating guidelines</a>.</p></li>
-<li>Apps must comply with the Children’s Online Privacy Protection Act
-and all other applicable laws and regulations.</li>
-</ol>
-
-
-<h2 id="inapp">Monetizing and Ads</h2>
-
-<p>Google Play for Education provides a simple and secure environment for students
-and teachers. To support that environment, priced or free apps that do not use in-app
-purchases are preferred, as are apps that do not display ads. Apps that use in-app
-payments or ads are acceptable, but you must declare those behaviors when opting-in
-to Google Play for Education. Your app's use of in-app purchases or ads will be
-disclosed to educators when they are browsing for content.</p>
-
-<p>Follow the guidelines below to help your app receive the
-  highest ratings and offer the best possible user-experience.</p>
-
-<p>If your app is priced or sells in-app products, you must:</p>
-
-<ul>
-  <li>Sell all content and services through Google Play for Education</li>
-  <li>Allow Google Play to offer teachers limited free trials before purchase
-(through business terms only, no development work is needed)</li>
-<li>Disable in-app purchases if possible, or ensure that:
-
-<ul>
-<li>Users can access your app's core functionality for a classroom setting without
-an in-app purchase.</li>
-<li>In-app purchases are clearly identifiable in your UI.</li>
-<li>You declare the use of in-app purchases at <a href="{@docRoot}distribute/googleplay/edu/start.html#opt-in">opt-in</a>.</li>
-</ul>
-</li>
-</ul>
-
-<p class="note"><strong>Note</strong>: In-app
-purchases are blocked on Google Play for Education tablets at this time.</p>
-
-<p>If your app displays ads, you should:
-  <ul>
-  <li>Disable the display of ads if possible, or ensure that:
-  <ul>
-    <li>Ads are not distracting for students or teachers</li>
-    <li>Ads do not occupy a significant portion of the screen</li>
-    <li>Ads content does not exceed the maturity rating of the app.</li>
-    <li>You declare the use of ads at <a href="{@docRoot}distribute/googleplay/edu/start.html#opt-in">opt-in</a>.</li>
-  </ul>
-  </li>
-</ul>
-
-
-<h2 id="approved">Educational Value</h2>
-
-<p>Apps submitted to Google Play for Education will be evaluated by a
-third-party educator network, which will review them based on alignment with <a
-href="http://www.corestandards.org/" class="external-link"
-target="_android">Common Core Standards</a> and other factors. This will help
-make your content more discoverable for teachers and administrators as they
-browse by grade level, subject, core curriculum, and other parameters. </p>
-
-<p>Apps with highest educational value will have these characteristics:</p>
-<ul>
-  <li>Designed for use in K-12 classrooms.</li>
-  <li>Aligned with a common core standard or support common-core learning.</li>
-  <li>Simple, easy to use, and intuitive for the grade levels the app is targeting.
-  App is relatively easy to navigate without teacher guidance. Not distracting
-  or overwhelming to students.</li>
-  <li>Enjoyable and interactive. App is engaging to students and lets them control
-  their experience.</li>
-  <li>Versatile. App has features make the it useful for more than one classroom
-  function or lesson throughout the school year.</li>
-  <li>Supports the "4Cs":
-    <ul>
-    <li><em>Creativity</em> &mdash; Allows students to create in order to express
-    understanding of the learning objectives, and try new approaches, innovation
-    and invention to get things done.</li>
-    <li><em>Critical thinking</em> &mdash; Allows students to look at problems in
-    a new way, linking learning across subjects and disciplines.</li>
-    <li><em>Collaboration</em> &mdash; Allows students and (if appropriate) educators
-    to work together to reach a goal.</li>
-    <li><em>Communication</em> &mdash; Allows students to comprehend, critique and
-    share thoughts, questions, ideas and solutions.</li>
-    </ul>
-  </li>
-</ul>
-
-<p>As you design and develop your app, make sure it offers high educational value
-by addressing as many of those characteristics as possible.</p>
-
-
-<h2 id="quality">App Quality</h2>
-
-<p>Google Play for Education brings educational content to students and teachers
-on Android tablets. Your apps should be designed to perform well and look great
-on Android tablets, and they should offer the best user experience possible.
-</p>
-
-<p>High quality apps are engaging, intuitive, and offer compelling content.
-Google Play for Education will highlight high-quality apps for easy discovery in
-the store. Here are some recommendations for making your app easy for students
-and teachers to enjoy.</p>
-
-<ul>
-  <li>Meet Core app quality guidelines
-    <ul>
-      <li>Follow <a
-      href="{@docRoot}design/index.html">Android Design Guidelines</a>. Pay special
-      attention to the sections on <a href="{@docRoot}design/patterns/actionbar.html">Action
-      Bar</a>, <a href="{@docRoot}design/patterns/navigation.html">Navigation</a> and <a
-      href="{@docRoot}design/patterns/pure-android.html">Pure Android</a>.</li>
-      <li>Test your apps against the <a href="{@docRoot}distribute/googleplay/quality/core.html">Core
-      App Quality Guidelines</a>.</li>
-    </ul>
-  </li>
-<li>Meet tablet app quality guidelines
-  <ul>
-   <li>Follow our best practices for tablet app development</li>
-   <li>Review the <a href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App
-   Quality Checklist</a> and <a
-   href="http://android-developers.blogspot.com/2012/11/designing-for-tablets-were-here-to-help.html"
-   target="_android">blog post on designing for tablets</a></li>
-   <li>Check your Optimization Tips in the Google Play Developer Console (if you've
-   already uploaded your app)</li>
-  </ul>
-<li>Strive for simplicity and highest usability for students
-  <ul>
-    <li>Design your app so that teachers and students can use all capabilities of
-    your app without having to sign-in to multiple accounts and remember
-    multiple passwords.</li>
-    <li>Every student or teacher using a Google Play for Education tablet will already be
-    signed in with a Google account on the device.  You can take advantage of that to provide a
-    simple, seamless sign-in experience in your app. A recommended approach is to use
-    <a href="{@docRoot}google/play-services/auth.html">Google OAuth 2 authorization</a>
-    through Google Play Services.</li>
-  </ul>
-</li>
-</ul>
-
-
-<h2 id="test-environment">Test Environment</h2>
-
-<p>To test your app and assess it against the guidelines in this document, it's
-recommended that you set up a test environment that replicates the actual
-environment in which students and teachers will run your app.</p>
-
-<p>In general, you should use the test environment described in <a
-href="{@docRoot}distribute/googleplay/quality/tablet.html#test-environment">
-Setting Up a Test Environment for Tablets</a>, including a small number of
-actual hardware devices that replicate the tablet form factors used in the
-Google Play for Education.</p>
-
-<h3 id="devices">Android tablets</h3>
-
-<p>Google Play for Education offers a range of 7-inch through 10-inch tablets, so
-your testing should focus on those hardware devices. You can purchase the Nexus 7
-device from <a href="https://play.google.com/store/devices/details?id=nexus_7_16gb"
-target="_android">Google Play</a> and other stores. Although testing on Nexus
-devices is preferred, you can test on other 7-inch or 10-inch tablets or virtual
-devices if you don't have access to Nexus devices.</p>
-
-<h3 id="conditions">Test conditions</h3>
-
-<p>Once you've set up a suitable hardware environment, make sure to test your
-apps under conditions that simulate those of schools. For example, Google Play
-for Education lets administrators control or disable certain capabilities for
-students, so it's good to test your app with those capabilities disabled. Below
-are some conditions to test your app in, to ensure best results in the Google
-Play for Education environment:</p>
-
-<ul>
-<li><em>Android version</em> &mdash; Test the app on devices running Android
-4.2. Google Play for Education devices will be running Android 4.2 or higher
-(API level 17+).</li>
-<li><em>Proxy server</em> &mdash; Test the app in network environment that uses
-proxies. Many schools use proxies.</li>
-<li><em>No location services</em> &mdash; Test the app to make sure it works
-properly with location services disabled. Many schools will disable location
-services for student devices.</li>
-<li><em>No In-app Billing</em> &mdash; Test the app to make sure it works
-properly without access to In-app Billing. In-app purchases are blocked on
-Google Play for Education devices at this time.</li>
-<li><em>No Bluetooth</em> &mdash; Test the app to make sure it works properly
-when Bluetooth is disabled. Many schools will disable Bluetooth on student
-devices.</li>
-<li><em>No access to network</em> &mdash; Test the app to make sure it works
-properly when the device cannot connect to the internet. </li>
-</ul>
diff --git a/docs/html/distribute/googleplay/edu/index.jd b/docs/html/distribute/googleplay/edu/index.jd
deleted file mode 100644
index a27f82f..0000000
--- a/docs/html/distribute/googleplay/edu/index.jd
+++ /dev/null
@@ -1,48 +0,0 @@
-page.title=Google Play for Education
-page.tags=Google Play,education,schools,distribution
-header.hide=1
-
-@jd:body
-    <div style="position:absolute;margin-left: 636px;
-            margin-top:6px;color:#777;">If you're interested<br>
-            <a href="{@docRoot}distribute/googleplay/edu/contact.html"
-            class="go-link"
-            style="display: block;text-align: right;">SIGN UP</a></div>
-
-   <div class="marquee">
-  <div class="mainimg" style="position:absolute;margin-left:34px;margin-top:57px;">
-    <img src="{@docRoot}images/gp-edu-hero14.jpg" style="width:670px;" />
-  </div>
-  <div class="copy" style="position:relative;left:334px;margin-top:28px;width:420px;">
-    <h1 style="margin-bottom:10px;">Google Play for Education</h1>
-    <p>Google Play for Education is a destination where schools can find great,
-    teacher-approved, educational apps and videos on Play Store. Teachers can filter
-    content by subject matter, grade and other criteria. Bulk purchase and instant
-    distribution let educators bring your apps directly to classrooms and schools.</p>
-    <p>If you have an educational app, join Google Play for Education.</p>
-    <p><a class="button" href="{@docRoot}distribute/googleplay/edu/about.html">Learn More</a></p>
-  </div>
-</div>
-
-<div class="distribute-features col-13" style="clear:both;margin-top:248px;">
-  <div class="distribute-link">
-  <ul>
-    <li><a href="{@docRoot}distribute/googleplay/edu/about.html"><h5>About the Initiative</h5>
-    Find out how Google Play for Education helps you reach a new audience of educators and students.</a>
-    <li><a href="{@docRoot}distribute/googleplay/edu/start.html"><h5>Get your Apps Ready</h5> 
-    Follow these guidelines to make sure your app meets requirements and offers a great user experience. </a>
-    </li>
-    <li class="last"><a href="{@docRoot}distribute/googleplay/edu/start.html#opt-in"><h5>Submit your App</h5>
-    Use the Google Play Developer Console to mark your app for inclusion in the program and review by third-party
-    educators. </a>
-    </li>
-  </ul>
-  </div>
-
-</div>
-
-
-    
-
-
-
diff --git a/docs/html/distribute/googleplay/edu/start.jd b/docs/html/distribute/googleplay/edu/start.jd
index dbfbb6a..260ae85 100644
--- a/docs/html/distribute/googleplay/edu/start.jd
+++ b/docs/html/distribute/googleplay/edu/start.jd
@@ -1,233 +1,320 @@
-page.title=Get Started
-page.metaDescription=Get Started with Google Play for Education
-excludeFromSuggestions=true
+page.title=Get Started with Education
+page.image=/distribute/images/play-education.jpg
+meta.tags="education", "guidelines", "quality"
+page.tags="education", "addendum"
+page.metaDescription=Join Google Play for Education in just a few simple steps.
+
 @jd:body
 
-    <div class="jd-descr" itemprop="articleBody">
-    <div style="position:absolute;margin-left: 636px;
-            margin-top:-76px;color:#777;">If you're interested<br>
-            <a href="{@docRoot}distribute/googleplay/edu/contact.html"
-            class="go-link"
-            style="display: block;text-align: right;">SIGN UP</a></div>
-
-<div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">You
-can now include your educational apps in the Google Play for Education program,
-getting it into the hands of participating schools and key influencers in the
-education technology community. See the sections below to learn more.</div>
-
-<p>If you've got a great app for education, be
-part of Google Play for Education to reach even more teachers and students. It's
-easy to participate, and you'll be able to offer new or existing Android apps
-using familiar tools and processes in Google Play.</p>
-
-<p>To get started, review the sections in this document and learn how to make
-your apps available through Google Play for Education. Also make sure to read <a
-href="{@docRoot}distribute/googleplay/edu/guidelines.html">Guidelines for
-Apps</a>  for information on the safety, usability, and quality standards that
-your apps should meet. When your app is ready, you can opt-in to Google Play for
-Education from the Developer Console.</p>
-
-<p>Note that Google Play for Education is currently available to schools in the
-United States only, with support for schools in other
-countries to follow. At this time, please include your app in Google Play for
-Education only if it is targeting the <strong>US K-12 market</strong>. </p>
-
-
-<h2 id="participate">How to Participate</h2>
-
-<div style="float:right; padding-top:2em;"><img
-src="{@docRoot}images/gp-edu-process.png" /></div>
-
-<p>Google Play for Education is a great way to put your educational apps in front of a
-new audience of teachers and students. You can develop and publish using
-familiar tools and processes, such as your existing <a
-href="https://play.google.com/apps/publish/">Developer Console</a> account
-and your current distribution and pricing settings. It's easy to participate
-&mdash; the sections below outline the process.</p>
-
-<h3 id="basic-info">1. Understand guidelines and policies</h3>
-
-<p>To prepare for a successful launch on Google Play for Education, start by
-reviewing the guidelines for educational apps in Google Play and the policies
-that apply to your apps. See <a
-href="{@docRoot}distribute/googleplay/edu/guidelines.html">Guidelines for
-Apps</a> for details.</p>
-
-<p>Also, make sure that your are familiar with the policies that your app must
-comply with, including
-<a href="http://play.google.com/about/developer-content-policy.html" target="_policies">content
-policies</a>, the <a
-href="http://play.google.com/about/developer-distribution-agreement.html"
-target="_policies">developer agreement</a>,  and <a
-href="https://play.google.com/about/developer-distribution-agreement-addendum.html"
-target="_policies">Google Play for Education Addendum</a>.</p>
-
-<h3 id="developing">2. Design and develop a great app for education</h3>
-
-<p>A great app for educators and students is designed for classroom use, looks
-great on tablets, and delivers a compelling feature set for teachers and
-students. If you are developing an app for education, make sure that it is
-appropriate for K-12 classrooms, offers educational value, and is refined to
-offer a polished, high-quality tablet experience.</p>
-
-<p>Assess your app against the criteria listed in <a
-href="{@docRoot}distribute/googleplay/edu/guidelines.html">Guidelines for
-Apps</a> and plan on supporting them to the greatest extent possible. In some
-cases you might need to modify your features or UI to support the requirements
-of the classroom use-case. It's a good idea to identify those areas early in
-development so that you are able address them properly. </p>
-
-<p>With Google Play for Education, optimizing your app for tablets is a crucial
-part of getting your app ready for distribution to educators. A variety of
-resources are available to help you understand what you need to optimize for
-tablets &mdash; a good starting point is the <a
-href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality
-Guidelines</a>. </p>
-
+<div id="qv-wrapper"><div id="qv">
+<h2>Steps to Join</h2>
+<ol>
+<li><a href="#register">Register for a Publisher Account</li>
+<li><a href="#prepare">Prepare Your Apps</a></li>
+<li><a href="#publish">Publish Your Apps</a></li>
+<li><a href="#related-resources">Related Resources</a></li>
+</ol>
+</div></div>
 <p>
-  Throughout design and development, it's important to have suitable devices
-  on which to prototype and test your user experience. It's highly recommended
-  that you acquire 7-inch and 10-inch tablet devices and set up
-  your testing environment as early as possible. The recommended 7-inch
-  hardware device that replicates the Google Play for Education environment is
-  the Nexus 7, which is available from <a href=
-  "https://play.google.com/store/devices/details?id=nexus_7_16gb" target=
-  "_android">Google Play</a> and other stores.
+  If you've got great apps for education and want to reach even more teachers
+  and students, you can join the <strong>Google Play for Education</strong>
+  program in a few simple steps. You do everything using the familiar tools and
+  processes in Google Play.
 </p>
 
-<p>Proper testing and quality assurance are key aspects of delivering a great
-app for teachers and students. Make sure you set up a <a
-href="{@docRoot}distribute/googleplay/edu/guidelines.html#test-environment">
-proper test environment</a> to ensure that your app meets guidelines under
-realistic conditions.</p>
+<p>
+  Note that Google Play for Education is currently available to <strong>K-12
+  schools in the United States</strong> only.
+</p>
 
-<h3 id="opt-in">3. Opt-in to Google Play for Education and publish</h3>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>Before you opt-in</h2>
-<p>To participate in Google Play for Education, you must agree to a <a
-href="https://play.google.com/about/developer-distribution-agreement-addendum.html"
-target="_policies">Google Play for Education Addendum</a>
-to the standard Developer Distribution Agreement.</p>
-
-<p>Before you opt-in, review the Addendum completely and make any necessary
-modifications to your app.</p>
-</div>
+<div class="center-img">
+  <img src="{@docRoot}images/gpfe-start-0.jpg" style=
+  "border:1px solid #ddd;padding:0px;width:100%;">
 </div>
 
-<p>Once you've built your release-ready APK and tested to ensure that it meets
-the <a href="{@docRoot}distribute/googleplay/edu/guidelines.html">app guidelines</a>,
-upload it to the Developer Console, create your store listing, and set
-distribution options. If you aren't familiar with how to prepare for launch on
-Google Play, see the <a
-href="{@docRoot}distribute/googleplay/publish/preparing.html">Launch Checklist</a>. </p>
+<div class="headerLine clearfloat">
+  <h1 id="register">
+    Register for a Publisher Account
+  </h1>
 
-<p>When your app is ready to publish, you can <em>opt-in</em> to Google Play for
-Education directly from the <a
-href="https://play.google.com/apps/publish/">Developer Console</a>. Opt-in means that you want your app to be
-made available to educators through Google Play for Education, including review,
-classification, and approval by our third-party educator network. Note that
-opt-in does not affect the availability of your app in Google Play Store.</p>
+  <hr>
+</div>
 
-<p>Opt-in also confirms that your app complies with <a
-href="http://play.google.com/about/developer-content-policy.html"
-target="_policies">Google Play Developer Program
-Policies</a> and the <a
-href="http://play.google.com/about/developer-distribution-agreement.html"
-target="_policies">Developer Distribution Agreement</a>,
-including a <a
-href="https://play.google.com/about/developer-distribution-agreement-addendum.html"
-target="_policies">Google Play for Education
-Addendum</a>. If you are not familiar with these policy documents or the
-Addendum, make sure to read them before opting-in. </p>
+<p>
+  If you’re new to Google Play, review the information on <a href=
+  "{@docRoot}distribute/googleplay/start.html">getting started</a> with
+  publishing on Google Play. You’ll gain access to the <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html">Developer
+  Console</a>, where you’ll manage your details, apps, and payments.
+</p>
 
-<p>Here's how to opt-in to Google Play for Education for a specific app:</p>
+<div class="headerLine">
+  <h1 id="prepare">
+    Prepare Your Apps
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure-right">
+  <img src="{@docRoot}images/gp-edu-process.png">
+</div>
+
+<p>
+  By participating in Google Play for Education you’ll be placing your apps
+  before a new audience of teachers and educators. To address this audience,
+  there are specific guidelines and policies your apps should meet and specific
+  design considerations too.
+</p>
+
+<h3>
+  Understand guidelines and policies
+</h3>
+
+<p>
+  To prepare for a launch on Google Play for Education, start by reviewing the
+  guidelines for educational apps in Google Play and the policies that apply to
+  your apps. See the <a href=
+  "{@docRoot}distribute/essentials/gpfe-guidelines.html">Education
+  Guidelines</a> for details.
+</p>
+
+<p>
+  Also, make sure that you're familiar with the policies that your app must
+  comply with, including <a href=
+  "http://play.google.com/about/developer-content-policy.html">content
+  policies</a>, the <a href=
+  "http://play.google.com/about/developer-distribution-agreement.html">Developer
+  Distribution Agreement</a>, and <a href=
+  "https://play.google.com/about/developer-distribution-agreement-addendum.html">
+  Google Play for Education Addendum</a>.
+</p>
+
+<h3>
+  Design and develop a great app for education
+</h3>
+
+<p>
+  Great apps for educators and students <strong>offer educational
+  value</strong>, are <strong>designed for K-12 classroom use</strong>,
+  <strong>deliver a compelling feature set</strong>, and are refined to offer a
+  polished, <strong>high-quality tablet experience</strong>.
+</p>
+
+<p>
+  Assess your app against the criteria listed in the <a href=
+  "{@docRoot}distribute/essentials/gpfe-guidelines.html">Education
+  Guidelines</a> and plan on supporting them to the greatest extent possible.
+  In some cases you might need to modify the app’s features or UI to support
+  classroom requirements. It's a good idea to identify any changes early in
+  development, so that you can address them properly.
+</p>
+
+<p>
+  With Google Play for Education, optimizing your apps for tablets is crucial.
+  A variety of resources are available to help you understand what you need to
+  do — a good starting point is the <a href=
+  "{@docRoot}distribute/essentials/quality/tablets.html">Tablet App Quality</a>
+  guidelines.
+</p>
+
+<p>
+  Throughout design and development, it's important to have suitable devices on
+  which to prototype and test your user experience. It's recommended highly
+  that you acquire 7-inch and 10-inch tablet devices and set up your testing
+  environment as early as possible. The recommended 7-inch hardware device that
+  replicates the Google Play for Education environment is the Nexus 7, which is
+  available from <a href=
+  "https://play.google.com/store/devices/details?id=nexus_7_16gb_2013">Google
+  Play</a> and other stores.
+</p>
+
+<p>
+  Comprehensive testing and quality assurance are key aspects of delivering
+  great apps for teachers and students. Make sure you set up a <a href=
+  "{@docRoot}distribute/essentials/gpfe-guidelines.html#test-environment">proper
+  test environment</a> to, ensure that your apps meet the guidelines under
+  realistic conditions.
+</p>
+
+<div class="headerLine">
+  <h1 id="publish">
+    Publish Your Apps
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Once you have designed, built, and tested your apps, you take two steps to
+  publish them:
+</p>
+
+<ul>
+  <li>Before you opt-in any apps, agree to the <a href=
+  "https://play.google.com/about/developer-distribution-agreement-addendum.html"
+    target="_policies">Google Play for Education Addendum</a>. Ensure you
+    review the Addendum completely and make any necessary modifications to your
+    apps.
+  </li>
+
+  <li>Publish your apps in the Developer Console as normal, but opt-in to
+  Google Play for Education.
+  </li>
+</ul>
+
+<h3 id="opt-in">
+  Opt-in to Google Play for Education and publish
+</h3>
+
+<p>
+  Once you've built your release-ready APK upload it to the Developer Console,
+  create your store listing, and set distribution options. If you aren't
+  familiar with preparing for launch on Google Play, see the <a href=
+  "{@docRoot}distribute/tools/launch-checklist.html">Launch Checklist</a>.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-edu-optin-console.jpg" style=
+  "border:2px solid #ddd;width:660px;">
+</div>
+
+<p>
+  When your apps are ready to publish, you <em>opt-in</em> to Google Play for
+  Education directly from the <a href=
+  "https://play.google.com/apps/publish/">Developer Console</a>. Opt-in means
+  that you want your apps to be made available to educators through Google Play
+  for Education, including review, classification, and approval by our
+  third-party educator network. Note that opt-in doesn’t affect the
+  availability of your app in Google Play Store.
+</p>
+
+<p>
+  Opt-in also confirms that your app complies with <a href=
+  "http://play.google.com/about/developer-content-policy.html" target=
+  "_policies">Google Play Developer Program Policies</a> and the <a href=
+  "http://play.google.com/about/developer-distribution-agreement.html" target=
+  "_policies">Developer Distribution Agreement</a>, including a <a href=
+  "https://play.google.com/about/developer-distribution-agreement-addendum.html"
+  target="_policies">Google Play for Education Addendum</a>. If you are not
+  familiar with these policy documents or the Addendum, make sure to read them
+  before opting-in.
+</p>
+
+<p>
+  Here's how to opt-in to Google Play for Education for a specific app:
+</p>
 
 <ol>
-  <li>In the Developer Console All Applications page, click the app you want to
-opt-in. </li>
-  <li>Under Pricing and Distribution, scroll down to find "Google Play for
-Education" and the opt-in checkbox. </li>
-  <li>Click the checkbox next to "Include this application in Google Play for
-Education."</li>
-  <li>In the first dialog that appears, review the content policies and guidelines
-  and click "Continue" if your app meets the the policies and guidelines.</li>
-  <li>In next dialog that appears, shown below, find the "Ads" and "In-app purchases" radio
-  buttons. Check each option that applies. Your app's use of ads or in-app purchases will
-be shown to educators when they are browsing your app. </li>
-  <li>Click "Save" to save your Pricing and Distribution changes.</li>
+  <li>In the Developer Console <strong>All Applications</strong> page, click
+  the app you want to opt-in.
+  </li>
+
+  <li>Under Pricing and Distribution, scroll down to find <strong>Google Play
+  for Education</strong> and the opt-in checkbox.
+  </li>
+
+  <li>Click the checkbox next to <strong>Include my app in Google Play for
+  Education...</strong>
+  </li>
+
+  <li>In the first dialog that appears, review the content policies and
+  guidelines and click <strong>Continue</strong> if your app meets the the
+  policies and guidelines.
+  </li>
+
+  <li>In the next dialog that appears, shown below, find the
+  <strong>Ads</strong> and <strong>In-app purchases</strong> radio buttons.
+  Check each option that applies. Your app's use of ads or in-app purchases
+  will be shown to educators when they are browsing your app.
+  </li>
+
+  <li>Click <strong>Save</strong>f to save your Pricing and Distribution
+  changes.
+  </li>
 </ol>
 
 <div style="clear:both;margin-top:1.5em;margin-bottom:1.5em;width:660px;">
-<img src="{@docRoot}images/gp-edu-ads-iab.png" style="border:2px solid #ddd;width:660px;" />
-<p class="image-caption"><span style="font-weight:500;">Ads and in-app purchase</span>:
-When you opt-in to Google Play for Education, make sure to declare your app's use of ads and
-in-app purchases.</p>
+  <img src="{@docRoot}images/gp-edu-ads-iab.png" style=
+  "border:2px solid #ddd;width:660px;">
+  <p class="img-caption">
+    <strong>Ads and in-app purchase</strong>: When you opt-in to Google Play
+    for Education, make sure to declare your app's use of ads and in-app
+    purchases.
+  </p>
 </div>
 
-<p>Once you save changes and publish your app, the app will be submitted to our
-third-party educator network for review and approval. If the app is already
-published, it will be submitted for review as soon as you opt-in and save your
-changes. </p>
+<p>
+  Once you save changes and publish your app, the app will be submitted to our
+  third-party educator network for review and approval. If the app is already
+  published, it will be submitted for review as soon as you opt-in and save
+  your changes.
+</p>
 
-<p class="note"><strong>Note</strong>: Google Play for Education is part of
-Google Play. When you publish an app that's opted-in to Google Play for
-Education, the app becomes available to users in Google Play right away. After
-the app is reviewed and approved, it then becomes available to educators in
-Google Play for Education.</p>
+<p class="note">
+  <strong>Note</strong>: Google Play for Education is part of Google Play. When
+  you publish an app that's opted-in to Google Play for Education, the app
+  becomes available to users in Google Play right away. After the app is
+  <a href="{@docRoot}distribute/essentials/gpfe-guidelines.html#e-value">review
+  and approval</a>, it then becomes available to educators in Google Play for
+  Education.
+</p>
 
-<h3 id="review">4. Track your review and approval</h3>
+<h3>
+  Track your review and approval
+</h3>
 
-<p>Google Play for Education provides content to educators in a way that's
-properly organized by subject, grade level, and common core standards (where
-applicable). To ensure high educational value and proper classification, we work
-with a third-party educator network to review and approve apps before making
-them discoverable through the Google Play for Education browsing tools. </p>
+<p>
+  As soon as you opt-in to Google Play for Education and publish, your apps are
+  queued for review by our third-party educator network. The review and
+  approval process can take four weeks or more. You'll receive notification by
+  email (to your developer account address) when the review is complete, with a
+  summary of the review results.
+</p>
 
-<p>Our third-party educator network will evaluate apps according to educational
-value and alignment with K-12 core standards, then assign the metadata for
-subject, grade level, and core curriculum that makes them easily browsable for
-educators. To understand how your apps will be evaluated, please see the <a
-href="{@docRoot}distribute/googleplay/edu/guidelines.html">Guidelines for
-Apps</a> document.</p>
-
-<p>As soon as you opt-in to Google Play for Education and publish, your app is
-queued for review by our third-party educator network. The review and approval
-process can take four weeks or more</strong>. You'll receive notification
-by email (to your developer account address) when the review is complete, with a
-summary of the review results. </p>
-
-<p>At any time, you can check the review and approval status of your app in the
-<a href="https://play.google.com/apps/publish/">Developer Console</a>, under
-"Google Play for Education" in the app's Pricing and
-Distribution page. There are three approval states:</p>
+<p>
+  At any time, you can check the review and approval status of your app in the
+  Developer Console, under "Google Play for Education" in the app's Pricing and
+  Distribution page. There are three approval states:
+</p>
 
 <ul>
-<li><em>Pending</em> &mdash; Your app was sent for review and the review
-is not yet complete.</li>
-<li><em>Approved</em> &mdash; Your app was reviewed and approved. The app
-will be made available directly to educators through Google Play for Education.
-Once your app is approved, you can update it at your convenience without needing
-another full review. </li>
-<li><em>Not approved</em> &mdash; Your app was reviewed and not approved.
-Check the notification email for information about why the app was not approved.
-You can address any issues and opt-in again for another review. </li>
+  <li>
+    <em>Pending</em> &mdash; Your app was sent for review and the review isn't
+    yet complete.
+  </li>
+
+  <li>
+    <em>Approved</em> &mdash; Your app was reviewed and approved. The app will
+    be made available directly to educators through Google Play for Education.
+    Once your app is approved, you can update it at your convenience without
+    needing another full review.
+  </li>
+
+  <li>
+    <em>Not approved</em> &mdash; Your app was reviewed and not approved. Check
+    the notification email send for information about why the app wasn’t
+    approved. You can address any issues and opt-in again for another review.
+  </li>
 </ul>
+<div class="headerLine">
+<h1 id="related-resources">Related Resources</h1><hr>
+</div>
 
-<p>If you have questions about the review status of your app, follow the process
-discussed in the next section. </p>
+<div class="dynamic-grid">
+<h3>FOR DEVELOPERS</h3>
 
-<h3 id="appeal">5. Get support or appeal your review results</h3>
+<div class="resource-widget resource-flow-layout col-13"
+    data-query="collection:distribute/googleplay/gpfe/dev"
+    data-sortOrder="-timestamp"
+    data-cardSizes="9x3,9x3,6x3,6x3,6x3"
+    data-maxResults="8"></div>
 
-<p>After your app is reviewed you'll receive an email giving you the
-results, including information on whether the app was approved and
-what issues may need to be addressed. You'll receive the email at the address
-you specified for your developer account. </p>
+<h3>FOR EDUCATORS</h3>
 
-<p>If your app has issues that need to be addressed, make the necessary
-adjustments, upload your app, and then resubmit the app to Google Play for
-Education through the Developer Console using process described above. Your app
-will be queued for review and you'll receive the review results by email just
-as before.</p>
-
+<div class="resource-widget resource-flow-layout col-13"
+    data-query="collection:distribute/googleplay/aboutgpfe/educators"
+    data-sortOrder="-timestamp"
+    data-cardSizes="9x3"
+    data-maxResults="3"></div>
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/googleplay_toc.cs b/docs/html/distribute/googleplay/googleplay_toc.cs
new file mode 100644
index 0000000..4196c39
--- /dev/null
+++ b/docs/html/distribute/googleplay/googleplay_toc.cs
@@ -0,0 +1,47 @@
+<ul id="nav">
+
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/about.html">
+            <span class="en">The Google Play Opportunity</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/start.html">
+            <span class="en">Get Started with Publishing</span>
+          </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/developer-console.html">
+          <span class="en">Developer Console</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/edu/about.html">
+          <span class="en">Google Play for Education</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/edu/start.html">
+          <span class="en">Get Started with Education</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/edu/faq.html">
+          <span class="en">Education FAQ</span>
+        </a>
+    </div>
+  </li>
+</ul>
+
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
+
diff --git a/docs/html/distribute/googleplay/index.jd b/docs/html/distribute/googleplay/index.jd
new file mode 100644
index 0000000..a215930
--- /dev/null
+++ b/docs/html/distribute/googleplay/index.jd
@@ -0,0 +1,45 @@
+page.title=Google Play
+section.landing=true
+nonavpage=true
+
+@jd:body
+
+ <p>
+  The premier store for distributing Android apps and games, with global reach
+  and <span style="white-space:nowrap;">tools to
+  help you gain traction in the marketplace.</span>
+</p>
+
+<div class="dynamic-grid">
+
+  <h3>Overview</h3>
+
+  <div class="resource-widget resource-flow-layout landing col-16"
+    data-query="collection:distribute/gp/gplanding"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x6"
+    data-maxResults="3">
+  </div>
+
+  <h3>Google Play for Education</h3>
+
+  <div class="resource-widget resource-flow-layout landing col-16"
+    data-query="collection:distribute/gp/gpfelanding"
+    data-cardSizes="6x6"
+    data-maxResults="3">
+  </div>
+
+  <h3>Related resources</h3>
+
+  <div class="resource-widget resource-flow-layout col-16"
+    data-query="type:youtube+tag:growth"
+    data-cardSizes="6x3"
+    data-maxResults="3">
+  </div>
+  <div class="resource-widget resource-flow-layout col-16"
+    data-query="type:blog+tag:googleplay"
+    data-cardSizes="6x3"
+    data-maxResults="3">
+  </div>
+
+</div>
diff --git a/docs/html/distribute/googleplay/policies/ads.jd b/docs/html/distribute/googleplay/policies/ads.jd
deleted file mode 100644
index f2fb0f8..0000000
--- a/docs/html/distribute/googleplay/policies/ads.jd
+++ /dev/null
@@ -1,350 +0,0 @@
-page.title=Ads
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-  <h2>In This Document</h2>
-  <ol>
-    <li><a href="#content-maturity">Content and Maturity</a></li>
-    <li><a href="#context">Context and Behavior</a></li>
-    <li><a href="#disclosure" style="clear:right">Disclosure</a></li>
-    <li><a href="#impersonation">Impersonation of System UI</a></li>
-    <li><a href="#adwalls">Adwalls and Interstitial Ads</a></li>
-    <li><a href="#interfering" style="clear:right;">Interference with Apps and Third-Party Ads</a></li>
-  </ol>
-
-  <h2>More Resources</h2>
-  <ol>
-    <li><a href="http://play.google.com/about/developer-content-policy.html" target="_policies">Developer Program Policies</a></li>
-    <li><a href="http://www.android.com/us/developer-distribution-agreement.html#showlanguages" target="_policies">Developer Distribution Agreement</a></li>
-    <li><a href="http://support.google.com/googleplay/android-developer/answer/188189" target="_policies">Maturity Ratings</a></p>
-  </ol>
-</div>
-</div>
-
-<p>
-  Google Play policies guide how you can use ads in your apps, to help ensure
-  the best experience for users visiting and downloading apps from the store.
-</p>
-
-<p>
-  In general, for the purposes of policy, the content of ads displayed by your
-  app is considered part of your app. As an app developer, it is your
-  responsibility to ensure that the content, context, and behavior of ads in
-  your apps conforms to Google Play policies.
-</p>
-
-<p>
-  Before you publish, make sure you understand Google Play ad policies and how
-  to display ads in conformance with those policies. The sections below
-  highlight best practices and common examples to help you avoid the most
-  common types of policy violations.
-</p>
-
-<p>
-  For more information about Google Play policies that apply to your apps and
-  content, please see the <a href=
-  "http://play.google.com/about/developer-content-policy.html" target=
-  "_policies">Developer Program Policies</a> and <a href=
-  "http://play.google.com/about/developer-distribution-agreement.html" target=
-  "_policies">Developer Distribution Agreement</a>.
-</p>
-
-
-<h2 id="content-maturity">Content and Maturity</h2>
-
-<div class="example-block bad">
-  <div class="heading">Ad maturity exceeds app</div>
-  <img src="{@docRoot}images/gp-policy-ads-maturity-violation.png">
-</div>
-
-<p>
-  From a policy perspective, ads shown in your app are part of your content
-  and your app is responsible for any violations. If an ad shown in your app
-  violates Google Play policies, your app may be suspended or your developer
-  account terminated.
-</p>
-
-<p>
-  For this reason, it's important for you to be be aware of what ads will be
-  displayed in your app and to manage the ads content according to Google Play
-  policies. Here are some guidelines:
-</p>
-
-<ul>
-    <li>
-        <strong>Ads must not violate Content Policy</strong>&mdash;Ads in
-        your app must not violate the terms of Google Play’s Content Policy,
-        including those concerning illegal activities, violence, sexually
-        explicit content, or privacy violations.
-    </li>
-    <li>
-        <strong>Ads maturity must be consistent with your app's
-        maturity</strong>&mdash;Content shown in your ads must be consistent
-        with the app’s maturity rating in Google Play. Especially, ads content
-        should never exceed your app's maturity rating, even if the ads content
-        by itself complies with general policies.
-    </li>
-</ul>
-
-<p>
-  In the example at right, the app's maturity rating is set to
-  "Everyone", which is the lowest maturity level on Google Play. By choosing
-  the "Everyone" maturity level, the developer is declaring that all of the
-  content in the app, <em>including ads</em>, is suitable for all users
-  regardless of age.
-</p>
-
-<p>
-  The example app violates Google Play policies by displaying ad content with a
-  higher maturity level&mdash;ad content showing gambling, profanity, user
-  location, suggestive content, or content from another app with higher
-  maturity exceeds the "Everyone" maturity rating. Because the ad's
-  maturity is higher than the app's maturity level, the app itself is in
-  violation of policy. To correct the problem, the developer must either
-  restrict ads content to "Everyone" level or raise the app's maturity rating.
-</p>
-
-<p>
-  For detailed information about how to choose the appropriate maturity level
-  for your app, or to assess the maturity requirement of ads in your app, see
-  <a href=
-  "http://support.google.com/googleplay/android-developer/answer/188189"
-  target="_policies">Rating your application content for Google Play</a>.
-</p>
-
-
-<h2 id="context">Context and Behavior</h2>
-
-<p>
-  If your app displays ads, it should do so in ways that do not interrupt users,
-  mislead them into clicking on ads, or make changes outside the app without
-  the user's knowledge or consent. Here are some guidelines:
-</p>
-
-<ul>
-  <li>
-    <strong>Display your ads within your UI</strong>&mdash;If possible,
-    display ads only within your app's UI. This leads to a better user
-    experience and helps avoid policy violations
-  </li>
-
-  <li>
-    <strong>Don't make changes outside of the app without consent</strong>
-   &mdash;Ads must not make changes outside of the app without the user's
-    full knowledge and consent.
-  </li>
-
-  <li>
-  <div class="example-block bad" style="width:360px;margin:1em 0 0 2em;">
-    <div class="heading">Ads through system-level notifications</div>
-    <img src="{@docRoot}images/gp-policy-ads-notif-attr-violation.png">
-  </div>
-  <div class="example-block good" style="width:360px;margin:.5em 0 0 2em;">
-    <div class="heading">Notification that's part of the app's feature set</div>
-    <img src="{@docRoot}images/gp-policy-ads-notif-attr.png">
-  </div>
-    <strong>Changes outside the app must be reversible</strong>&mdash;If an
-    ad makes changes outside the app as described above, the changes (and
-    origin app) must be evident and easily reversible. For example, the user
-    must be able to locate and reverse the changes by adjusting settings,
-    changing ad preferences in the app, or uninstalling the app altogether.
-  </li>
-
-  <li>
-    <strong>Notification ads are prohibited</strong>&mdash;Your app
-    should not create system-level <a href=
-    "{@docRoot}design/patterns/notifications.html">notifications</a>
-    containing ads unless the notifications are part of the explicit
-    feature set of the app.
-  </li>
-
-  <li>
-    <strong>Don't add shortcuts, bookmarks, or icons</strong>&mdash;Your app
-    and its ads must not add homescreen shortcuts, browser bookmarks, or icons
-    on the user's device as a service to third parties or for advertising 
-    purposes.
-  </li>
-</ul>
-
-<p>
-  Above right is an example notification ad that violates ad policy by
-  providing ads through system level notification.
-</p>
-<p>
-  Below right, the notification ad complies with policy because the
-  nature of the notification is part of the explicit feature set of the app,
-  and it also provides attribution of the origin app. 
-</p>
-
-<h2 id="disclosure" style="clear:right">Disclosure of Ads to Users</h2>
-
-<p>
-  It's important to sufficiently disclose to users how your app will use ads.
-  You must make it easy for users to understand what ads will be shown in your
-  app, where they will be shown, and what the associated behaviors are, if any.
-  Further, you should ask for user consent and provide options for managing ads
-  or opt-out. Here are some guidelines:
-</p>
-
-<ul>
-  <li>
-    <strong>Tell users about your ads</strong>&mdash;Create a simple,
-    complete disclosure that tells users how your app uses ads, where the ads
-    are shown, and how they can manage ad options. Take common-sense steps to
-    make the disclosure as clear as possible.
-  </li>
-
-  <li>
-    <div class="example-block good" style="width:213px;margin-left:.5em;">
-      <div class="heading">Disclosure in Terms</div>
-      <img src="{@docRoot}images/gp-policy-ads-terms.png">
-    </div>
-    <div class="example-block bad" style="width:213px;">
-      <div class="heading">Disclosure is hidden</div>
-      <img src="{@docRoot}images/gp-policy-ads-eula-violation.png">
-    </div>
-    <strong>Make sure users know</strong>&mdash;Present your ads disclosure
-    is an easy-to-see location, rather than hiding it where users are not
-    likely to find it.
-  </li>
-
-  <li>
-    <strong>Ask for consent (opt-in) at launch</strong>&mdash;Where possible,
-    include your ads disclosure in the app description as well as in an Ads
-    Terms, End User License Agreement (EULA), or similar document. Display the
-    terms at first launch and ask for the user's consent before continuing to
-    the app.
-  </li>
-</ul>
-
-<p>
-  A recommended approach is to provide an ads disclosure in an End-User License
-  Agreement (EULA). The disclosure should be clear and succinct and displayed
-  in a modal dialog that asks the user to agree to the terms before using the
-  app.
-</p>
-
-<p>
-  Above left is an example of ads disclosure that is hidden in a long EULA. The
-  disclosure information itself is not clearly indicated in the document text
-  and it's not visible unless the user happens to scroll down far enough in the
-  EULA. 
-</p>
-<p>
-  Above right shows an approach that presents the disclosure in an obvious
-  and clear manner in a EULA and a dedicated Terms agreement. 
-</p>
-
-
-<h2 id="impersonation">Impersonation of System UI</h2>
-
-
-
-
-
-
-
-
-<p>
-  Ads must not simulate or impersonate the user interface of any app, or
-  notification and warning elements of an operating system. Your app must not
-  display any ad that attempts to impersonate or represent a
-  system function or UI component. If such an ad is displayed in your app, your
-  app will be in violation of policy and subject to suspension. Here are some
-  guidelines:
-</p>
-
-<ul>  
-  <li>
-    <strong>No fake app UI notifications</strong>&mdash;Ads should not impersonate
-    the interface of an application for advertising purposes.
-  </li>
-  <li>
-    <strong>No fake system dialogs or warnings</strong>&mdash;Any ad that
-    presents itself as a system dialog or warning and asks for user input is in
-    violation of Google Play policies.
-  </li>
-
-  <li>
-    <strong>No fake app updates</strong>&mdash;Ads should not impersonate
-    system UI for app updates.
-  </li>
-</ul>
-
-<div class="example-block bad" style="width:213px;">
-  <div class="heading">Ad impersonates app UI</div>
-  <img src="{@docRoot}images/gp-policy-ads-impersonate-violation-app-ui.png">
-</div>
-<div class="example-block bad" style="width:213px;">
-  <div class="heading">Ad impersonates system warning</div>
-  <img src="{@docRoot}images/gp-policy-ads-impersonate-violation-sys-warning.png">
-</div>
-<div class="example-block bad" style="width:213px;">
-  <div class="heading">Ad impersonates system dialog</div>
-  <img src="{@docRoot}images/gp-policy-ads-impersonate-violation.png">
-</div>
-<p style="clear:both">
-  Above are examples of impersonations &mdash; a pop-up ad that impersonates a
-  system dialog, an ad that impersonates a system warning, and an ad that impersonates
-  an application UI. All of these are in violation of policy.
-</p>
-
-
-<h2 id="adwalls">Adwalls and Interstitial Ads</h2>
-
-<p>
-  If your app uses adwalls to drive affiliate traffic, those adwalls must not
-  force the user to click on ads or submit personal information for advertising
-  purposes before using the app.
-</p>
-
-<p>
-  Forcing a user action in an adwall is not only a poor user experience, it is
-  a violation of Google Play policies.
-</p>
-
-<p>
-  For this reason, <strong>all adwalls must give the user the option to
-  cancel</strong> or otherwise dismiss the ad without penalty. Interstitial ads
-  may only be displayed inside of the app they came with. Forcing the user to
-  click on ads or submit personal information for advertising purposes in order
-  to fully use an app is prohibited.
-</p>
-
-<div class="example-block bad" style="width:213px;">
-  <div class="heading">Interstitial, modal ad</div>
-  <img src="{@docRoot}images/gp-policy-ads-interstitial-violation.png">
-</div>
-
-<div class="example-block good" style="width:213px;">
-  <div class="heading">Adwall lets user cancel</div>
-  <img src="{@docRoot}images/gp-policy-ads-paywall.png">
-</div>
-
-<div class="example-block bad" style="width:213px;">
-  <div class="heading">Adwall forces user action</div>
-  <img src="{@docRoot}images/gp-policy-ads-paywall-violation.png">
-</div>
-
-<p style="clear:both">
-  At left is an example of an app that requires the user to click through the
-  ad to fully use the app. This is a violation of policy.
-</p>
-
-<p>
-  The center example demonstrates an adequate option to let the user dismiss
-  the ad wall easily by cancelling. This is not a violation of policy.
-</p>
-
-<p>
-  At right is an example of an interstitial, modal ad that is displayed outside
-  of the app. This is a violation of policy.
-</p>
-
-<h2 id="interfering" style="clear:right;">Interfering with Apps and Third-Party Ads</h2>
-
-<p>
-  Ads associated with your app <strong>must not interfere</strong> with other
-  apps or their ads.
-</p>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/policies/index.jd b/docs/html/distribute/googleplay/policies/index.jd
deleted file mode 100644
index fb46055..0000000
--- a/docs/html/distribute/googleplay/policies/index.jd
+++ /dev/null
@@ -1,59 +0,0 @@
-page.title=Google Play Policies and Guidelines
-page.metaDescription=Guidelines and tips for creating apps that comply with Google Play content and distribution policies.
-@jd:body
-
-<p>
-  Before publishing your apps on Google Play, take a few minutes to read and
-  understand the content and distribution policies that apply to all apps
-  in the store. These policies help to keep Android and Google Play an enjoyable
-  and trusted platform for content consumers and developers alike.
-</p>
-
-<p>
-  The documents below highlight important policy areas and provide tips to help
-  you create policy-compliant apps. You'll also find examples and guidance on common
-  policy questions that can help your app stay clear of practices that can result in
-  low ratings or even suspensions from the store.
-</p>
-
-<p>
-  For complete information about Google Play policies, please see the full
-  <a href="http://play.google.com/about/developer-content-policy.html" target=
-  "_policies">Developer Program Policies</a> and <a href=
-  "http://play.google.com/about/developer-distribution-agreement.html" target=
-  "_policies">Developer Distribution Agreement</a> documents.
-</p>
-
-<div class="vspace size-1">
-  &nbsp;
-</div>
-<div class="layout-content-row">
-  <div class="layout-content-col span-4">
-    <h4>
-      Spam
-    </h4>
-    <p>
-      Make sure that your app does not present content that is unwanted,
-      deceptive, repetitive, or unrelated to the core function of the app.
-    </p><a href="{@docRoot}distribute/googleplay/policies/spam.html">Learn more &raquo;</a>
-  </div>
-  <div class="layout-content-col span-4">
-    <h4>
-      Intellectual Property
-    </h4>
-    <p>
-      Tips and examples of how to use intelletual property (IP) properly,
-      including when to ask permission to use someone else's copyright or
-      trademark.
-    </p><a href="{@docRoot}distribute/googleplay/policies/ip.html">Learn more &raquo;</a>
-  </div>
-  <div class="layout-content-col span-4">
-    <h4>
-      Ads
-    </h4>
-    <p>
-      Make sure that the ads displayed in your app follow the Google Play Content
-      Policy and meet the maturity rating that you have selected for your app.
-    </p><a href="{@docRoot}distribute/googleplay/policies/ads.html">Learn more &raquo;</a>
-  </div>
-</div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/policies/ip.jd b/docs/html/distribute/googleplay/policies/ip.jd
deleted file mode 100644
index 0d1f68d..0000000
--- a/docs/html/distribute/googleplay/policies/ip.jd
+++ /dev/null
@@ -1,345 +0,0 @@
-page.title=Intellectual Property
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-  <h2>In This Document</h2>
-  <ol>
-    <li><a href="#copyright">Copyright Infringement</a></li>
-    <li><a href="#impersonation">Impersonation</a></li>
-    <li><a href="#trademarks">Trademark Infringement</a></li>
-    <li><a href="#other">DDA 4.4 Prohibited Actions</a></li>
-  </ol>
-
-  <h2>More Resources</h2>
-  <ol>
-    <li><a href="http://play.google.com/about/developer-content-policy.html"
-    target="_policies">Developer Program Policies</a></li>
-    <li><a href="http://www.android.com/us/developer-distribution-agreement.html#showlanguages"
-    target="_policies">Developer Distribution Agreement</a></li>
-  </ol>
-</div>
-</div>
-
-<p>
-  Google Play policies protect your intellectual property (IP) as well as that
-  of other app developers and content creators in the store. The policies and
-  their enforcements help ensure proper use of copyright, trademarks, and
-  developer identity in Google Play.
-</p>
-
-<p>
-  As an app developer, these IP policies benefit you. At the same time, it's
-  your responsibility to ensure that your app does not violate the IP of other
-  developers or content creators. Violations of IP-related policy may result in
-  suspension of your apps from the store and termination of your developer
-  account.
-</p>
-
-<p>
-  This document introduces several key areas of IP-related policy that you
-  should understand before publishing on Google Play. In each area you'll find
-  best practices and examples to help you avoid common types of mistakes and
-  violations.
-</p>
-
-<p>
-  For more information about Google Play policies that apply to your apps and
-  content, please see the <a href=
-  "http://play.google.com/about/developer-content-policy.html" target=
-  "_policies">Developer Program Policies</a> and <a href=
-  "http://play.google.com/about/developer-distribution-agreement.html" target=
-  "_policies">Developer Distribution Agreement</a>.
-</p>
-
-
-
-<h2 id="copyright">Copyright Infringement</h2>
-
-<p>
-  Copyright is the legal right granted to an author or creator for a literary,
-  dramatic or artistic piece of work. As soon as you create an original piece
-  of work and fix it in a tangible medium, the work is automatically protected
-  by copyright law and you are the owner of the copyright. Likewise, when other
-  people create content, they may own the copyrights for those works.
-</p>
-
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>How to report infringements</h2>
-<p>If you feel your copyright is being infringed, you may file a Digital Millenium
-   Copyright Act (DMCA) request. Please see <a 
-   href="http://support.google.com/bin/request.py?&product=androidmarket&contact_type=lr_dmca"
-   target="_policies">copyright procedures</a> for more information.</p>
-</div>
-</div>
-
-<p>
-  Copyright infringement is an improper or unauthorized use of a copyrighted
-  work. If you publish an app in Google Play that uses another party's copyrighted
-  works improperly or without permission, your apps can be suspended and your
-  developer account terminated.
-</p>
-
-<p>
-  As you design your app and prepare for publishing, make sure to review Google
-  Play policies and analyze all of your content. If your app uses or links to
-  another party's original work, make sure that your app is not infringing on
-  copyright. Not all uses of another party’s work are infringements on
-  copyright, and the rules vary by country and can be complex.
-</p>
-
-<p>
-  If you are unsure whether your use of another party's work infringes on a
-  copyright, consider getting legal advice before publishing, or simply request
-  permission to use the work from the copyright owner.
-</p>
-
-<p>
-  Here are some guidelines to help you avoid copyright infringement policy
-  violations:
-</p>
-
-<ul>
-  <li>
-    <strong>Respect copyright laws</strong>&mdash;Do not let your app infringe
-    on the copyrights of others. That includes linking to other apps or web
-    sites that contain obviously infringing material (please refer to the <a href="
-    {@docRoot}distribute/googleplay/policies/spam.html#webview-spam">Spam in WebViews</a> guidelines), and using icons or images that are obvious infringements.
-  </li>
-
-  <li>
-    <strong>Know your app's content</strong>&mdash;Before you publish, look
-    for content that may be protected by trademark or copyright in your app
-    and get legal advice if necessary. Protected work could typically include
-    product names, brands, images, music, and similar works.
-  </li>
-
-  <li>
-    <strong>Create original work</strong>&mdash;If you’re not sure whether
-    something will violate another party's copyright, the safest approach is to
-    create something that's completely original, such as images or audio
-    that you’ve created yourself. When you create your own original content,
-    you rarely have to worry about infringing on existing copyright.
-  </li>
-
-  <li>
-    <strong>Ask permission to use copyrighted work</strong>&mdash;If you want
-    to use another party's copyrighted work in your app, you should ask for
-    permission from the work's creator or copyright owner and include
-    appropriate copyright attribution.
-  </li>
-</ul>
-
-<p>
-  A common misunderstanding is believing that your app may use copyrighted
-  content without permission, provided that you clearly indicate that your app
-  is not the "official" app that readers may be familiar with. That is not the
-  case. Even if you let users know that your app is "unofficial", it still
-  violates Google Play policies if it uses or links to copyrighted content
-  without permission. Also, this type of "unofficial" app may violate <a
-  href="#impersonation">impersonation policies</a>.
-</p>
-
-<p>
-  The example app below shows an app that uses screenshots/images of known
-  artists without their authorization and lists popular songs. The combination
-  of these may induce users to download music ringtones that infringe on
-  copyright. This is a violation of Google Play policy.
-</p>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
-  <div class="heading">Images and downloads that violate copyright</div>
-  <img src="{@docRoot}images/gp-policy-ip-copyright-violation.png">
-</div>
-
-
-<h2 id="impersonation">Impersonation</h2>
-
-<p>
-  Impersonation is when an app attempts to imply a relationship to another app
-  or developer, where no relationship actually exists.
-</p>
-
-<p>
-  For example, if your app displays the brand, icon, or title from another app
-  in order to get to users to download your app, you are leading users to
-  believe that your app is developed by the same entity as the other app and
-  offers similar content or experience. This is an impersonation of the other
-  app and developer, and it is a violation of Google Play policy. If you
-  publish apps that violate impersonation policies, your apps can be suspended
-  and your developer account terminated.
-</p>
-
-<p>
-  No matter what type of app you offer or what your motivation, don’t try to
-  imply an endorsement or relationship to another company or product where none
-  exists. Don’t try to establish your app as the "official" version of another
-  party's work by prominently featuring their brand names or trademarks in your
-  app title or description.
-</p>
-
-<p>
-  Even if your app description states that your app is an "unofficial" version,
-  the use of the other app's branding, trademarks, and other content still can
-  violate policy by presenting content that isn’t yours.
-</p>
-
-<p>
-  Here are some guidelines:
-</p>
-
-<ul>
-  <li>
-    <strong>Don't pretend to be someone else</strong>&mdash; Don't represent
-    that your content is produced by another company or organization if that is
-    not the case.
-  </li>
-
-  <li>
-    <strong>Don't support infringing sites or apps</strong>&mdash; Don't divert
-    users or provide links to any other site that mimics Google Play or
-    represents itself as another application or service.
-  </li>
-
-  <li>
-    <strong>Don't use another app's branding</strong>&mdash; Don’t try to pass
-    off your app as the official version of someone else’s property by using a
-    person or entity (or brand) name in your app title or description.
-  </li>
-</ul>
-
-<p>
-  Below is an example of an "unofficial" app that violates Google Play policy
-  by impersonating another company and an existing product. Specifically:
-</p>
-
-<ul>
-  <li>The example app has a name and icon that appear to be impersonating an
-  existing product.
-  </li>
-
-  <li>The example developer name implies an endorsement or relationship to
-  another company and their products where none exists.
-  </li>
-</ul>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
-  <div class="heading">App name, icon, and developer name that impersonate another</div>
-  <img src="{@docRoot}images/gp-policy-ip-impersonation-violation.png">
-</div>
-
-
-<h2 id="trademarks">Trademark Infringement</h2>
-
-<p>
-  A trademark is a brand that uniquely identifies a product and distinguishes
-  it from other products. It can be a word, name, symbol, or combination of
-  those that is intended to identify the source of the product. A trademark is
-  specifically acquired by a company or other entity through a legal process
-  and once acquired gives the owner exclusive rights to the trademark usage.
-</p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>How to report infringements</h2>
-<p>If you feel your trademark is being infringed, you can request a content review.
-See <a href="http://support.google.com/bin/static.py?&ts=1114905&page=ts.cs"
-target="_policies">Removing content from Google</a> for more information.</p>
-</div>
-</div>
-
-<p>
-  Trademark infringement is improper or unauthorized use of a trademark. Google
-  Play policies prohibit apps that infringe trademarks. If you publish apps in
-  Google Play that use another party's trademarks, your apps can be suspended
-  and your developer account terminated.
-</p>
-
-<p>
-  As you design your app and prepare for publishing, make sure to review Google
-  Play policies and analyze all of your content. If your app uses a trademark
-  not owned by you, or if you are not sure whether a brand is a trademark, you
-  should get legal advice before publishing. As with copyright, the rules vary
-  by country and can be complex.
-</p>
-
-<p>
-  Here are some guidelines for avoiding trademark infringement policy
-  violations:
-</p>
-
-<ul>
-  <li>
-    <strong>Understand and follow trademark laws</strong>&mdash;Don't let your
-    app infringe on the trademarks of others.
-  </li>
-
-  <li>
-    <strong>Know your app's content</strong>&mdash;Before you publish, look for
-    brands and potential trademarks used in your app and store listing and get
-    legal advice if necessary.
-  </li>
-
-  <li>
-    <strong>Use a distinct name</strong>&mdash;Don't give your app a name that
-    is confusingly similar to another company's trademark.
-  </li>
-
-  <li>
-    <strong>Don't use trademarks to imply a relationship</strong>&mdash;Don't
-    describe your app using another company's trademarks in a way that implies
-    an endorsement by or affiliation with the other company.
-  </li>
-
-  <li>
-    <strong>Use a distinct app icon and logo</strong>&mdash;Don't use a
-    modified version of another company’s trademarked logo.
-  </li>
-</ul>
-
-<p>
-  A common misunderstanding is believing that your app may use a brand or
-  trademark without permission, provided you clearly indicate that the app is
-  not the "official" or original app. That is not the case. Even if you let
-  users know that your app is "unofficial", it still violates Google Play
-  policies if it uses another party's trademarks. Also, this type of
-  "unofficial" app may violate <a href="#impersonation">impersonation
-  policies</a>.
-</p>
-
-<p>
-  Below is an example app that violates Google Play policies by infringing on
-  another party's trademarks. Specifically:
-</p>
-
-<ul>
-  <li>The example app name is confusingly similar to another party's trademark.</li>
-  <li>The example app icon is a modified version of a another party's logo.</li>
-</ul>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
-  <div class="heading">App name and icon that infringe trademarks</div>
-  <img src="{@docRoot}images/gp-policy-ip-trademark-violation.png">
-</div>
-
-
-<h2 id="other">DDA 4.4 Prohibited Actions</h2>
-
-<p>
-  When you publish an app on Google Play, you agree to the terms of the
-  Developer Distribution Agreement (DDA). Section 4.4 of the DDA prohibits certain
-  types of actions on your part. For reference, you agree that you will not
-  engage in any activity with the Market, including the development or
-  distribution of Products, that interferes with, disrupts, damages, or
-  accesses in an unauthorized manner the devices, servers, networks, or other
-  properties or services of any third party including, but not limited to,
-  Android users, Google or any mobile network operator.
-</p>
-
-<p>
-  For details, please refer to the complete <a href=
-  "http://play.google.com/about/developer-distribution-agreement.html" target=
-  "_policies">Developer Distribution Agreement</a>.
-</p>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/policies/spam.jd b/docs/html/distribute/googleplay/policies/spam.jd
deleted file mode 100644
index f4d303c..0000000
--- a/docs/html/distribute/googleplay/policies/spam.jd
+++ /dev/null
@@ -1,421 +0,0 @@
-page.title=Spam
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-  <h2>In This Document</h2>
-  <ol>
-    <li><a href="#keyword-spam">Spam in App Title and Description</a></li>
-    <li><a href="#ratings">Spam in Ratings and Reviews</a></li>
-    <li><a href="#webview-spam">Spam in WebViews</a></li>
-    <li><a href="#wizard-spam">Spam from Wizards</a></li> 
-    <li><a href="#message-spam">Spam in Messaging</a></li>
-  </ol>
-
-  <h2>More Resources</h2>
-  <ol>
-    <li><a href="http://play.google.com/about/developer-content-policy.html" target="_policies">Developer Program Policies</a></li>
-    <li><a href="http://play.google.com/about/developer-distribution-agreement.html" target="_policies">Developer Distribution Agreement</a></li>
-  </ol>
-</div>
-</div>
-
-<p>
-  Google Play policies prohibit spam, to help ensure the best experience for
-  Android users. Please do not publish deceptive, repetitive, or irrelevant
-  content on Google Play. Not only will it lower your app's rating and cause
-  negative reviews, it can result in your app being suspended or your developer
-  account terminated.
-</p>
-
-<p>
-  As an app developer, it is your responsibility to ensure that your apps are
-  free from spam and conform to the Google Play policies highlighted in this
-  document. Before you publish, make sure that you understand what is
-  considered spam on Google Play and check your apps for violations, even those
-  that might be inadvertent. The sections below highlight best practices and
-  common spam examples to help you avoid the most common types of policy
-  violations.
-</p>
-
-<p>
-  For more information about Google Play policies that apply to your apps and
-  content, please see the <a href=
-  "http://play.google.com/about/developer-content-policy.html" target=
-  "_policies">Developer Program Policies</a> and <a href=
-  "http://play.google.com/about/developer-distribution-agreement.html" target=
-  "_policies">Developer Distribution Agreement</a>.
-</p>
-
-
-<h2 id="keyword-spam">Spam in App Title and Description</h2>
-
-<p>
-  When you publish an app on Google Play, you should pay special attention to
-  the app's title and description in its store listing. Those fields are
-  important because they make your app recognizable to users, and they help to
-  drive downloads by highlighting what's great about your app. A memorable
-  title and compelling description are essential to effective marketing, but
-  you should realize that these must follow Google Play policies, just as your
-  app content must do.
-</p>
-
-<p>
-  Many developers unknowingly violate spam policy in their app titles and
-  descriptions in ways that are easy to avoid. In general, you can
-  avoid spam violations in your app title and description by following these
-  best practices:
-</p>
-
-<ul>
-  <li>
-    <strong>Highlight what's great about your app</strong>&mdash;Share
-    interesting and exciting facts about your app with users. Help users
-    understand what makes your app special.
-  </li>
-
-  <li>
-    <strong>Describe your app accurately</strong>&mdash;Make sure the title
-    and description describe the app function and user experience accurately.
-  </li>
-
-  <li>
-    <strong>Don't use repetitive keywords</strong>&mdash;Avoid keywords that
-    are repetitive or excessive.
-  </li>
-
-  <li>
-    <strong>Don't include unrelated keywords or references</strong> &mdash;
-    Your description should not be loaded with irrelevant keywords in an
-    attempt to manipulate ranking or relevancy.
-  </li>
-
-  <li>
-    <strong>Keep it brief</strong>&mdash;Keep the description succinct and
-    straightforward. Shorter descriptions tend to give a better user experience
-    on devices with smaller displays. Excessive length, detail, or repetition
-    can violate spam policy.
-  </li>
-</ul>
-
-<p>
-  Here's an example app title and description that follows best practices and
-  does not violate Google Play spam policies.
-</p>
-
-<div class="example-block good" style="width:100%;float:none;margin:.5em auto 2em 0;">
-  <div class="heading">Best practice: App description</div>
-  <table>
-  <tr>
-    <td>App Title:</td>
-    <td>Kids puzzle: Identify Turtles</td>
-  </tr>
-  <tr>
-    <td style="white-space:nowrap;">App Description:</td>
-    <td>
-      <p>This is the perfect app to have a good time with your children. It
-        is designed to help kids learn different species of turtles through
-        cute pictures and amusing puzzle games.</p>
-      <p>The rules of Kids puzzle: Identify Turtles are quite simple. Have
-        your child drag images around the screen to fit them into the shaded
-        region. Phonics is also utilized, as a child can also tap the word
-        below the image and hear the name pronounced.</p>
-    </td>
-  </tr>
-  </table>
-</div>
-
-<p>
-  The sections below highlight common types of policy violations in an app
-  title and description, illustrated with variations on the best practice
-  example. 
-</p>
-
-<h3 id="repetitive-keywords">Repetitive keywords</h3>
-
-<p>
-  Your app description should not include keywords that are repetitive or excessive.
-</p>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
-  <div class="heading">Description includes repetitive keywords</div>
-  <table>
-  <tr>
-    <td>App Title:</td>
-    <td>Kids puzzle: Identify Turtles</td>
-  </tr>
-  <tr>
-    <td style="white-space:nowrap;">App Description:</td>
-    <td>
-      <p>This is the perfect app to have a good time with your children. It is
-        designed to help kids learn different species of turtles through cute
-        pictures and amusing puzzle games.</p>
-      <p>The rules of Kids puzzle: Identify Turtles are quite simple. Have your
-        child drag images around the screen to fit them into the shaded region.
-        Phonics is also utilized, as a child can also tap the word below the image
-        and hear the name pronounced.</p>
-      <p style="border:2px solid red;">KEYWORDS: game, games, fun, funny, child,
-        children, kid, kids, puzzle, puzzle games, sound, turtle, turtles, sea turtles,
-        turtles, turtle, turtles, tortoise, tortoises, tortoise, tortoise,  turtles,
-        turtles, turtles, turtles, tortoises, tortoise</p>
-    </td>
-  </tr>
-  </table>
-</div>
-
-<h3 id="unrelated-keywords">Unrelated keywords or references</h3>
-
-<p>
-  The description should not be loaded with irrelevant keywords in an attempt
-  to manipulate ranking or relevancy in Google Play search results.
-</p>
-
-<p>
-  For example, if your app has nothing to do with Lady Gaga, then she shouldn’t
-  be included in your description. Also, do not add highly searched, irrelevant
-  keywords that are unrelated to the function of the app. This is in breach of
-  policy.
-</p>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
-  <div class="heading">Description includes unrelated keywords or references</div>
-  <table>
-  <tr>
-    <td>App Title:</td>
-    <td>Kids puzzle: Identify Turtles</td>
-  </tr>
-  <tr>
-    <td style="white-space:nowrap;">App Description:</td>
-    <td>
-      <p>This is the perfect app to have a good time with your children. It is designed to
-        help kids learn different species of turtles through cute pictures and amusing puzzle
-        games.</p>
-      <p>The rules of Kids puzzle: Identify Turtles are quite simple. Have your child drag
-        images around the screen to fit them into the shaded region. Phonics is also utilized,
-        as a child can also tap the word below the image and hear the name pronounced.</p>
-      <p style="border:2px solid red;">This game is as addictive as Angry Birds, more social
-        than Facebook and Twitter, and has a soundtrack reminiscent of Katy Perry and Lady
-        Gaga.</p>
-      <p style="border:2px solid red;">KEYWORDS: Angry Birds, Facebook, Twitter, Katy Perry,
-        Lady Gaga</p>
-    </td>
-  </tr>
-  </table>
-</div>
-
-<h3 id="excessive-detail">Excessive detail, references to your other apps</h3>
-
-<p>
-  Your app description should avoid excessive detail and references to your
-  other apps or products. For example, you should not list all of the details
-  of content included in the app or its various components, as shown in the
-  example below. Also, the description should not include any references to
-  other apps you’ve published.
-</p>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
-  <div class="heading">Description includes excessive detail, references to your other apps</div>
-  <table>
-  <tr>
-    <td>App Title:</td>
-    <td>Kids puzzle: Identify Turtles</td>
-  </tr>
-  <tr>
-    <td style="white-space:nowrap;">App Description:</td>
-    <td>
-      <p>This is the perfect app to have a good time with your children. It is designed
-        to help kids learn different species of turtles through cute pictures and amusing
-        puzzle games.</p>
-      <p>The rules of Kids puzzle: Identify Turtles are quite simple. Have your child
-        drag images around the screen to fit them into the shaded region. Phonics is also
-        utilized, as a child can also tap the word below the image and hear the name
-        pronounced.</p>
-      <p style="border:2px solid red;">Turtles included in the app: Alligator
-        Snapping Turtle, Asian Box Turtle, Bog Turtle, Common Musk Turtle, Common Snapping
-        Turtle, Diamondback Terrapin, Eastern Box Turtle, Eastern Mud Turtle, Eastern Painted
-        Turtle, False Map Turtle, Florida Pond Cooter, Florida Softshell Turtle, Green Sea
-        Turtle, Map Turtle, Matamata Ornate Box Turtle, Red-bellied Side-necked Turtle,
-        Red-eared Slider, Smooth Softshell Turtle, Spiny Softshell Turtle, Spotted Turtle,
-        Western Painted Turtle, Wood Turtle, Yellow-bellied Slider</p>
-      <p style="border:2px solid red;">If you like this app try our other free apps:<br />
-       ★ Fun Zoo<br />
-       ★ CD Guns<br />
-       ★ Dessert House<br />
-       ★ Playground<br />
-       ★ 578 Weapons</p>
-    </td>
-  </tr>
-  </table>
-</div>
-
-
-<h2 id="ratings">Spam in Ratings and Reviews</h2>
-
-<div class="example-block bad" style="width:440px;">
-  <div class="heading">Inappropriate content in a review</div>
-  <img src="{@docRoot}images/gp-policy-spam-negreview.png">
-</div>
-
-<p>
-  Ratings and reviews are benchmarks of app quality and users depend on them to
-  be authentic and relevant. As an app developer, you should not attempt to
-  artificially influence your app's ratings and reviews or those of your
-  competitor, such as by posting fake ratings or reviews or including spam
-  content in app reviews. The sections below provide guidelines for rating and
-  reviewing apps.
-</p>
-
-<p>
-  So that you can stay in touch with any issues that users are having with your
-  app, you should read through your ratings and reviews on a regular basis. If
-  you choose to reply to reviews, make sure to keep your reply focused on the
-  actual issues raised in the user's comments and do not ask for a higher
-  rating.
-</p>
-
-<p>
-  If you see an app or developer reply that doesn’t follow these guidelines,
-  you can report it. See <a href=
-  "http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113417&topic=2364761&ctx=topic"
-  target="_policies">Inappropriate content in comments and applications</a> for
-  more information.
-</p>
-
-<div class="example-block bad" style="margin-top:3em;width:213px;">
-  <div class="heading">Soliciting ratings</div>
-  <img src="{@docRoot}images/gp-policy-spam-reqrating.png">
-</div>
-
-<h3 id="fake-ratings">Fake or inappropriate ratings and reviews</h3>
-
-<p>
-  To help ensure the quality of ratings and reviews, Google Play policies limit
-  the ways that individuals can use ratings and reviews. In particular, note
-  that it is a violation of policy to use ratings and reviews to influence the
-  placement of any app in Google Play.
-</p>
-
-<p>
-  As an app developer, make sure that you follow these guidelines:
-</p>
-
-<ul>
-  <li>
-    <strong>Don't try to manipulate ratings</strong>&mdash;Do not engage in
-    attempts to manipulate the ratings, reviews, or ranking of your apps,
-    either directly or indirectly, or by manipulating the ratings of your
-    competitors. Do not attempt to artificially boost reviews, ratings, or
-    installs through any means.
-  </li>
-
-  <li>
-    <strong>Don't solicit ratings through incentives</strong>&mdash;Do not
-    offer users any incentives to rate your app, such as offering rewards of
-    any kind or tying app functionality to rating.
-  </li>
-
-  <li>
-    <strong>Don't rate apps multiple times</strong>&mdash;Do not review or
-    rate any app multiple times in an attempt to influence its placement in
-    Google Play.
-  </li>
-
-  <li>
-    <strong>Don't add improper content to reviews</strong>&mdash;Do not
-    include affiliate, coupon, game codes, email addresses, or links to
-    websites or other apps in your reviews. If you are responding to a user
-    review, feel free to include references to helpful resources such as a
-    support address or FAQ page.
-  </li>
-</ul>
-
-<h3 id="solicited-ratings">Soliciting ratings from users</h3>
-
-<p>
-  In general, <strong>do not offer incentives for ratings</strong>. You should
-  not offer users incentives of any kind for rating your app (or any other app)
-  on Google Play, and you should not tie your app's functionality or content to
-  rating in any way.
-</p>
-
-<p>
-  It's acceptable to ask users to rate your app without incentives, for
-  example: "If you like this game, rate us in Google Play!" On the other hand,
-  it's a policy violation to ask users to rate your app based on incentives,
-  for example: "Rate this app and get 500 coins" or "Rate this app 5 stars and
-  get you 500 coins!"
-</p>
-
-
-<h2 id="webview-spam" style="clear:right">Spam in WebViews</h2>
-
-<p>
-  Apps published on Google Play should provide their own content. Do not
-  publish an app whose primary function is to reproduce or frame someone else’s
-  website (unless you have permission).
-</p>
-
-<p>
-  Similarly, do not publish an app whose primary function is to drive affiliate
-  traffic to a website. Although affiliate deals can exist where an app's
-  primary purpose is delivering its own content or functionality, it's a
-  violation of Google Play policies to publish an app whose primary (or
-  only) purpose is to direct affiliate traffic to another website.
-</p>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
-  <div class="heading">WebView spam</div>
-  <table>
-  <tr>
-    <td>App Title:</td>
-    <td>Kids puzzle: Desktop Browser for Turtoogle Game</td>
-  </tr>
-  <tr>
-    <td>Developer:</td>
-    <td>AAZZZ <span style="border:2px solid red;">(not affiliated with Turtoogle
-      Inc.)</span></td>
-  </tr>
-  <tr>
-    <td style="white-space:nowrap;">App Description:</td>
-    <td>
-      <p>Have you ever wanted to use the full, desktop web version of Turtoogle
-        Game from your phone or tablet instead of the Turtoogle Game mobile app
-        or Turtoogle Game mobile web site?</p>
-      <p style="border:2px solid red;">This app lets you access Turtoogle Game
-        on your Android device in the same way as you access the game on your
-        desktop computer, and with all the same Turtoogle Game features.</p>
-    </td>
-  </tr>
-  </table>
-</div>
-
-
-<h2 id="wizard-spam">Spam from Wizards</h2>
-
-<p>
-  Apps that are created by an automated tool or wizard service must not be
-  submitted to Google Play by the operator of that service on behalf of other
-  persons. Such tools often produce too many duplicative or low-quality
-  apps which crowd the higher-quality apps in the Play Store.
-</p>
-
-<p>
-  Please be advised that apps created by an automated tool are only permissible
-  if the app end-product complies with Google Play policies and is published in
-  the Play Store through a developer account that is registered and owned by
-  you.
-</p>
-
-
-<h2 id="message-spam">Spam in Messaging</h2>
-
-<p>
-  Your app may not send SMS, email, or other messages on behalf of the user
-  without providing the user with the ability to confirm the content and intended
-  recipient.
-</p>
-
-<p>
-  Google Play will aggressively remove applications that are found to send or
-  modify SMS messages without user knowledge or consent.
-</p>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/promote/badge-files.jd b/docs/html/distribute/googleplay/promote/badge-files.jd
deleted file mode 100644
index 03ebd01..0000000
--- a/docs/html/distribute/googleplay/promote/badge-files.jd
+++ /dev/null
@@ -1,290 +0,0 @@
-page.title=Google Play Badge Files
-@jd:body
-
-
-
-
-<style>
-table tr td {border:0}
-</style>
-
-<p>The following links provide the Adobe&reg; Illustrator&reg; (.ai) file for the
-two Google Play badges.</p>
-
-<hr>
-<img src="{@docRoot}images/brand/en_generic_rgb_wo_60.png" alt="Get It On Google Play">
-
-<div style="clear:left">&nbsp;</div>
-
-<div class="col-4" style="margin-left:0">
-
-       <a href="{@docRoot}downloads/brand/v2/english_get.ai">English (English)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/amharic_get.ai">ኣማርኛ (Amharic)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/af_generic_rgb_wo.ai">Afrikaans (Afrikaans)</a><br/>
-<!--
-       <a href="{@docRoot}downloads/brand/ar_generic_rgb_wo.ai">العربية (Arabic)</a><br/>
--->
-       <a href="{@docRoot}downloads/brand/v2/belarusian_get.ai">Беларуская (Belarusian)</a><br/>
-       
-       <a href="{@docRoot}downloads/brand/v2/bulgarian_get.ai">български (Bulgarian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/catalan_get.ai">Català (Catalan)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/traditional_chinese_get.ai">中文 (中国) (Chinese)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/hongkong_chinese_get.ai">中文(香港) (Chinese Hong Kong)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/taiwan_chinese_get.ai">中文 (台灣) (Chinese Taiwan)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/croatian_get.ai">Hrvatski (Croatian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/czech_get.ai">Česky (Czech)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/danish_get.ai">Dansk (Danish)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/dutch_get.ai">Nederlands (Dutch)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/estonian_get.ai">Eesti keel (Estonian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/farsi_get.ai">فارسی (Farsi Persian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/filipino_get.ai">Tagalog (Filipino)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/finnish_get.ai">Suomi (Finnish)</a><br/>
-
-</div>
-
-<div class="col-4">
-
-       <a href="{@docRoot}downloads/brand/v2/french_get.ai">Français (French)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/german_get.ai">Deutsch (German)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/greek_get.ai">Ελληνικά (Greek)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/hebrew_get.ai">עברית (Hebrew)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/hindi_get.ai">हिन्दी (Hindi)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/hungarian_get.ai">Magyar (Hungarian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/indonesian_get.ai">Bahasa Indonesia (Indonesian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/italian_get.ai">Italiano (Italian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/japanese_get.ai">日本語 (Japanese)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/kazakh_get.ai">Қазақ тілі (Kazakh)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/korean_get.ai">한국어 (Korean)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/latvian_get.ai">Latviski (Latvian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/lithuanian_get.ai">Lietuviškai (Lithuanian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/malay_get.ai">Bahasa Melayu (Malay)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/norwegian_get.ai">Norsk (Norwegian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/polish_get.ai">Polski (Polish)</a><br/>
-
-</div>
-
-<div class="col-4" style="margin-right:0">
-
-       <a href="{@docRoot}downloads/brand/v2/portugal_portuguese_get.ai">Português (Portuguese)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/brazilian_portuguese_get.ai">Português Brasil (Portuguese Brazil)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/romanian_get.ai">Românã (Romanian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/russian_get.ai">Pусский (Russian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/serbian_get.ai">Српски / srpski (Serbian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/slovak_get.ai">Slovenčina (Slovak)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/slovenian_get.ai">Slovenščina (Slovenian)</a><br/>
-       
-       <a href="{@docRoot}downloads/brand/v2/spanish_get.ai">Español (Spanish)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/spanish_latam_get.ai">Español Latinoamérica (Spanish Latin America)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/swahili_get.ai">Kiswahili (Swahili)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/swedish_get.ai">Svenska (Swedish)</a><br/>
-       
-       <a href="{@docRoot}downloads/brand/v2/thai_get.ai">ภาษาไทย (Thai)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/turkish_get.ai">Türkçe (Turkish)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/uk_generic_rgb_wo.ai">Українська (Ukrainian)</a><br/>
-       <a href="{@docRoot}downloads/brand/vi_generic_rgb_wo.ai">Tiếng Việt (Vietnamese)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/zulu_get.ai">isiZulu (Zulu)</a><br/>
-
-</div>
-<div style="clear:left">&nbsp;</div>
-
-
-
-
-
-
-
-
-
-<hr>
-<img src="{@docRoot}images/brand/en_app_rgb_wo_60.png" alt="Android App On Google Play">
-
-<div style="clear:left">&nbsp;</div>
-
-<div class="col-4" style="margin-left:0">
-
-       <a href="{@docRoot}downloads/brand/v2/english_app.ai">English (English)</a><br/>
-      
-       <a href="{@docRoot}downloads/brand/v2/afrikaans_app.ai">Afrikaans (Afrikaans)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/amharic_app.ai">ኣማርኛ (Amharic)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/arabic_app.ai">العربية (Arabic)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/belarusian_app.ai">Беларуская (Belarusian)</a><br/>
-       
-       <a href="{@docRoot}downloads/brand/v2/bulgarian_app.ai">български (Bulgarian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/catalan_app.ai">Català (Catalan)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/traditional_chinese_app.ai">中文 (中国) (Chinese)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/hongkong_chinese_app.ai">中文(香港) (Chinese Hong Kong)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/taiwan_chinese_app.ai">中文 (台灣) (Chinese Taiwan)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/croatian_app.ai">Hrvatski (Croatian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/czech_app.ai">Česky (Czech)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/danish_app.ai">Dansk (Danish)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/dutch_app.ai">Nederlands (Dutch)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/estonian_app.ai">Eesti keel (Estonian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/farsi_app.ai">فارسی (Farsi Persian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/filipino_app.ai">Tagalog (Filipino)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/finnish_app.ai">Suomi (Finnish)</a><br/>
-
-</div>
-
-<div class="col-4">
-
-       <a href="{@docRoot}downloads/brand/v2/french_app.ai">Français (French)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/german_app.ai">Deutsch (German)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/greek_app.ai">Ελληνικά (Greek)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/hebrew_app.ai">עברית (Hebrew)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/hindi_app.ai">हिन्दी (Hindi)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/hungarian_app.ai">Magyar (Hungarian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/indonesian_app.ai">Bahasa Indonesia (Indonesian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/italian_app.ai">Italiano (Italian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/japanese_app.ai">日本語 (Japanese)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/korean_app.ai">한국어 (Korean)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/latvian_app.ai">Latviski (Latvian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/lithuanian_app.ai">Lietuviškai (Lithuanian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/malay_app.ai">Bahasa Melayu (Malay)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/norwegian_app.ai">Norsk (Norwegian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/polish_app.ai">Polski (Polish)</a><br/>
-
-
-</div>
-
-<div class="col-4" style="margin-right:0">
-
-       <a href="{@docRoot}downloads/brand/v2/portugal_portuguese_app.ai">Português (Portuguese)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/brazilian_portuguese_app.ai">Português Brasil (Portuguese Brazil)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/romanian_app.ai">Românã (Romanian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/russian_app.ai">Pусский (Russian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/serbian_app.ai">Српски / srpski (Serbian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/slovak_app.ai">Slovenčina (Slovak)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/slovenian_app.ai">Slovenščina (Slovenian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/spanish_app.ai">Español (Spanish)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/spanish_latam_app.ai">Español Latinoamérica (Spanish Latin America)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/swahili_app.ai">Kiswahili (Swahili)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/swedish_app.ai">Svenska (Swedish)</a><br/>
-       
-       <a href="{@docRoot}downloads/brand/v2/thai_app.ai">ภาษาไทย (Thai)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/turkish_app.ai">Türkçe (Turkish)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/ukranian_app.ai">Українська (Ukrainian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/vietnamese_app.ai">Tiếng Việt (Vietnamese)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/zulu_app.ai">isiZulu (Zulu)</a><br/>
-
-</div>
-<div style="clear:left">&nbsp;</div>
-
-
-
-
-
-  
-<h2>Guidelines</h2>
-
-  <ul>
-    <li>Do not modify the color, proportions, spacing or any other aspect of the badge image.
-    </li>
-    <li>When used alongside logos for other application marketplaces, the Google Play logo
-    should be of equal or greater size.</li>
-    <li>When used online, the badge should link to either:
-      <ul>
-        <li>A list of products published by you, for example:<br />
-        <span style="margin-left:1em;">http://play.google.com/store/search?q=<em>publisherName</em></span>
-        </li>
-        <li>A specific app product details page within Google Play, for example:<br />
-        <span style="margin-left:1em;">http://play.google.com/store/apps/details?id=<em>packageName</em></span>
-        </li>
-      </ul>
-    </li>
-  </ul>
-  
-<p>For more information, see the
-<a href="{@docRoot}distribute/googleplay/promote/brand.html#brand-google_play">Brand
-Guidelines</a>.
-
-
-<p>To quickly create a badge that links to your apps on Google Play,
-use the <a
-href="{@docRoot}distribute/googleplay/promote/badges.html">Googe Play badge generator</a>.</p>
-    
-    
-    
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/promote/badges.jd b/docs/html/distribute/googleplay/promote/badges.jd
deleted file mode 100644
index 9a32921..0000000
--- a/docs/html/distribute/googleplay/promote/badges.jd
+++ /dev/null
@@ -1,355 +0,0 @@
-page.title=Google Play Badges
-@jd:body
-
-<p itemprop="description">Google Play badges allow you to promote your app with official branding
-in your online ads, promotional materials, or anywhere else you want a link to your app.</p>
-
-<p>In the form below,
-input your app's package name or publisher name, choose the badge style,
-click <em>Build my badge</em>, then paste the HTML into your web content.</p>
-
-<p>If you're creating a promotional web page for your app, you should also use the
-<a href="{@docRoot}distribute/promote/device-art.html">Device Art Generator</a>, which quickly
-wraps your screenshots in real device artwork.</p>
-
-<p>For guidelines when using the Google Play badge and other brand assets,
-see the <a href="{@docRoot}distribute/googleplay/promote/brand.html#brand-google_play">Brand
-Guidelines</a>.</p>
-
-<style type="text/css">
-
-form.button-form {
-  margin-top:2em;
-}
-
-/* the label and input elements are blocks that float left in order to
-   keep the left edgets of the input aligned, and IE 6/7 do not fully support "inline-block" */
-label.block {
-  display: block;
-  float: left;
-  width: 100px;
-  padding-right: 10px;
-}
-
-input.text {
-  display: block;
-  float: left;
-  width: 250px;
-}
-
-div.button-row {
-  white-space:nowrap;
-  min-height:80px;
-}
-
-div.button-row input {
-  vertical-align:middle;
-  margin:0 5px 0 0;
-}
-
-#jd-content div.button-row img {
-  margin: 0;
-  vertical-align:middle;
-}
-
-</style>
-
-<script type="text/javascript">
-
-// locales for which we have the 'app' badge
-var APP_LANGS = ['it','pt-br','pt-pt','nl','ko','ja','fr','es','es-419','en','de'];
-
-// variables for creating 'try it out' demo button
-var imagePath = "https://developer.android.com/images/brand/"
-var linkStart = "<a href=\"https://play.google.com/store/";
-var imageStart = "\">\n"
-        + "  <img alt=\"";
-  // leaves opening for the alt text value
-var imageSrc = "\"\n       src=\"" + imagePath;
-  // leaves opening for the image file name
-var imageEnd = ".png\" />\n</a>";
-
-// variables for creating code snippet
-var linkStartCode = "&lt;a href=\"https://play.google.com/store/";
-var imageStartCode = "\"&gt;\n"
-        + "  &lt;img alt=\"";
-  // leaves opening for the alt text value
-var imageSrcCode = "\"\n       src=\"" + imagePath;
-  // leaves opening for the image file name
-var imageEndCode = ".png\" />\n&lt;/a>";
-
-/** Generate the HTML snippet and demo based on form values */
-function buildButton(form) {
-  var lang = $('#locale option:selected').val();
-  var selectedValue = lang + $('form input[type=radio]:checked').val();
-  var altText = selectedValue.indexOf("generic") != -1 ? "Get it on Google Play" : "Android app on Google Play";
-
-  if (form["package"].value != "com.example.android") {
-    $("#preview").show();
-    var packageName = escapeHTML(form["package"].value);
-    $("#snippet").show().html(linkStartCode + "apps/details?id=" + packageName
-            + imageStartCode + altText + imageSrcCode
-            + selectedValue + imageEndCode);
-    $("#button-preview").html(linkStart + "apps/details?id=" + packageName
-            + imageStart + altText + imageSrc
-            + selectedValue + imageEnd);
-            
-    // Send the event to Analytics
-    _gaq.push(['_trackEvent', 'Distribute', 'Create Google Play Badge', 'Package ' + selectedValue]);
-  } else if (form["publisher"].value != "Example, Inc.") {
-    $("#preview").show();
-    var publisherName = escapeHTML(form["publisher"].value);
-    $("#snippet").show().html(linkStartCode + "search?q=pub:" + publisherName
-            + imageStartCode + altText + imageSrcCode
-            + selectedValue + imageEndCode);
-    $("#button-preview").html(linkStart + "search?q=pub:" + publisherName
-            + imageStart + altText + imageSrc
-            + selectedValue + imageEnd);
-   
-    // Send the event to Analytics
-    _gaq.push(['_trackEvent', 'Distribute', 'Create Google Play Badge', 'Publisher ' + selectedValue]);
-  } else {
-    alert("Please enter your package name or publisher name");
-  }
-  return false;
-}
-
-/** Listen for Enter key */
-function onTextEntered(event, form, me) {
-  // 13 = enter
-  if (event.keyCode == 13) {
-    buildButton(form);
-  }
-}
-
-/** When input is focused, remove example text and disable other input */
-function onInputFocus(object, example) {
-  if (object.value == example) {
-    $(object).val('').css({'color' : '#000'});
-  }
-  $('input[type="text"]:not(input[name='+object.name+'])',
-          object.parentNode).attr('disabled','true');
-  $('#'+object.name+'-clear').show();
-}
-
-/** When input is blured, restore example text if appropriate and enable other input */
-function onInputBlur(object, example) {
-  if (object.value.length < 1) {
-    $(object).attr('value',example).css({'color':'#ccc'});
-    $('input[type="text"]', object.parentNode).removeAttr('disabled');
-    $('#'+object.name+'-clear').hide();
-  }
-}
-
-/** Clear the form to start over */
-function clearLabel(id, example) {
-  $("#preview").hide();
-  $('#'+id+'').html('').attr('value',example).css({'color':'#ccc'});
-  $('input[type="text"]', $('#'+id+'').parent()).removeAttr('disabled');
-  $('#'+id+'-clear').hide();
-  return false;
-}
-
-/** Switch the badge urls for selected language */
-function changeBadgeLang() {
-  var lang = $('#locale option:selected').val();
-  
-  // check if we have the 'app' badge for this lang and show notice if not
-  $("div.button-row.error").remove();  // remove any existing instance of error message
-  if ($.inArray(lang,APP_LANGS) == -1) {
-    $("div.button-row.app").hide();
-    $("div.button-row.app").after('<div class="button-row error"><p class="note" style="margin:1em 0 -1em">'
-        + 'Sorry, we currently don\'t have the '
-        + '<em>Android app on Google Play</em> badge translated for '
-        + $("select#locale option[value="+lang+"]").attr("title")
-        + '.<br>Please check back later or instead use the <em>Get it on Google Play</em> badge below.'
-        + '</p></div>');
-  } else {
-    $("div.button-row.app").show(); // show the 'app' badge row
-  }
-  
-  $('.button-row img').each(function() {
-    var id = $(this).parent().attr('for');
-    var imgName = lang + $('input#'+id).attr('value') + '.png';
-    var lastSlash = $(this).attr('src').lastIndexOf('/');
-    var imgPath = $(this).attr('src').substring(0, lastSlash+1);
-    $(this).attr('src', imgPath + imgName);
-  });
-}
-
-/** When the doc is ready, find the inputs and color the input grey if the value is the example
-    text. This is necessary to handle back-navigation, which can auto-fill the form with previous
-    values (and text should not be grey) */
-$(document).ready(function() {
-  $(".button-form input.text").each(function(index) {
-    if ($(this).val() == $(this).attr("default")) {
-      $(this).css("color","#ccc");
-    } else {
-      /* This is necessary to handle back-navigation to the page after form was filled */
-      $('input[type="text"]:not(input[name='+this.name+'])',
-              this.parentNode).attr('disabled','true');
-      $('#'+this.name+'-clear').show();
-    }
-  });
-});
-
-</script>
-
-<form class="button-form">
-  <label class="block" for="locale">Language:</label>
-  <select id="locale" style="display:block;float:left;margin:0"
-          onchange="changeBadgeLang()">
-    <option title="Afrikaans"
-            value="af">Afrikaans</option>
-    <option title="Arabic"
-            value="ar">العربية</option>
-    <option title="Belarusian"
-            value="be">Беларуская</option>
-    <option title="Bulgarian"
-            value="bg">Български</option>
-    <option title="Catalan"
-            value="ca">Català</option>
-    <option title="Chinese (China)"
-            value="zh-cn">中文 (中国)</option>
-    <option title="Chinese (Hong Kong)"
-            value="zh-hk">中文(香港)</option>
-    <option title="Chinese (Taiwan)"
-            value="zh-tw">中文 (台灣)</option>
-    <option title="Croatian"
-            value="hr">Hrvatski</option>
-    <option title="Czech"
-            value="cs">Česky</option>
-    <option title="Danish"
-            value="da">Dansk</option>
-    <option title="Dutch"
-            value="nl">Nederlands</option>
-    <option title="Estonian"
-            value="et">Eesti</option>
-    <option title="Farsi - Persian"
-            value="fa">فارسی</option>
-    <option title="Filipino"
-            value="fil">Tagalog</option>
-    <option title="Finnish"
-            value="fi">Suomi</option>
-    <option title="French"
-            value="fr">Français</option>
-    <option title="German"
-            value="de">Deutsch</option>
-    <option title="Greek"
-            value="el">Ελληνικά</option>
-    <option title="English"
-            value="en" selected="true">English</option>
-<!--
-    <option title="Hebrew"
-            value="iw-he">עברית</option>
--->
-    <option title="Hungarian"
-            value="hu">Magyar</option>
-    <option title="Indonesian"
-            value="id-in">Bahasa Indonesia</option>
-    <option title="Italian"
-            value="it">Italiano</option>
-    <option title="Japanese"
-            value="ja">日本語</option>
-    <option title="Korean"
-            value="ko">한국어</option>
-    <option title="Latvian"
-            value="lv">Latviešu</option>
-    <option title="Lithuanian"
-            value="lt">Lietuviškai</option>
-    <option title="Malay"
-            value="ms">Bahasa Melayu</option>
-    <option title="Norwegian"
-            value="no">Norsk (bokmål)‎</option>
-    <option title="Polish"
-            value="pl">Polski</option>
-    <option title="Portuguese (Brazil)"
-            value="pt-br">Português (Brasil)</option>
-    <option title="Portuguese (Portugal)"
-            value="pt-pt">Português (Portugal)</option>
-    <option title="Romanian"
-            value="ro">Română</option>
-    <option title="Russian"
-            value="ru">Русский</option>
-    <option title="Serbian"
-            value="sr">Српски / srpski</option>
-    <option title="Slovak"
-            value="sk">Slovenčina</option>
-    <option title="Slovenian"
-            value="sl">Slovenščina</option>
-    <option title="Spanish (Spain)"
-            value="es">Español (España)</option>
-    <option title="Spanish (Latin America)"
-            value="es-419">Español (Latinoamérica)</option>
-    <option title="Swedish"
-            value="sv">Svenska</option>
-    <option title="Swahili"
-            value="sw">Kiswahili</option>
-    <option title="Thai"
-            value="th">ไทย</option>
-    <option title="Turkish"
-            value="tr">Türkçe</option>
-    <option title="Ukrainian"
-            value="uk">Українська</option>
-    <option title="Vietnamese"
-            value="vi">Tiếng Việt</option>
-    <option title="Zulu"
-            value="zu">isiZulu</option>
-  </select>
-  <p style="clear:both;margin:0">&nbsp;</p>
-  <label class="block" for="package" style="clear:left">Package name:</label>
-  <input class="text" type="text" id="package" name="package"
-         value="com.example.android"
-         default="com.example.android"
-         onfocus="onInputFocus(this, 'com.example.android')"
-         onblur="onInputBlur(this, 'com.example.android')"
-         onkeyup="return onTextEntered(event, this.parentNode, this)"/>&nbsp;
-         <a id="package-clear" style="display:none" href="#"
-            onclick="return clearLabel('package','com.example.android');">clear</a>
-  <p style="clear:both;margin:0">&nbsp;<em>or</em></p>
-  <label class="block" style="margin-top:5px" for="publisher">Publisher&nbsp;name:</label>
-  <input class="text" type="text" id="publisher" name="publisher"
-         value="Example, Inc."
-         default="Example, Inc."
-         onfocus="onInputFocus(this, 'Example, Inc.')"
-         onblur="onInputBlur(this, 'Example, Inc.')"
-         onkeyup="return onTextEntered(event, this.parentNode, this)"/>&nbsp;
-         <a id="publisher-clear" style="display:none" href="#"
-            onclick="return clearLabel('publisher','Example, Inc.');">clear</a>
-         <br/><br/>
-
-
-<div class="button-row app">
-  <input type="radio" name="buttonStyle" value="_app_rgb_wo_45" id="ws" />
-    <label for="ws"><img src="{@docRoot}images/brand/en_app_rgb_wo_45.png"
-alt="Android app on Google Play (small)" /></label>
-    &nbsp;&nbsp;&nbsp;&nbsp;
-  <input type="radio" name="buttonStyle" value="_app_rgb_wo_60" id="wm" />
-    <label for="wm"><img src="{@docRoot}images/brand/en_app_rgb_wo_60.png"
-alt="Android app on Google Play (large)" /></label>
-</div>
-
-<div class="button-row">
-  <input type="radio" name="buttonStyle" value="_generic_rgb_wo_45" id="ns" checked="checked" />
-    <label for="ns"><img src="{@docRoot}images/brand/en_generic_rgb_wo_45.png"
-alt="Get it on Google Play (small)" /></label>
-    &nbsp;&nbsp;&nbsp;&nbsp;
-  <input type="radio" name="buttonStyle" value="_generic_rgb_wo_60" id="nm" />
-    <label for="nm"><img src="{@docRoot}images/brand/en_generic_rgb_wo_60.png"
-alt="Get it on Google Play (large)" /></label>
-</div>
-
-  <input class="button" onclick="return buildButton(this.parentNode);"
-    type="button" value="Build my badge" style="padding:10px" />
-  <br/>
-</form>
-
-<div id="preview" style="display:none">
-  <p>Copy and paste this HTML into your web site:</p>
-  <textarea id="snippet" cols="100" rows="5" onclick="this.select()"
-style="font-family:monospace;background-color:#efefef;padding:5px;display:none;margin-bottom:1em">
-  </textarea >
-
-<p>Try it out:</p>
-<div id="button-preview" style="margin-top:1em"></div>
-</div>
diff --git a/docs/html/distribute/googleplay/promote/brand.jd b/docs/html/distribute/googleplay/promote/brand.jd
deleted file mode 100644
index 0bda561..0000000
--- a/docs/html/distribute/googleplay/promote/brand.jd
+++ /dev/null
@@ -1,193 +0,0 @@
-page.title=Brand Guidelines
-@jd:body
-
-
-
-<p>We encourage you to use the Android and Google Play brands with your Android app
-promotional materials. You can use the icons and other assets on this page
-provided that you follow the guidelines described below.</p>
-
-<h2 id="brand-android">Android</h2>
-
- <p>The following are guidelines for the Android brand
- and related assets.</p>
- 
-
-  <h4 style="clear:right">Android in text</h4>
-    
-  <div style="float:right;clear:right;width:200px;margin:0 0 20px 30px">
-    <img alt="" src="{@docRoot}images/brand/mediaplayer.png">
-  </div>
-    <ul>
-    <li>Android&trade; should have a trademark symbol the first time it appears in a creative.</li>
-    <li>Android should always be capitalized and is never plural or possessive.</li>
-    <li>"Android" cannot be used in names of applications or accessory products,
-    including phones, tablets, TVs, speakers, headphones, watches, and other devices. Instead use "for Android".
-      <ul>
-        <li><span style="color:red">Incorrect</span>: "Android MediaPlayer"</li>
-        <li><span style="color:green">Correct</span>: "MediaPlayer for Android"</li>
-      </ul>
-      <p>If used with your logo, "for Android" needs to be smaller in size than your logo.
-      First instance of this use should be followed by a TM symbol, "for Android&trade;".</p>
-    </li>
-    <li>Android may be used as a descriptor, as long as it is followed by a proper generic term.
-      <ul>
-        <li><span style="color:red">Incorrect</span>: "Android MediaPlayer" or "Android XYZ app"</li>
-        <li><span style="color:green">Correct</span>: "Android features" or "Android applications"</li>
-      </ul>
-    </li>
-    </ul>
-  
-    <p>Any use of the Android name needs to include this
-    attribution in your communication:</p>
-    <blockquote><em>Android is a trademark of Google Inc.</em></blockquote></p>
-
-
- <h4>Android robot</h4>
-
-  <div style="float:right;width:200px;margin-left:30px">
-    <img alt="" src="{@docRoot}images/brand/Android_Robot_100.png"
-      style="margin-left:50px">
-    <p style="text-align:center">
-       <a href="{@docRoot}images/brand/Android_Robot_100.png">100x118</a> |
-       <a href="{@docRoot}images/brand/Android_Robot_200.png">200x237</a><br>
-       <a href="{@docRoot}downloads/brand/Android_Robot_outlined.ai">Illustrator (.ai)</a></p>
-  </div>
-
-    <p>The Android robot can be used, reproduced, and modified freely in marketing
-    communications. The color value for print is PMS 376C and the online hex
-    color is <span style="color:#A4C639">#A4C639</span>.</p>
-
-    <p>When using the Android Robot or any modification of it, proper attribution is
-    required under the terms of the <a href="http://creativecommons.org/licenses/by/3.0/">Creative
-Commons Attribution</a> license:</p>
-   
-    <blockquote><em>The Android robot is reproduced or modified from work created and shared by Google and
-used according to terms described in the Creative Commons 3.0 Attribution License.</em></blockquote>
-    
-    <p>You may not file trademark applications incorporating the Android robot logo or
-derivatives thereof. We want to ensure that the Android robot remains available
-for all to use.</p>
-
-
-<h4 style="clear:right">Android logo</h4>
-
-<div style="float:right;width:210px;margin-left:30px;margin-top:-10px">
-  <img alt="" src="{@docRoot}images/brand/android_logo_no.png">
-</div>
-
-<p>The Android logo may not be used. Nor can this be used with the Android robot.</p>
-<p>The custom typeface may not be used.</p>
-
-
-
-
-<h2 id="brand-google_play">Google Play</h2>
-
-
- <p>The following are guidelines for the Google Play brand
- and related assets.</p>
-
-<h4>Google Play in text</h4>
-
-<p>Always include a TM symbol on the first or most prominent instance of Google Play&trade;
-in text.</p>
-
-<p>When referring to the mobile experience, use "Google Play" unless the text is clearly
-instructional for the user. For example, a marketing headline might read "Download our
-games on Google Play&trade;," but instructional text would read "Download our games using the Google
-Play&trade; Store app."
-
- <p>Any use of the Google Play name or icon needs to include this
-    attribution in your communication:</p>
-
-<blockquote><em>Google Play is a trademark of Google Inc.</em></blockquote>
-
-
-  <div style="float:right;width:96px;margin-left:30px;margin-top:-20px">
-     <img src="{@docRoot}images/brand/Google_Play_Store_96.png" alt="">
-    <p style="text-align:center">
-       <a href="{@docRoot}images/brand/Google_Play_Store_48.png">48x48</a> |
-       <a href="{@docRoot}images/brand/Google_Play_Store_96.png">96x96</a><br>
-       <a href="{@docRoot}downloads/brand/Google_Play_Store.ai">Illustrator (.ai)</a>
-       </p>
-  </div>
-  
-<h4>Google Play Store icon</h4>
-
-<p>You may use the Google Play Store icon, but you may not modify it.</p>
-
-<p>As mentioned above, when referring to the Google Play Store app in copy, use the full name:
-"Google Play Store." However, when labeling the Google Play Store icon directly, it's OK to use
-"Play Store" alone to accurately reflect the icon label as it appears on a device.</p>
-
-        
-<h4>Google Play badge</h4>
-      
-  <div style="float:right;clear:right;width:172px;margin-left:30px">
-    <img src="{@docRoot}images/brand/en_app_rgb_wo_60.png" alt="">
-    <p style="text-align:center">
-       <a href="{@docRoot}images/brand/en_app_rgb_wo_45.png">129x45</a> |
-       <a href="{@docRoot}images/brand/en_app_rgb_wo_60.png">172x60</a></p>
-  </div>
-      
-  <div style="float:right;clear:right;width:172px;margin-left:30px">
-    <img src="{@docRoot}images/brand/en_generic_rgb_wo_60.png" alt="">
-    <p style="text-align:center">
-       <a href="{@docRoot}images/brand/en_generic_rgb_wo_45.png">129x45</a> |
-       <a href="{@docRoot}images/brand/en_generic_rgb_wo_60.png">172x60</a></p>
-  </div>
-         
-  <p>The "Get it on Google Play" and "Android App on Google Play" logos are badges that you
-    can use on your web site and promotional materials, to point to your products on Google
-    Play.</p>
-
-  <ul>
-    <li>Do not modify the color, proportions, spacing or any other aspect of the badge image.
-    </li>
-    <li>When used alongside logos for other application marketplaces, the Google Play logo
-    should be of equal or greater size.</li>
-    <li>When used online, the badge should link to either:
-      <ul>
-        <li>A list of products published by you, for example:<br />
-        <span style="margin-left:1em;">http://play.google.com/store/search?q=<em>publisherName</em></span>
-        </li>
-        <li>A specific app product details page within Google Play, for example:<br />
-        <span style="margin-left:1em;">http://play.google.com/store/apps/details?id=<em>packageName</em></span>
-        </li>
-      </ul>
-    </li>
-  </ul>
-  
-  <p>To quickly create a badge that links to your apps on Google Play,
-  use the <a
-  href="{@docRoot}distribute/googleplay/promote/badges.html">Googe Play badge generator</a>
-  (provides the badge in over 40 languages).</p>
-  
-  <p>To create your own size, download an Adobe&reg; Illustrator&reg; (.ai) file for the
-  <a href="{@docRoot}distribute/googleplay/promote/badge-files.html">Google Play
-  badge in over 40 languages</a>.</p>
-    
-  <p>For details on all the ways that you can link to your product details page in Google Play, 
-    see <a href="{@docRoot}distribute/googleplay/promote/linking.html">Linking to your products</a></p>
-
-
-
-<h2 id="Questions">Questions</h2>
-
-<p>To view our full guidelines or for any further brand usage questions, please contact our
-Android Partner Marketing team:</p>
-<ul>
-  <li>For North and South America, please contact <a
-  href="mailto:android-brand-approvals@google.com?Subject=Brand%20Approval%20Questions"
-  >android-brand-approvals@google.com</a></li>
-
-  <li>For Europe and Emerging Markets, please contact <a
-  href="mailto:emea-android-brand@google.com?Subject=Brand%20Approval%20Questions"
-  >emea-android-brand@google.com</a></li>
-
-  <li>For Asia and Pacific-America, please contact <a
-  href="mailto:apac-android-brand-approvals@google.com?Subject=Brand%20Approval%20Questions"
-  >apac-android-brand-approvals@google.com</a></li>
-</ul>
-
diff --git a/docs/html/distribute/googleplay/promote/index.jd b/docs/html/distribute/googleplay/promote/index.jd
deleted file mode 100644
index 6882990..0000000
--- a/docs/html/distribute/googleplay/promote/index.jd
+++ /dev/null
@@ -1,43 +0,0 @@
-page.title=Promoting Your Apps
-page.metaDescription=Raise the visibility of your apps in Google Play through deep links  and Google Play badges.
-header.hide=0
-footer.hide=0
-@jd:body
-
-<!--
-<style>
-#landing-graphic-container {
-  position: relative;
-}
-
-#text-overlay {
-  position: absolute;
-  left: 0;
-  top: 472px;
-  width: 280px;
-}
-</style>
-
-<div id="landing-graphic-container">
-  <div id="text-overlay">
-   Raise the visibility of your apps with badges and link users to your products on Google Play.
-    <br><br>
-    <a href="{@docRoot}distribute/googleplay/promote/product-pages.html" class="landing-page-link">Your Product Pages</a>
-  </div>
-
-  <a href="{@docRoot}distribute/googleplay/promote/index.html">
-    <img src="{@docRoot}design/media/index_landing_page.png">
-  </a>
-</div> -->
-
-<p>After you publish your app, you can bring Android users to your app's product details page by
-providing links in your social network posts, ad campaigns, app reviews and articles, your
-web site, and more. </p>
-
-<p>You can use the resources in this section to create deep links for your online placements.
-Google Play badges are an especially great way let Android users know that your app is available
-and link them directly to your download page. With the badge generator, they're also easy to make.</p>
-
-
-<p style="margin-top:1.5em;margin-bottom:1.5em;"><a href="{@docRoot}distribute/googleplay/promote/linking.html" class="landing-page-link">Linking to Your Products</a></p>
-
diff --git a/docs/html/distribute/googleplay/promote/linking.jd b/docs/html/distribute/googleplay/promote/linking.jd
deleted file mode 100644
index 4fdc5db..0000000
--- a/docs/html/distribute/googleplay/promote/linking.jd
+++ /dev/null
@@ -1,213 +0,0 @@
-page.title=Linking to Your Products
-@jd:body
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<a href="badges.html">
-  <img alt="Get it on Google Play"
-       src="{@docRoot}images/brand/en_app_rgb_wo_45.png" />
-</a>
-<p>For a link that includes the Google Play brand icon, check out the <a href="badges.html">Badges</a> page. </p>
-</div>
-</div>
-
-<p>Google Play provides several link formats that let you bring users to your
-products in the way you want, from Android apps, web pages, ads, reviews,
-articles, social media posts, and more.</p> 
-
-<p>The link formats let you:</p>
-<ul>
-<li>Link to a specific app's <a href="#OpeningDetails">product details page</a></li>
-<li>Link to a <a href="#OpeningPublisher">list of all of your apps</a>, or</li>
-<li>Link to a <a href="#PerformingSearch">search result</a> of your choice</li>
-<li>Link to a <a href="#OpeningCollection">collection</a> on Google Play</li>
-</ul>
-
-<p>If you are linking from an Android app, you can also control whether the link
-launches the Play Store application or the browser, which takes the user
-to the Google Play web site.</p>
-
-<h2 id="OpeningDetails">Linking to a Product Details Page</h2>
-
-<p>Use the format below to deep-link users directly to a specific app's product
-details page. At the product details page, users can see the app description,
-screenshots, reviews and more, and then install it.</p>
-
-<p>To create the link, you need to know the app's fully qualified <em>package
-name</em>, which is declared in the app's <a
-href="{@docRoot}guide/topics/manifest/manifest-element.html#package">manifest
-file</a>. The package name is also visible in the Developer Console. </p>
-
-<dl>
-<dt><strong>From a web site:</strong></dt>
-<dd>
-<pre>http://play.google.com/store/apps/details?id=&lt;package_name&gt;</pre>
-</dd>
-<dt><strong>From an Android app:</strong></dt>
-<dd>
-<pre>market://details?id=&lt;package_name&gt;</pre>
-</dd>
-</dl>
-
-<p>Here's an example:</p>
-
-<p style="margin-left:1em;"><code><a href="http://play.google.com/store/apps/details?id=com.google.android.apps.maps">http://play.google.com/store/apps/details?id=com.google.android.apps.maps</a></code></p>
-
-<p>For details on how to send the link in an Android app, see <a href="#android-app">Linking from an Android App</a>.</p>
-
-
-
-<h2 id="OpeningPublisher">Linking to a Product List</h2>
-
-<p>Use the format below to link users to a list of apps published by you. The
-product list lets users see all of the apps from a specific publisher, with
-ratings, editorial badges, and an Install button for each. </p>
-
-<p>To create the link, you need to know your <em>publisher name</em>, which is
-available from the Developer Console. </p>
-
-<dl>
-<dt><strong>From a web site:</strong></dt>
-<dd>
-<pre>http://play.google.com/store/search?q=pub:&lt;publisher_name&gt;</pre>
-</dd>
-<dt><strong>From an Android app:</strong></dt>
-<dd>
-<pre>market://search?q=pub:&lt;publisher_name&gt;</pre>
-</dd>
-</dl>
-
-<p>Here's an example:</p>
-
-<p style="margin-left:1em;"><code><a href="http://play.google.com/store/search?q=pub:Google Inc.">http://play.google.com/store/search?q=pub:Google Inc.</a></code></p>
-
-<p>For details on how to send the link in an Android app, see <a href="#android-app">Linking from an Android App</a>.</p>
-
-
-<h2 id="PerformingSearch">Linking to a Search Result</h2>
-
-<p>Use the format below to link users to a search query result on Google Play.
-The search result page shows a list of apps (and optionally other content) that
-match the query, with ratings, badges, and an Install button for each. </p>
-
-<p>To create the link, you just need a search query string. If you want the
-query to search outside of the Google Play Apps listings, you can remove the
-<code>&c=apps</code> part of the link URL.</p>
-
-<dl>
-<dt><strong>From a web site:</strong></dt>
-<dd>
-<pre>http://play.google.com/store/search?q=&lt;search_query&gt;&c=apps</pre>
-</dd>
-<dt><strong>From an Android app:</strong></dt>
-<dd>
-<pre>market://search?q=&lt;seach_query&gt;&c=apps</pre>
-</dd>
-</dl>
-
-<p>Here's an example:</p>
-
-<p style="margin-left:1em;"><code><a href="http://play.google.com/store/search?q=maps&c=apps">http://play.google.com/store/search?q=maps&c=apps</a></code></p>
-
-<p>For details on how to send the link in an Android app, see <a href="#android-app">Linking from an Android App</a>.</p>
-
-
-
-<h2 id="OpeningCollection">Linking to a Collection</h2>
-
-<p>If your app is featured or appears in one of the Google Play Top charts or
-collections, you can use the format below to link users directly to the
-collection. The collection shows a ranked list of apps in the collection, with
-ratings, short descriptions, and an Install button.</p>
-
-<dl>
-<dt><strong>From a web site:</strong></dt>
-<dd>
-<pre>http://play.google.com/store/apps/collection/&lt;collection_name&gt;</pre>
-</dd>
-<dt><strong>From an Android app:</strong></dt>
-<dd>
-<pre>market://apps/collection/&lt;collection_name&gt;</pre>
-</dd>
-</dl>
-
-<p>Here's an example:</p>
-
-<p style="margin-left:1em;"><code><a href="http://play.google.com/store/apps/collection/editors_choice">http://play.google.com/store/apps/collection/editors_choice</a></code></p>
-
-<p>For details on how to send the link in an Android app, see <a href="#android-app">Linking from an Android App</a>.</p>
-
-<p class="table-caption"><strong>Table 1.</strong> Collections on Google Play</a>.</p>
-
-<table>
-<tr>
-<th>Collection</th><th>collection_name</th>
-</tr>
-<tr><td>Staff Picks (Featured)</td><td>featured</td></tr>
-<tr><td>Editor's Choice</td><td>editors_choice</td></tr>
-<tr><td>Top Paid</td><td>topselling_paid</td></tr>
-<tr><td>Top Free</td><td>topselling_free</td></tr>
-<tr><td>Top New Free</td><td>topselling_new_free</td></tr>
-<tr><td>Top New Paid</td><td>topselling_new_paid</td></tr>
-<tr><td>Top Grossing</td><td>topgrossing</td></tr>
-<tr><td>Trending</td><td>movers_shakers</td></tr>
-<tr><td>Best Selling in Games</td><td>topselling_paid_game</td></tr>
-</table>
-
-
-<h2 id="android-app">Linking from an Android App</h2>
-
-<p>There are two general formats for links that are accessible to users on
-Android devices, The two formats trigger slightly different behaviors on the
-device:</p>
-
-<ul>
-<li><code>market://</code> &nbsp;&nbsp; Launches the Play Store app to load the
-target page.</li>
-<li><code>http://</code> &nbsp;&nbsp; Lets the user choose whether to launch the
-Play Store app or the browser to handle the request. If the browser handles the
-request, it loads the target page on the Google Play web site.</li>
-</ul>
-
-<p>In general, you should use <code>http://</code> format for links on web pages
-and <code>market://</code> for links in Android apps.</p>
-
-<p>If you want to link to your products from an Android app, create an {@link
-android.content.Intent} that opens an Google Play URL, as shown in the example
-below.</p>
-
-<pre>
-Intent intent = new Intent(Intent.ACTION_VIEW);
-intent.setData(Uri.parse("market://details?id=com.example.android"));
-startActivity(intent);
-</pre>
-
-
-<h2 id="UriSummary">Summary of URL formats</h2>
-
-<p>The table below provides a summary of the URIs currently supported by the Google Play (both on
-the web and in an Android application), as discussed in the previous sections.</p>
-
-<table>
-<tr>
-<th>For&nbsp;this&nbsp;result</th>
-<th>Web page link</th>
-<th>Android app link</th>
-</tr>
-<tr>
-<td style="width:72px;">Show the product details page for a specific app</td>
-<td><code>http://play.google.com/store/apps/details?id=&lt;package_name&gt;</code>
-<td><code>market://details?id=&lt;package_name&gt;</code></td>
-</tr>
-<tr>
-<td>Show apps by a specific publisher</td>
-<td><nobr><code>http://play.google.com/store/search?q=pub:&lt;publisher_name&gt;</code></nobr></td>
-<td><nobr><code>market://search?q=pub:&lt;publisher_name&gt;</code></nobr></td>
-</tr>
-<tr>
-<td>Search for apps using a general string query.</td>
-<td><code>http://play.google.com/store/search?q=&lt;query&gt;</code></td>
-<td><code>market://search?q=&lt;query&gt;</code></td>
-</tr>
-</table>
-
diff --git a/docs/html/distribute/googleplay/promote/product-pages.jd b/docs/html/distribute/googleplay/promote/product-pages.jd
deleted file mode 100644
index af5b2d5..0000000
--- a/docs/html/distribute/googleplay/promote/product-pages.jd
+++ /dev/null
@@ -1,4 +0,0 @@
-page.title=Your Product Pages
-@jd:body
-
-<p>Placeholder...</p>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/publish/console.jd b/docs/html/distribute/googleplay/publish/console.jd
deleted file mode 100644
index 3831e51..0000000
--- a/docs/html/distribute/googleplay/publish/console.jd
+++ /dev/null
@@ -1,198 +0,0 @@
-page.title=Developer Console
-@jd:body
-
-
-<p>Once you've <a
-href="{@docRoot}distribute/googleplay/publish/register.html">registered</a> and
-received verification by email, you can sign in to your Google Play
-Developer Console, which will be the home for your app publishing operations and
-tools on Google Play. This sections below introduce a few of the key areas
-you'll find in the Developer Console.</p>
-
-<div class="figure" style="width:756px;">
-<img src="{@docRoot}images/gp-dc-home.png" class="frame">
-<p class="img-caption"><strong>All applications page</strong>: Gives you a quick
-overview of your apps, lets you jump to stats, reviews, and product details, or
-upload a new app. </p>
-</div>
-
-<div class="figure-right" style="width:450px;">
-<img src="{@docRoot}images/gp-dc-profile.png" class="frame">
-<p class="img-caption"><strong>Account details page</strong>: Specifies your developer
-identity and contact information, accounts for app testing, and more.</p>
-</div>
-
-<h3 id="profile">Your account details</h3>
-
-<p>The account details page is where you specify basic information about yourself
-or your company in a developer profile. The information in your developer profile
-is important because it identifies you to Google Play and also to your customers.</p>
-
-<p>During registration you must provide the information for your profile, but you can
-go back at any time to edit the information and change your settings. </p>
-
-<p>Your developer profile contains:</p>
-<ul>
-<li>Your developer name &mdash; the name you want to show users on your store
-listing page and elsewhere on Google Play. </li>
-<li>Your developer contact information &mdash; how Google can contact you if
-needed (this information isn't exposed to users).</li>
-<li>Your developer website URL &mdash; shown to users on your store listing page
-so they can learn more about your company or products.</li>
-</ul>
-
-<p>On the account details page you can also register for a merchant account, set
-up test accounts for Google Play licensing, and more. </p>
-
-<h3 id="user-accounts">Multiple user accounts</h3>
-
-<p>If you are working with a team, you can set up multiple user accounts to
-access different parts of your Developer Console. The first account registered
-is the <em>account owner</em>, with full access to all parts of the Console. The
-owner can add <em>user accounts</em> and manage what parts of the Console they
-have access to. For example, an owner can grant users access to publishing and
-app configuration, but not access to financial reports. </p>
-
-
-<div class="figure-right" style="width:450px;">
-<img src="{@docRoot}images/gp-dc-details.png" class="frame">
-<p class="img-caption"><strong>Store listing page</strong>: Lets you upload your
-graphic assets, description, support information, and other information to
-create the store listing page for a specific app.</p>
-</div>
-
-<h3 id="merchant">Linking your Merchant Account</h3>
-
-<p>If you want to sell apps or in-app products, you can link your Google
-Wallet merchant account to your developer profile. Google Play uses the linked
-merchant account for financial and tax identification and monthly payouts of
-sales. </p>
-
-<h3 id="details">Your store listing details</h3>
-
-<p>The Developer Console lets you set up a colorful storefront page for your app
-called the <em>Store Listing page</em>. Your Store Listing page is the home
-for your app in Google Play &mdash; it's the page users see on their mobile
-phones or on the web when they want to learn about your app and download it.
-</p>
-
-<p>You can upload custom brand assets, screen shots, and videos to highlight
-what's great about your app, and you can provide a localized description, add
-notes about the latest version, and more. You can update your store listing at
-any time, even if you don’t have a new version of your application.</p>
-
-<h3 id="uploading">Uploading and publishing</h3>
-
-<p>From the Developer Console you can quickly upload a release-ready APK and
-publish it when you're ready. The app is a <em>draft</em> until you publish it,
-at which time Google Play makes your store listing page and app available to
-users. You can unpublish the app at any time.</p>
-
-<h3 id="controls">Distribution controls</h3>
-
-<p>In the Developer Console you can manage what countries and territories the
-app is distributed to and, for some countries, you can choose what carriers you
-want to target.</p>
-
-<p>You can also see the list of devices that your app is currently available to,
-based on any distribution rules declared in its manifest file.</p>
-
-<h3 id="selling">Selling and pricing your products</h3>
-
-<p>The Developer Console gives you tools to set prices for your apps and in-app
-products. Your app can either be free to download or priced (charged before
-download). </p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<p>See <a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138294&topic=2365624&ctx=topic">Supported locations for distributing applications</a> for a list of countries where you can distribute or sell your app,</p>
-</div>
-</div>
-
-<ul>
-<li>If you publish your app as free, <span style="font-weight:500;">it must
-remain free</span>. Free apps can be downloaded by any users in Google
-Play.</li>
-<li>If you publish it as priced, you can later change it to free. Priced apps can be
-purchased and downloaded only by users who have registered a form of payment
-in Google Play.</li>
-</ul>
-
-<p>In addition, you can sell in-app products and subscriptions in your app,
-whether the app is free or priced. You can set prices separately for priced apps,
-in-app products, and subscriptions.</p>
-
-<p>If you are selling a priced app or in-app products or subscriptions, the
-Developer Console lets you set prices in a large number of different currencies.
-When users around the world visit your store listing, they see the price
-of your app in their own currency. For most countries, the price you set is the
-final price charged to users, inclusive of taxes. </p>
-
-<p>To help you manage your prices, the Developer Console provides an autofill
-capability that uses recent exchange rates to populate the prices in all
-supported currencies. You can change prices for apps and in-app products at any
-time, just by saving changes in the Developer Console.</p>
-
-<h3>In-app Billing</h3>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>In-app Billing</h2>
-<p>For details on how to implement In-app Billing, see the
-<a href="{@docRoot}google/play/billing/index.html">In-app Billing</span></a>
-developer documentation.</p></div></div>
-
-<p><a href="{@docRoot}google/play/billing/index.html">In-app Billing</a> is
-a Google Play service that lets you monetize your apps in more ways by selling
-in-app products and subscriptions. In-app products are one-time purchases, while
-subscriptions are recurring charges on an monthly or annual basis.</p>
-
-<p>From the Developer Console you can create product lists for in-app
-products and subscriptions, set prices, and publish.</p>
-
-<div class="figure-right" style="width:410px;">
-<img src="{@docRoot}images/gp-dc-reviews.png" class="frame">
-<p class="img-caption"><strong>User
-reviews page</strong>: Gives you access to user reviews for a specific app.
-You can filter  reviews in a number of ways to locate issues more easily
-and support your customers more effectively.</p>
-</div>
-
-<h3>User reviews and crash reports</h3>
-
-<p>Google Play makes it easy for users to submit reviews of your app for the
-benefit of other users. The reviews are also extremely important to you, since
-they give you usability feedback, support requests, and important functionality
-issues direct from your customers. </p>
-
-<p>The Developer Console also lets you see crash reports, with stack trace and
-other data, submitted automatically from Android devices, for debugging and
-improving your app.</p>
-
-<h3>App statistics</h3>
-
-<p>The Developer Console gives you detailed statistics on the install
-performance of your app. </p>
-
-<p>You can view installations of your app measured by unique users, as well as
-by unique devices. For user installations, you can view active installs, total
-installs, daily installs and uninstalls, and metrics about user ratings.
-For devices, you can see active
-installs as well as daily installs, uninstalls, and upgrades.</p>
-
-<p>You can zoom into the installation numbers along several dimensions,
-including Android platform version, device, country, language, app version, and
-carrier (mobile operator). You can see the installation data for each dimension
-on a timeline charts.</p>
-
-<p>At a glance, these charts highlight your app’s installation peaks and
-longer-term trends, which you can correlate to promotions, app improvements, or
-other factors. You can even focus in on data inside a dimension by adding
-specific points (such as individual platform versions or languages) to the
-timeline.</p>
-
-<div style="width:530px;">
-<img src="{@docRoot}images/gp-dc-stats.png" class="frame">
-<p class="img-caption"><strong>App statistics page</strong>: Shows you a variety
-of statistics about a specific app's installation performance over time.</p>
-</div>
diff --git a/docs/html/distribute/googleplay/publish/index.jd b/docs/html/distribute/googleplay/publish/index.jd
deleted file mode 100644
index 5a5eaf2..0000000
--- a/docs/html/distribute/googleplay/publish/index.jd
+++ /dev/null
@@ -1,23 +0,0 @@
-page.title=Publishing on Google Play
-header.hide=1
-footer.hide=1
-page.metaDescription=Get started publishing apps on Google Play.
-
-@jd:body
-
-<div style="height:413px;padding-top:50px;">
-    <img src="{@docRoot}images/gp-devconsole-home.png" style="margin-top:0px;">
-</div>
-
-<div style="width:460px;padding-bottom:40px;margin-left:1.5em;"> 
-  <p>Upload apps, build your product pages, configure prices and
-  distribution, and publish. You can manage all phases of publishing
-  on Google Play through the Developer Console, from any web browser.</p>
-
-<p style="margin-top:1.5em;margin-bottom:1.5em;"><a href="{@docRoot}distribute/googleplay/publish/register.html" class="landing-page-link">Get started</a></p>
-</div>
-
-
-
-
-
diff --git a/docs/html/distribute/googleplay/publish/localizing.jd b/docs/html/distribute/googleplay/publish/localizing.jd
deleted file mode 100644
index 30f10b7..0000000
--- a/docs/html/distribute/googleplay/publish/localizing.jd
+++ /dev/null
@@ -1,600 +0,0 @@
-page.title=Localization Checklist
-page.tags=localize,localization,resources,formats,l10n
-@jd:body
-
-<div id="qv-wrapper"><div id="qv">
-<h2>Checklist</h2>
-<ol>
-<li><a href="#target-languages">1. Identify target languages</a></li>
-<li><a href="#design">2. Design for localization</a></li>
-<li><a href="#strings">3. Manage strings for localization</a></li>
-<li><a href="#translate">4. Translate UI strings</a></li>
-<li><a href="#test">5. Test your localized app</a></li>
-<li><a href="#prelaunch">6. Prepare for international launch</a></li>
-<li><a href="#support">7. Support international users</a></li>
-</ol>
-<h2>See Also</h2>
-<ol>
-<li><a href="{@docRoot}distribute/googleplay/promote/badges.html">Google Play Badge Builder</a></li>
-<li><a href="{@docRoot}distribute/promote/device-art.html">Device Art Generator</a></li>
-<li><a href="#gp-trans">Translations in Google Play</a></li>
-<li><a href="{@docRoot}sdk/installing/installing-adt.html#tmgr">ADT Translation Manager Plugin</a></li>
-</ol>
-</div></div>
-
-<p>Android and Google Play give you a worldwide audience for your app, with an
-addressable user base that's growing very rapidly in countries such as Japan,
-Korea, India, Brazil, Russia, and elsewhere. </p>
-
-<p>To maximize your app's distribution potential and earn high ratings from
-users around the world, we strongly encourage you to localize your app. </p>
-
-<p>Localization involves a variety of tasks throughout your app's development
-cycle, and advance planning is essential. Some of the tasks include
-translating your UI strings and localizing dates and times, layouts, text
-direction, and finally your Google Play store listing. </p>
-
-<p>This document helps you identify key aspects of localization to prepare for
-and the tasks you'll need to perform, to get your app ready for a
-successful worldwide launch on Google Play.</p>
-
-
-<h2 id="target-languages">1. Identify target languages and locales</h2>
-
-<p>A basic but important step in preparing for localization is identifying the
-countries where you will distribute your app and the languages spoken there.
-Google Play lets you distribute your app broadly to hundreds of countries, reaching
-users who speak a variety of languages. </p>
-
-<p>For international users, you can manage your app on three main dimensions:
-country, locale, and language. Of those, language is the key consideration for
-localization, although locale is also significant because of differences in
-formats for dates, times, currencies, and similar information. Users control
-both the language and locale used on their Android devices and in turn those
-affect the display of your app, once installed.</p>
-
-<p>Typically, you would decide which countries to target first, based on overall
-market size and opportunity, app category, competitive landscape, local pricing
-and financial factors, and so on. Then, based on your country targeting, you
-would determine the languages you need to support in your app. </p>
-
-<p>You will need to decide when to localize into some or all of the languages in your targeted countries. In some countries it might make most sense to deliver an app
-in a major regional or international language only, rather than in all locally
-spoken languages. Similarly, based on overall market size, you might decide to
-deliver your app in only a small number of key languages and offer English or
-another language for other countries. You can add more languages in the future
-as your app's userbase grows.</p>
-
-<p>Localizing your app is particularly important in countries where there is a
-large market opportunity and English or another international language is not
-widely used. Once you have identified your target languages, you can focus your
-development, translation, testing, and marketing efforts to these markets.</p>
-
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138294&topic=2365624&ctx=topic">Supported locations for distributing applications</a></strong> on Google Play.
-.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-
-<h2 id="design">2. Design for localization</h2>
-
-<p>After you've determined your target languages for localization, assess what
-you'll need to do to support them in your app and plan the work early. Consider
-the vocabulary expansion, script requirements, character spacing and wrapping
-constraints, left-to-right and right-to-left support, and other potential
-factors in each language.
-
-<h4>Design a single set of flexible layouts</h4>
-
-<p>As you create your layouts, make sure that any UI elements that hold text are
-designed generously. It’s good to allow more space than necessary for your
-language (up to 30% more is normal) to accommodate other languages.</p>
-
-<p>Also, elements should be able to expand horizontally or vertically to
-accommodate variations in the width and height of UI strings or input text. Your
-text strings should not overlap borders or the screen edge in any of your target
-languages.</p>
-
-<p>If you design your UI carefully, you can typically use a single set of
-layouts for all of the languages you support. See <a
-href="{@docRoot}training/basics/fragments/fragment-ui.html">Building a Flexible
-UI</a> for more information.</p>
-
-<h4 id="rtl">Use alternative layouts where needed</h4>
-
-<p>In cases where your UI can't accommodate text in one of your target
-languages, you can create an <a
-href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">alternative
-layout</a> for that language only.
-Android makes it easy to declare sets of layouts and other resources to load for
-specific languages, locales, screen sizes, and so on, simply by tagging them
-with the appropriate resource qualifiers. </p>
-
-<p>Although you can use alternative layouts to work around isolated issues, they
-can also make your app harder to maintain over time. In general, using a single,
-more flexible layout is preferred. </p>
-
-<h4 id="rtl">Support RTL layouts and text</h4>
-
-<p>If you are distributing to countries where right-to-left (RTL) scripts are used,
-should consider implementing support for RTL layouts and text display and
-editing, to the extent possible. </p>
-
-<p>Android 4.1 introduced limited support for bidirectional text, allowing apps
-to display and edit text in both left-to-right (LTR) and right-to-left (RTL)
-scripts. Android 4.2 added <a
-href="http://android-developers.blogspot.fr/2013/03/native-rtl-support-in-
-android-42.html">full native support for RTL layouts</a>, including layout
-mirroring, so that you can deliver the same great app experience to all of your
-users. </p>
-
-<p>At a minimum, for Android 4.2 users, it's simple to add basic RTL layout
-mirroring, which goes a long way toward meeting the needs of RTL users. </p>
-
-<h4 id="formats">Use system-provided formats for dates, times, numbers, and
-currencies</h4>
-
-<p>Where your app specifies dates, times, numbers, currencies, and other
-entities that can vary by locale, make sure to use the system-provided formats,
-rather than app-specific formats. Keep in mind that not every locale uses the
-same thousands separator, decimal separator, or percent sign. </p>
-
-<p>Android provides a variety of utilities for formatting and converting
-patterns across locales, such as {@link android.text.format.DateUtils DateUtils} and
-{@link java.text.DateFormat DateFormat} for
-dates; {@link java.lang.String#format String.format()} or {@link java.text.DecimalFormat DecimalFormat} for
-numbers and currency; {@link android.telephony.PhoneNumberUtils
-PhoneNumberUtils} for phone numbers; and others.</p>
-
-<p>If you hard-code your formats based on assumptions about the user's locale,
-your app could encounter problems when the user changes to another locale. The
-easiest and most reliable approach is to always use system-provided formats and
-utilities.</p>
-
-<h4 id="default-resources">Include a full set of default resources</h4>
-
-<p>Make sure that your app can run properly regardless of language or locale by
-providing a complete set of default resources. The app's default resources are
-those that are <em>not marked</em> with any language or locale qualifiers, for
-example those stored in <code>res/drawable/</code> and <code>res/values/</code>.
-If your app attempts to load a resource that isn't available in the current
-language or in the default set, the app will crash. </p>
-
-<p>Whatever the default language you are using in your app, make sure that you
-store the associated layouts, drawables, and strings in default resource
-directories, without language or locale qualifiers.  </p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://android-developers.blogspot.fr/2013/03/native-rtl-support-in-android-42.html">Native RTL Support in Android 4.2</a></strong> &mdash; Blog post that explains how to support RTL in your UI.</li>
-<li><strong><a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">Quantity Strings (Plurals)</a></strong> &mdash; Developer guide describing how to work with string plurals according to rules of grammar in a given locale. </li>
-<li><strong>{@link java.util.Locale Locale}</strong> &mdash; Reference information about how to use locale data determine exactly what CLDR data or version of the Unicode spec a particular Android platform version uses.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-
-<h2 id="managing-strings">3. Manage strings for localization</h2>
-
-<p>It's important to manage your app's UI strings properly, so that you deliver
-a great experience for users and make localization straightforward.</p>
-
-<h4 id="strings">Move all strings into strings.xml</h4>
-
-<p>As you build your app, remember that it's a best practice to keep all of your
-UI strings in a single file that's easy to update and localize. Declare
-<em>all</em> of your strings as resources in a default <code>strings.xml</code>
-file. Do not hard-code any strings into your compiled code&mdash;hard-coded
-strings are much more difficult to extract, translate, and load properly.
-
-<p>If you keep all of your default strings in a <code>strings.xml</code> file,
-you can quickly extract them for translation, and once the translated strings
-are integrated back into your app with appropriate qualifiers, your app can load
-them without any changes to your compiled code.</p>
-
-<p>If you generate images with text, put those strings in <code>strings.xml</code> as well,
-and regenerate the images after translation.</p>
-
-<h4 id="style">Follow Android guidelines for UI strings</h4>
-
-<p>As you design and develop your UI, make sure that you pay close attention to
-<em>how</em> you talk to your user. In general, use a <a
-href="{@docRoot}design/style/writing.html">succinct and compressed style</a>
-that is friendly but brief, and use a consistent style throughout your UI.
-</p>
-
-<p>Make sure that you read and follow the Android Design recommendations for <a
-href="{@docRoot}design/style/writing.html">writing style and word choice</a>.
-Doing so will make your app appear more polished to the user and will help users
-understand your UI more quickly. </p>
-
-<p>Also, always use Android standard terminology wherever possible&mdash;such as
-for UI elements such as "Action Bar," "Options Menu," "System Bar,"
-"Notifications," and so on. Using Android terms correctly and consistently
-makes translation easier and results in a better end-product for users.</p>
-
-<h4 id="context">Provide sufficient context for declared strings</h4>
-
-<p>As you declare strings in your <code>strings.xml</code> file, make sure to describe the
-context in which the string is used. Add comments before each string that may
-need clarification. This information will be invaluable to translators and will
-help you manage your strings more effectively over time.</p>
-
-<p>For example, background information to provide might include:</p>
-
-<ul>
-  <li>What is this string for? When/where is it presented to the user?</li>
-<li>Where is this in the layout? For example, if it’s a button, translations are
-less flexible than if it were a text box. </li>
-</ul>
-
-<p>Here's an example: </p>
-
-<pre>&lt;!-- The action for submitting a form. This text is on a button that can fit 30 chars --&gt;
-&lt;string name="login_submit_button"&gt;Sign in&lt;/string&gt;</pre>
-
-<h4 id="xliff">Mark message parts that should not be translated</h4>
-
-<p>Often strings contain contain text that should not be translated to other
-languages. Common examples might be a piece of code, a placeholder for a value,
-a special symbol, or a name. As you prepare you strings for translation, look
-for and mark text that should remain as-is, without translation, so that
-translators do not change it. </p>
-
-<p>To mark text that should not be translated, use an
-<code>&lt;xliff:g&gt;</code> placeholder tag. Here's an example tag that ensures
-the text “%1$s” will not be changed during translation (otherwise it could break
-the message):</p>
-
-<pre>&lt;string name="countdown"&gt;
-    &lt;xliff:g id="time" example="5 days&gt;%1$s&lt;/xliff:g&gt;until holiday
-&lt;/string&gt;</pre>
-
-<p>When you declare a placeholder tag, always add an <code>id</code> attribute
-that explains what the placeholder is for. If your app will later replace the
-placeholder value, be sure to provide an example attribute to clarify the expected
-usage.</p>
-
-<p>Here are some more examples of placeholder tag usage:</p>
-<pre>&lt;resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"&gt;
-    &lt;!-- Example placeholder for a special unicode symbol --&gt;
-    &lt;string name="star_rating"&gt;Check out our 5 
-        &lt;xliff:g id="star"&gt;\u2605&lt;/xliff:g&gt;
-    &lt;/string&gt;
-    &lt;!-- Example placeholder for a for a URL --&gt;
-    &lt;string name="app_homeurl"&gt;
-        Visit us at &lt;xliff:g id="application_homepage"&gt;http://my/app/home.html&lt;/xliff:g&gt;
-    &lt;/string&gt;
-    &lt;!-- Example placeholder for a name --&gt;
-    &lt;string name="prod_name"&gt;
-        Learn more at &lt;xliff:g id="prod_gamegroup"&gt;Game Group&lt;/xliff:g&gt;
-    &lt;/string&gt;
-    &lt;!-- Example placeholder for a literal --&gt;
-    &lt;string name="promo_message"&gt;
-        Please use the ”&lt;xliff:g id="promotion_code"&gt;ABCDEFG&lt;/xliff:g&gt;” to get a discount.
-    &lt;/string&gt;
-    ...
-&lt;/resources&gt;</pre>
-<!--<pre>&lt;string name="contact_info"&gt;
-    You can see our posts at &lt;xliff:g id="social_account_id"&gt;@superApp&lt;/xliff:g&gt;
-&lt;/string&gt;</pre>-->
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}guide/topics/resources/string-resource.html">String Resources</a></strong> &mdash; Developer guide explaining how to use string resources in your UI.</li>
-<li><strong><a href="{@docRoot}design/style/writing.html">Writing Style</a></strong> &mdash; Android Design guidelines for voice and style in your UI.</li>
-<li><strong><a class="external-link" href="http://en.wikipedia.org/wiki/XLIFF">XML Localisation Interchange File Format (XLIFF)</a></strong> &mdash; Background information on XLIFF.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-
-<h2 id="translate">4. Translate UI strings and other resources</h2>
-
-<p>Translating your app's UI strings and resources to your target languages is
-the key phase of localization, and it's the one that requires the most care and
-planning.</p>
-
-<p>In general, it's recommended to work with a professional translator to ensure
-that the work goes smoothly, stays on schedule, and results in a high-quality
-product that will enhance the value of your app. If you are considering machine
-translations as an alternative, keep in mind that automated translations are less
-reliable than high-quality professional translations and may not produce as good an
-experience for your users.</p>
-
-<h4>Prepare for translation</h4>
-
-<p>Getting high-quality translation output depends in part on your input. To get
-ready for translation, make sure that your <code>strings.xml</code> file is well organized,
-well commented, and accurate.</p>
-
-<p>Here are some ways to prepare your strings for translation:</p>
-<ul>
-  <li>Make sure your strings are formatted correctly and consistently.</li>
-  <li>Follow the strings recommendations listed in <a href="#strings">Manage
-strings for localization</a>, above.</li>
-  <li>Clean up the <code>strings.xml</code> file and remove unused strings.</li>
-  <li>Place comments in the file to identify the owner, origin, and the version
-of the file, as well as any special instructions for translators.</li>
-<li>Identify existing translations, if any, and include those in an outgoing
-zip file or other package that you will send to translators.</li>
-<li>Identify drawables or other resources that require translation and include
-them in the outgoing package for translators.</li>
-<p>Additionally, consider translating your app's store listing details &mdash;
-app title and description, release notes, and so on &mdash; as
-well as other international marketing materials.</p>
-<li>Create a terminology list that explains the meaning and usage of key terms
-used in your product, your market, or the underlying technology. Add the list to
-the outgoing package.</li>
-</ul>
-
-<h4 id="send">Send your strings for translation</h4>
-
-<p>Early in the development cycle, contact professional translation vendors for
-your target languages to get an idea of cost, lead time required, turnaround
-time, and so on. Then select a vendor and secure their services, making sure to
-include multiple iterations in the cost as a safeguard. Google Play can help you
-do this &mdash; see <a href="#gp-trans">Purchase professional
-translations</a>, below.</p>
-
-<p>As soon as your app's UI strings and design are stable, work with your
-development team to extract all of the strings and other resources from the app
-and package them together for the translator. If appropriate, you can version
-the outgoing package for later identification. </p>
-
-<p>When the outgoing package is ready, send it to the translator or share it
-with them over a cloud platform such as Google Drive. Keep a record of what you
-sent and when you sent it, to cross-reference against returning translations and
-billing invoices from the translator.</p>
-
-<p>When your translations are complete, take a preliminary look at the
-translations. Check that all files were translated, check for potential encoding
-issues, and make sure that declaration formats are intact. </p>
-
-<p>If everything looks good, carefully move the localized directories and files 
-back into your app's resources. Make sure to tag the directories with the
-appropriate language and locale qualifiers so that they'll later be loaded
-properly.</p>
-
-<p>After the translations are merged back into your app, start <a
-href="#testing">testing the localized app</a>.</p>
-
-<h4 id="gp-trans">Purchase professional translations through Google Play
-<br />App Translation Service</h4>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>App Translations in Google Play</h2>
-
-<p>Hear from developers who have used the Google Play App Translation Service in <a
-href="{@docRoot}distribute/googleplay/spotlight/localization.html">Developer
-Stories: Localization in Google Play</a>.</p>
-
-<p>To make it easy to export your app's strings and import
-the finished translations into your project, try the <a
-href="{@docRoot}sdk/installing/installing-adt.html#tmgr">
-ADT Translation Manager Plugin</a>.</div>
-</div>
-
-<p>Google Play App Translation Service can help you quickly find and purchase translations of your app.
-In the Developer Console, you can browse a list of third-party vendors who are
-pre-qualified by Google to offer high-quality translation at competitive prices.
-You can upload the strings you want translated, select the languages you want to
-translate into, and select your translation vendor based on time and price.</p>
-
-<p>Once you've purchased translations, you'll receive an email from your vendor.
-Your translations are a direct business agreement between you and your vendor;
-you'll need to work directly with the vendor to manage the translation process and
-deliverables and resolve any support issues. </p>
-
-
-<h2 id="testing">5. Test your localized app</h2>
-
-<p>Once you've received your translated strings and resources and moved them
-back into your app, you need to test the app to make sure that it's ready for
-distribution to your international users. </p>
-
-<p>Manual testing can help you discover localization issues in your layouts and
-strings that can affect user satisfaction and, ultimately, your app's user
-rating. </p>
-
-<h4 id="native">Set up a test environment</h4>
-
-<p>To test your localized app, you'll need to set up an environment consisting
-of multiple devices (or virtual devices) and screen sizes, based on the markets
-and form factors you are targeting. Note that the range of devices in specific
-regions might be different. If possible, match your test devices to the actual
-devices likely to be available to users.</p>
-
-<h4 id="native">Look for common localization issues</h4>
-
-<p>On each test device, set the language or locale in Settings. Install and
-launch the app and then navigate through all of the UI flows, dialogs, and user
-interactions. Enter text in inputs. Some things to look for include:</p>
-
-<ul>
-  <li>Clipped text, or text that overlaps the edge of UI elements or the
-screen</li>
-  <li>Poor line wrapping</li>
-  <li>Incorrect word breaks or punctuation</li>
-  <li>Incorrect alphabetical sorting</li>
-  <li>Incorrect layout direction or text direction</li>
-  <li>Untranslated text &mdash; if your default strings are displayed instead of
-translated strings, then you may have overlooked those strings for translation
-or marked the resources directory with an incorrect language qualifier. </li>
-</ul>
-
-<p>For cases where your strings have expanded in translation and no longer fit
-your layouts, it's recommended to simplify your default text, simplify your
-translated text, or adjust your default layouts. If none of those resolves the
-issue, you can create a custom layout for the language. </p>
-
-<h4 id="default-test">Test for default resources</h4>
-
-<p>After you've tested your app in all of your supported languages and locales,
-make sure to test it again in an <em>unsupported language</em> and locale. This
-will help you make sure that your app includes a full set of default strings and
-resources, so that your app is usable to all users, regardless of their
-preferred language. </p>
-
-<h4 id="native">Review with native-language speakers</h4>
-
-<p>During or after testing, it's recommended that you let native speakers review
-your localized app. One way to do that is through beta testing with regional
-users &mdash; Google Play can help you do this. See <a href="#beta">Plan a beta
-release</a> for more information.</p>
-
-
-<h2 id="prelaunch">Prepare for international launch</h2>
-
-<p>Getting your app translated is a key part of localization, but to help your
-product attract users and gain visibility, you should prepare for launch in your
-target countries and create a broader launch and marketing plan for
-international users. </p>
-
-
-<h4 id="listing">Localize your Google Play listing</h4>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>Localize your Google Play listing</h2>
-<p>Highlight what's great about your app to all of your users! Localize your
-listing in the Developer Console: </p>
-<ul>
-  <li>App title and description</li>
-  <li>App screenshots on phones and tablets</li>
-  <li>Promotional graphics and videos.</li>
-</ul>
-</div>
-</div>
-<p>If you want your app to be successful in international markets, it's
-essential to localize your Google Play store listing. You can manage your
-localized listing in the Developer Console.</p> 
-
-<p>Well before launch, decide on your app title, description, promotional text,
-marketing names and programs, and other text and images. Send your
-listing text and images for translation early, so that you have them ready when
-beta testing begins. When your translated text is available, you can add it
-through the Developer Console.</p>
-
-<p>Also, since you've made the effort to create a great localized app, let users
-know about it! Take screenshots of your UI in each language, for phones and 7-
-and 10- inch tablets. You can upload screenshots to the Developer Console for
-each language you support. These will be of great value to users browsing your
-app listing in other languages. </p>
-
-<p>It's also essential to create localized versions of your promotional graphics
-and videos. For example, your app's feature graphic might include text that
-should be translated, for maximum effectiveness, or you might want to take a
-different visual approach in one country than you do in another. You can create
-different versions of your promotional graphics for each language and upload
-them to the Developer Console. If you offer a promotional video, you can create
-localized versions of it and then add a link to the correct localized video for
-each language you support.</p>
-<h4 id="beta">Plan a beta release in key countries</h4>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>Easy beta testing</h2>
-<p>Google Play now lets you set up groups of alpha and beta testers, anywhere
-around the world. Check out this powerful feature next time you sign in to the
-Developer Console.</p>
-</div>
-</div>
-
-<p>Before launching your app, it's always valuable to get real-world feedback
-from users &mdash; even more so when you are launching an app in a new language,
-country, or region. In those cases, it's highly recommended that you distribute
-a pre-release version of your app to users across your key markets and provide
-an easy means for them to provide feedback and report bugs. </p>
-
-<p>Google Play can help you set up a beta program for your app. After you sign
-in to the Developer Console and upload your APK, you can set up groups of users
-for alpha testing and beta testing the app. You can start with a small group of
-alpha testers, then move to a larger group of beta testers. Once users are
-added, they access your app's store listing and install the app. User feedback
-from alpha and beta testers goes directly to you and is not posted as public
-reviews. </p>
-
-<p>The feedback you receive will help you adjust your UI, translations, and
-store listing to ensure a great experience for users. </p>
-
-<h4 id="beta">Plan for international marketing</h4>
-
-<p>For highest visibility across countries, consider an international marketing
-or advertising campaign. The scope of the campaign might vary based on the
-budget you can support, but in general it's cost-effective and productive to do
-regional or country-specific marketing at launch and after. </p>
-
-<h4 id="badges">Create localized Google Play badges</h4>
-
-<p>If you are preparing international marketing, make sure to include a <a
-href="{@docRoot}distribute/googleplay/promote/badges.html">localized Google Play
-badge</a> to tell users you're on Google Play. You can use the badge generator
-to quickly build localized badges that you can use on web sites or marketing
-materials. High-resolution assets are also available.</p> 
-
-<h4 id="deviceart">Create Localized Device Art</h4>
-
-<p>If you feature product shots of your app running on Android devices, make
-sure that those shots look great and reflect the latest in Android devices. To
-help you create high-quality marketing materials, use the drag-and-drop <a
-href="{@docRoot}distribute/promote/device-art.html">Device Art Generator</a> to
-quickly frame your screen shot on a Nexus device. </p>
-
-<h4 id="deviceart">Check your Optimization Tips</h4>
-
-<p>As you prepare for launch, make sure to sign into the Developer Console and check
-your app's Optimization Tips. The Optimization Tips let you know when you are missing parts of your localized store listing and provide other helpful reminders for a successful localized launch.</p>
-
-<h2 id="support">Support International Users after Launch</h2>
-
-<p>After you launch your app internationally, you should be prepared to support
-users in a variety of languages and time zones. The extent of your international
-user support depends on your budget, but at a minimum you should watch your
-ratings, reviews, and download stats carefully after launch. 
-
-<p>Here are some suggestions: </p>
-
-<ul>
-  <li>Use the app stats in the Developer Console to compare your downloads,
-installs, and uninstalls, and ratings across languages and countries&mdash;If
-your downloads or ratings are not keeping up in specific languages or countries,
-consider options for improving your product or changing your marketing approach.
-</li>
-  <li>Check reviews regularly&mdash;Google Play translates all user reviews for
-you, so you can stay in touch with how international users feel about your app,
-what features they like and what issues are affecting them. By watching reviews,
-you can spot technical issues that may affect many users in a particular
-country, then fix and update your app.</li>
-  <li>Respond to reviews if possible&mdash;It's good to engage with
-international users in their language or a common language if possible. If not,
-you can try using translation tools, although results may not be predictable. If
-your app gets very popular in a language, consider getting support help from
-native-language speakers. </li>
-  <li>Make sure there's a link to any support resources on your web site.
-Consider setting up language-specific user groups, Google+ communities, or other
-support forums.
-</ul>
-
-<p>By following these practices for localizing your app, promoting and marketing
-to international users, and providing ongoing support, you can attract many new
-users to your app and maintain their loyalty.</p>
-
-<p>Make sure to read the <a
-href="{@docRoot}distribute/googleplay/publish/preparing.html">Launch
-Checklist</a> to learn more about how to plan, build, and launch your app on
-Google Play. </p>
diff --git a/docs/html/distribute/googleplay/publish/preparing.jd b/docs/html/distribute/googleplay/publish/preparing.jd
deleted file mode 100644
index 6af3eea..0000000
--- a/docs/html/distribute/googleplay/publish/preparing.jd
+++ /dev/null
@@ -1,681 +0,0 @@
-page.title=Launch Checklist
-page.tags=publishing,launch,Google Play,Developer Console
-@jd:body
-
-<div id="qv-wrapper"><div id="qv">
-<h2>Checklist</h2>
-<ol>
-<li><a href="#process">1. Understand the publishing process</a></li>
-<li><a href="#policies">2. Understand Google Play policies</a></li>
-<li><a href="#core-app-quality">3. Test for core app quality</a></li>
-<li><a href="#rating">4. Determine your content rating</a></li>
-<li><a href="#countries">5. Determine country distribution</a></li>
-<li><a href="#size">6. Confirm the app's overall size</a></li>
-<li><a href="#compatibility">7. Confirm app compatibility ranges</a></li>
-<li><a href="#free-priced">8. Decide on free or priced</a></li>
-<li><a href="#inapp-billing">9. Consider In-app Billing</a></li>
-<li><a href="#pricing">10. Set prices for your apps</a></li>
-<li><a href="#localize">11. Start localization early</a></li>
-<li><a href="#graphics">12. Prepare promotional graphics</a></li>
-<li><a href="#apk">13. Build the release-ready APK</a></li>
-<li><a href="#beta">14. Plan a beta release</a></li>
-<li><a href="#product-page">15. Complete the product details</a></li>
-<li><a href="#badges">16. Use Google Play badges</a></li>
-<li><a href="#final-checks">17. Final checks and publishing</a></li>
-<li><a href="#support">18. Support users after launch</a></li>
-</ol>
-</div></div>
-
-
-<p>Before you publish your app on Google Play and distribute it to users, you
-need to get the app ready, test it, and prepare your promotional materials. </p>
-
-<p>This document helps you understand the publishing process and get ready for a
-successful product launch on Google Play. It summarizes some of the
-tasks you'll need to complete before publishing your app on Google Play, such as
-creating a signed, release-ready APK, understanding the requirements of the app,
-and creating the product page and graphic assets for your app.</p>
-
-<p>The preparation and publishing tasks are numbered to give you a rough idea of
-sequence. However, you can handle the tasks in any sequence that works for you
-or you can skip steps as appropriate.</p>
-
-<p>As you move toward publishing, a variety of support resources are available to
-you. Relevant links are provided in each step.</p>
-
-
-<h2 id="process">1. Understand the publishing process</h2>
-
-<p>Before you begin the steps in this checklist, you should take a moment to
-read and understand the overall publishing workflow and become familiar with how
-the process works. In particular, you or your development team will need to
-prepare your app for release using a process common to all Android apps.
-The <a
-href="{@docRoot}tools/publishing/publishing_overview.html">Publishing
-Workflow</a> documents provide the details on how publishing works and how to
-get an APK ready for release. </p>
-
-<p>Once you are familiar with publishing in general, read this document to
-understand the issues that you should consider when publishing an app on Google
-Play. </p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}tools/publishing/publishing_overview.html">General Publishing Overview</a></strong> &mdash; Start here for an overview of publishing options for Android apps.</li>
-<li><strong><a href="{@docRoot}tools/publishing/preparing.html">Preparing for Release</a></strong> &mdash; Developer documentation on how to build the signed, release-ready APK. This process is the same for all Android apps. </li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="policies">2. Understand Google Play policies and agreements</h2>
-
-<p>Make sure that you understand and follow the Google Play program policies
-that you accepted when registering. Google Play actively enforces the policies
-and any violations can lead to suspension of your app or, for repeated
-violations, termination of your developer account. </p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-
-<li><strong><a href="{@docRoot}distribute/googleplay/policies/index.html">Google Play Policies and Guidelines</a></strong> &mdash; An overview of Google Play policies for spam, intellectual property, and ads, with examples of common problems. </li>
-</a></strong> &mdash; Help Center document describing various content policies and processes.</li>
-
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/topic.py?hl=en&topic=2364761&parent=2365624&ctx=topic">Policy and Best Practices
-</a></strong> &mdash; Help Center document describing various content policies and processes.</li>
-
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="core-app-quality">3. Test for Core App Quality</h2>
-
-<p>Before you publish an app on Google Play, it's important to make sure that
-it meets the basic quality expectations for all Android apps, on all of the devices that you
-are targeting. You can check your app's quality by setting up a test
-environment and testing the app against a short set of <strong>core app quality criteria</strong>.
-For complete information, see the <a
-href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality Guidelines</a>. 
-</p>
-
-<p>If your app is targeting tablet devices, make sure that it delivers a rich, compelling
-experience to your tablet customers. See the <a
-href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality Checklist</a>
-for recommendations on ways to optimize your app for tablets.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a
-href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality
-Guidelines</a></strong> &mdash; A set of core quality criteria that all Android
-apps should meet on all targeted devices.</li>
-<li><strong><a
-href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality
-Checklist</a></strong> &mdash; A set recommendations for delivering the best
-possible experience to tablet users.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="rating">4. Determine your app's content rating</h2>
-
-<p>Google Play requires you to set a content rating for your app, which informs
-Google Play users of its maturity level. Before you publish, you should confirm
-what rating level you want to use. The available content rating levels are:</p>
-
-<ul>
-<li>Everyone</li>
-<li>Low maturity</li>
-<li>Medium maturity</li>
-<li>High maturity</li>
-</ul>
-
-<p>On their Android devices, Android users can set the desired maturity level
-for browsing. Google Play then filters apps based on the setting, so the content
-rating you select can affect the app's distribution to users. You can assign (or
-change) the content rating for your app in the Developer Console, so no changes
-are required in your app binary.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=188189">Rating your application content for Google Play</a></strong> &mdash; Help Center document describing content ratings levels and how to choose the appropriate one for your app.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="countries">5. Determine country distribution</h2>
-
-<p>Google Play lets you control what countries and territories your app is
-distributed to. For widest reach and the largest potential customer base, you
-would normally want to distribute to all available countries and territories.
-However, because of business needs, app requirements, or launch dependencies,
-you might want to exclude one or more countries from your distribution. </p>
-
-<p>It's important to determine the exact country distribution early, because it
-can affect:</p>
-<ul>
-<li>The need for localized resources in the app</li>
-<li>The need for a localized app description in the Developer Console</li>
-<li>Legal requirements for the app that may be specific to certain
-countries</li>
-<li>Time zone support, local pricing, and so on.</li>
-</ul>
-
-<p>With your country targeting in mind, you should assess what
-your localization needs are, both in your app and in its Google Play listing
-details, and start the work of localization well in advance of your
-launch target date.</p>
-
-<p>See <a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization
-Checklist</a> for key steps and considerations in the localizing process. </p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization Checklist</a></strong> &mdash; Overview of key steps and considerations for localizing your Android app.</li>
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138294&topic=2365624&ctx=topic">Supported locations for distributing applications</a></strong> on Google Play.
-.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="size">6. Confirm the app's overall size</h2>
-
-<p>The overall size of your app can affect its design and how you publish it on
-Google Play. Currently, the maximum size for an APK published on Google Play is
-<strong>50 MB</strong>. If your app exceeds that size, or if you want to offer a
-secondary download, you can use <a
-href="{@docRoot}google/play/expansion-files.html">APK Expansion Files</a>,
-which Google Play will host for free on its server infrastructure and
-automatically handle the download to devices.</p>
-
-<ul>
-<li>The maximum size for an APK published on Google Play is 50 MB.</li>
-<li>You can use up to two (2) APK Expansion Files, each up to 2 GB in size, for
-each APK.</li>
-</ul>
-
-<p>Using APK Expansion files is a convenient, cost-effective method of
-distributing large apps. However, the use of APK Expansion Files requires some
-changes in your app binary, so you will need to make those changes before
-creating your release-ready APK.</p>
-
-<p>To minimize the size of your app binary, make sure that you run the
-<a href="{@docRoot}tools/help/proguard.html">Proguard</a> tool on your code when
-building your release-ready APK.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}google/play/expansion-files.html">APK Expansion Files</a></strong>
-&mdash; Developer documentation describing APK Expansion Files and how to support them in your app.</li>
-<li><strong><a href="{@docRoot}tools/help/proguard.html">ProGuard</a></strong> &mdash; Developer
-documentation describing how to use ProGuard to shrink, optimize, and obfuscate your code prior
-to release.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="compatibility">7. Confirm the app's platform and screen compatibility ranges</h2>
-
-<p>Before publishing, it's important to make sure that your app is designed to
-run properly on the Android platform versions and device screen sizes that you
-want to target. 
-
-<p>From an app-compatibility perspective, Android platform versions are defined
-by <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API level</a>. You should
-confirm the minimum version that your app is compatible with (<a
-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code>&lt;minSdkVersion&gt;</code></a>),
-as that will affect its distribution to Android
-devices once it is published. </p>
-
-<p>For screen sizes, you should confirm that the app runs properly and looks
-good on the range of screen sizes and densities that you want to support. You
-should confirm the minimum screen-size and density support that your app
-declares (<a
-href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code>&lt;supports-screens&gt;</code></a>),
-since that can affect its distribution to
-Android devices once it is published. </p>
-
-<p>To get a better understanding of the current device penetration of Android
-platform versions and screen sizes across all Android devices, see the <a
-href="{@docRoot}about/dashboards/index.html">Device Dashboard</a>
-charts.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}about/dashboards/index.html">Device Dashboard</a></strong> &mdash; A chart showing global percentages of devices by Android version, screen size, and level of OpenGL ES support.</li>
-<li><strong><a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">Android API Levels</a></strong> &mdash; A definition of API Levels and a list of which Android platform versions they are associated with. </li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="free-priced">8. Decide whether your app will be free or priced</h2>
-
-<p>On Google Play, you can publish apps as free to download or priced. Free apps
-can be downloaded by any Android user in Google Play.
-Paid apps can be downloaded only by users who have registered a form of payment
-in Google Play, such as a credit card or Direct Carrier Billing.</p>
-
-<p>Deciding whether you app will be free or paid is important because, on Google
-Play, <strong>free apps must remain free</strong>.</p>
-
-<ul>
-<li>Once you publish your app as a free app, you cannot ever change it to being
-a priced app. However, you can still sell in-app products and
-subscriptions through Google Play's In-app Billing service.</li>
-<li>If you publish your app as a priced app, you <em>can</em> change
-it at any time to being a free app (but cannot then change it back to
-priced). You can also sell in-app products and subscriptions. </li>
-</ul>
-
-<p> If your app is be priced, or if you'll be selling in-app products,
-you need set up a Google Wallet merchant account before you can publish.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}google/play/billing/index.html">In-app Billing</a></strong> &mdash; Developer introduction to Google Play In-app Billing.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="inapp-billing">9. Consider using In-app Billing</h2>
-
-<p>Google Play <a href="{@docRoot}google/play/billing/index.html">In-app
-Billing</a> lets you sell digital content in your applications. You can use the
-service to sell a wide range of content, including downloadable content such as
-media files or photos, and virtual content such as game levels or potions.
-In-app Billing service lets you sell one-time purchases and subscriptions from
-inside your app. This can help you to monetize the app over its installed
-lifetime. </p>
-
-<p>If your are looking for more ways to monetize your app and build engagement,
-you should consider In-app Billing. The service has become very popular with
-both users and developers. To use In-app Billing, you need to make changes to
-your app binary, so you will need to complete and test your implementation
-before creating your release-ready APK.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}google/play/billing/index.html">In-app Billing</a></strong> &mdash; Developer documentation describing In-app Billing and how to support it in your app.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="pricing">10. Set prices for your products</h2>
-
-<p>If your app is priced or you will sell in-app products, Google Play lets you
-set prices for your products in a variety of currencies, for users in markets
-around the world. You can set prices individually in different currencies, so
-you have the flexibility to adjust your price according to market conditions and
-exchange rates. </p>
-
-<p>Before you publish, consider how you will price your products
-and what your prices will be in various currencies. Later, you can set prices
-in all available currencies through the Developer Console.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=1169947&topic=15867&ctx=topic">Selling Apps in Multiple Currencies
-</a></strong> &mdash; Help Center document describing how pricing works in Google Play.</li>
-
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138412&topic=15867&ctx=topic">Prices and supported currencies
-</a></strong> &mdash; Help Center document listing supported currencies for pricing your apps.</li>
-
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=112622&topic=15867&ctx=topic">Transaction Fees
-</a></strong> &mdash; Help Center document describing transaction fees for priced apps and in-app products.</li>
-
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138000&topic=15867&ctx=topic">Specifying tax rates
-</a></strong> &mdash; Help Center document describing how to set tax rates for different countries. </li>
-
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="localize">11. Start localization</h2>
-
-<p>With your country targeting in mind, it's a good idea to assess your localization
-needs and start the work of localizing well in advance of your target
-launch date.</p>
-
-<p>There are at least three aspects of localization to consider:</p>
-
-<ul>
-<li>Localizing the strings, images, and other resources in your app</li>
-<li>Localizing your app's store listing details on Google Play</li>
-<li>Localizing the app's graphic assets, screenshots, and videos that accompany your store listing.</li>
-</ul>
-
-<p>See <a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization Checklist</a> for key steps and considerations in the localizing process. </p>
-
-<p>To localize your store listing, first create and finalize your app title, description, 
-and promotional text. Collect and send all of these for localization. You can optionally
-translate the "Recent Changes" text for app updates as well. Later you can add your localized
-listing details in the Developer Console, or you can  choose to let Google Play auto-translate
-your listing details into the languages you support.</p>
-
-<p>A key part of making your app listing attractive to a global customer base is
-creating localized versions of your promotional graphics, screenshots and
-videos. For example, your app's feature graphic might include text that should
-be translated, for maximum effectiveness. You can create different versions of
-your promotional graphics for each language and upload them to the Developer
-Console. If you offer a promotional video, you can create localized versions of
-it and then add a link to the correct localized video for each language you
-support.</p>
-
-<p>When your translations are complete, move them into your app resources as needed and test
-that they are loaded properly. Save your app's translated listing details for later,
-when you upload assets and configure your product details.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization Checklist</a></strong> &mdash; Overview of key steps and considerations for localizing your Android app.</li>
-<li><strong><a href="{@docRoot}guide/topics/resources/localization.html">Localizing with Resources</a></strong> &mdash; Developer guide to localizing resources in your app.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="graphics">12. Prepare promotional graphics, screenshots, and videos</h2>
-
-<p>When you publish on Google Play, you can supply a variety of high-quality
-graphic assets to showcase your app or brand. After you publish, these appear on
-your product details page, in store listings and search results, and elsewhere.
-These graphic assets are key parts of a successful product details page that
-attracts and engages users, so you should consider having a professional produce
-them for you. Screen shots and videos are also very important, because they show
-what your app looks like, how it's used or played, and what makes it different.</p>
-
-<p>All of your graphic assets should be designed so that they are easy to see
-and highlight your app or brand in a colorful, interesting way. The assets
-should reference the same logo and icon as users will actually find in the All
-Apps launcher once they have downloaded the app. Your graphic assets should also
-fit in well with the graphic assets of other apps published by you, which will
-be also be displayed to users on your product details page. </p>
-
-<p>To help you market your app more effectively to a global audience, Google
-Play lets you create localized versions of your promotional graphics,
-screenshots, and videos and upload them to the Developer Console. When a user
-visits your app's store listing, Google Play displays the promotional graphic,
-screenshots and video that you've provided for the user's language.</p>
-
-<p>To localize your promotional graphics, you can translate any embedded text, use
-different imagery or presentation, or change your marketing approach to best address the needs
-of users in specific languages. For example, if your feature or promotional graphic
-includes and embedded product name or tag line, you can translate that text
-and add it to a localized version of the promotional graphic.</p>
-
-<p>Because your localized graphic assets and videos are so important, you should get
-started on creating them and localizing them well in advance of your target
-publishing date. </p>
-
-<p class="note"><strong>Note:</strong> Localized promotional graphics and videos
-are supported only in the new Developer Console design.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=1078870">Graphic Assets for your Application
-</a></strong> &mdash; Details about the graphic assets you need to upload before publishing.</li>
-<li><strong><a href="http://android-developers.blogspot.com/2011/10/android-market-featured-image.html">Google Play Featured Image Guidelines
-</a></strong> &mdash; Blog post that highlights key design considerations for your app's featured image.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="apk">13. Build and upload the release-ready APK</h2>
-
-<p>When you are satisfied that your app meets your UI, compatibility, and
-quality requirements, you can build the release-ready version of the app. The
-release-ready APK is what you you will upload to the Developer Console and
-distribute to users. 
-
-<p>The process for preparing a release-ready APK is the same for all apps,
-regardless of how they are distributed. Generally the process includes basic code cleanup
-and optimization, building and signing with your release key, and final testing.
-When you are finished preparing your application for release, you'll have a signed
-APK file that you can upload to the Developer Console for distribution to
-users. </p>
-
-<p>For complete details on how to create a release-ready version of your app,
-read <a href="{@docRoot}tools/publishing/preparing.html">Preparing for
-Release</a>.</p>
-
-<p>Once you have the release-ready APK in hand, you can upload it to 
-the Developer Console. If necessary, you can replace the APK with a more 
-recent version before publishing. </p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}tools/publishing/preparing.html">Preparing for Release</a></strong> &mdash; Essential information for preparing and packaging your app properly for distribution.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="beta">14. Plan a beta release</h2>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>Easy beta testing</h2>
-<p>Google Play now lets you set up groups of alpha and beta testers, anywhere around the world. Check out this powerful feature next time you sign in to the Developer Console.</p>
-</div>
-</div>
-
-<p>Before launching your app, it's always valuable to get real-world feedback
-from users &mdash; even more so when you are launching a new app. It's highly
-recommended that you distribute a pre-release version of your app to users
-across your key markets and provide an easy means for them to provide feedback
-and report bugs. </p>
-
-<p>Google Play can help you set up a beta program for your app. After you sign
-in to the Developer Console and upload your APK, you can set up groups of users
-for alpha testing and beta testing the app. You can start with a small group of
-alpha testers, then move to a larger group of beta testers. Once users are
-added, they access your app's store listing and install the app. User feedback
-from alpha and beta testers goes directly to you and is not posted as public
-reviews. </p>
-
-<p>The feedback you receive will help you adjust your UI, translations, and
-store listing to ensure a great experience for users. </p>
-
-<h2 id="product-page">15. Complete the app's product details</h2>
-
-<p>On Google Play, your app's product information is shown to users on its
-product details page, the page that users visit to learn more about your app and
-the page from which they will decide to purchase or download your app, on their
-Android devices or on the web.</p>
-
-<p>Google Play gives you a variety of ways to promote your app and engage with
-users on your product details page, from colorful graphics, screenshots, and
-videos to localized descriptions, release details, and links to your other apps.
-As you prepare to publish your app, make sure that you take advantage of all
-that your product details page can offer, making your app as compelling as
-possible to users.</p>
-
-<p>You should begin planning your product page in advance of your target launch
-date, arranging for localized description, high-quality graphic assets,
-screenshots and video, and so on. </p>
-
-<p>As you get near your target publishing date, you should become familiar with 
-all the fields, options, and assets associated with the product details configuration
-page in the Developer Console. As you collect the information and assets for the
-page, make sure that you can enter or upload it to the Developer Console, until 
-the page is complete and ready for publishing. </p>
-
-<p>After you've set your app's geographic targeting in the Developer Console,
-remember to add your localized product details, promotional graphics, and so on, for all of the
-languages that you support.</p>
-
-<p>If your app is targeting tablet devices, make sure to include at least one screen
-shot of the app running on a tablet, and highlight your app's support for tablets
-in the app description, release notes, promotional campaigns, and elsewhere.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113475&topic=2365760&ctx=topic">Category types
-</a></strong> &mdash; Help Center document listing available categories for apps.</li>
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=1078870&topic=2365760&ctx=topic">Graphic Assets for your Application
-</a></strong> &mdash; Help Center document describing the various graphics you can add to your product listing.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="badges">16. Use Google Play badges and links in your promotional
-campaigns</h2>
-
-<p>Google Play badges give you an officially branded way of promoting your app
-to Android users. Use the <a
-href="{@docRoot}distribute/googleplay/promote/badges.html">Google Play Badge
-generator</a> to quickly create badges to link users to your products from web
-pages, ads, reviews, and more. You can also use special <a
-href="{@docRoot}distribute/googleplay/promote/linking.html">link formats</a>
-to link directly to your product details page, to a list of your products, or to
-search results.</p>
-
-<p>To help your app get traction after launch, it's strongly recommended that you support 
-launch with a promotional campaign that announces your product through many channels as
-possible, in as many countries as possible. For example, you can promote the launch 
-using ad placements, social network or blog posts, video and other media, interviews
-and reviews, or any other channel available.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}distribute/googleplay/promote/badges.html">Google Play Badges</a></strong> &mdash; Generate a badge to bring users to your app in Google Play.</li>
-<li><strong><a href="{@docRoot}distribute/googleplay/promote/linking.html">Linking to Your Products</a></strong> &mdash; Link formats that you can use to bring users to your app in Google Play.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="final-checks">17. Final checks and publishing</h2> 
-
-<p>When you think you are ready to publish, sign in to the Developer Console and take a few moments for a few
-final checks.</p>
-
-<p>Make sure that: </p>
-
-<ul>
-<li>Your developer profile has the correct information and is linked to the proper Google Wallet merchant account (if you are selling products).</li>
-<li>You have the right version of the app uploaded.</li>
-<li>All parts of your Product Details are ready, including all graphic assets, screenshots, video, localized descriptions, and so on. </li>
-<li>You have set your app's pricing to free or priced.</li>
-<li>You have set country (and carrier) targeting and priced your products (if appropriate) in buyer currencies</li>
-<li>"Compatible devices" shows that your app is actually reaching the devices that you are targeting. If not, you should check with your development team on the apps requirements and filtering rules. </li>
-<li>You have provided the correct link to your web site and the correct support email address.</li>
-<li>Your app does not violate content policy guidelines.</li>
-<li>You have acknowledged that your app meets the guidelines for Android content on Google Play and also US export laws. </li>
-</ul>
-
-<p>Your app is now ready to publish!</p>
-
-<p>If you are releasing an update, make sure to read the <a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113476&topic=2365760&ctx=topic">requirements for publishing updates</a>. </p>
-
-<p>When you are ready, click the <strong>Publish</strong> button in the Developer Console. Within a few hours, your app will become available to users and your product page will be appear in Google Play for browsing, searching, or linking from your promotional campaigns.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://www.android.com/us/developer-content-policy.html">Google Play Developer Program Policies</a></strong> &mdash; Guidelines for what is acceptable conent in Google Play. Please read and understand the policies before publishing. </li>
-<li><strong><a href="{@docRoot}distribute/googleplay/promote/linking.html">Updates</a></strong> &mdash; Requirements for app updates in Google Play.</li>
-<li><strong><a href="{@docRoot}support.html">Developer Support</a></strong> &mdash; Support resources that you can use to find answers and report issues.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-
-<h2 id="support">18. Support users after launch</h2>
-
-<p>After you publish an app or an app update, it's crucial for you to support
-your customers. Prompt and courteous support can provide a better experience for
-users that results in better ratings and more positive reviews for your
-products. Users are likely to be more engaged with your app and recommend it if
-you are responsive to their needs and feedback.  This is especially true after
-publishing if you are using a coordinated promotional campaign.</p>
-
-<p>There are a number of ways that you can keep in touch with users and offer
-them support. The most fundamental is to provide your <em>support email
-address</em> on your product details page. Beyond that, you can provide support
-in any way you choose, such as a forum, mailing list or a Google+ page.  The
-Google Play team does provide user support for downloading, installing and
-payments issues, but issues that fall outside of these topics will fall under
-your domain.  Examples of issues you can support include:  feature requests,
-questions about using the app and questions about compatibility settings.  </p>
-
-<p>After publishing, plan to: </p>
-<ul>
-<li>Check your ratings and reviews frequently on your app's product details
-page. Watch for recurring issues that could signal bugs or other issues. </li>
-<li>Be mindful of new Android platform version launches, as compatibility
-settings for your apps might need to be updated.</li>
-<li>Put a link to your support resources on your web site and set up any other
-support such as forums.</li>
-<li>Provide an appropriate support email address on your product details page
-and respond to users when they take the time to email you.</li>
-<li>Beyond the automatic refund window offered by Google Play, be generous with
-your own refund policy, as satisfied users will be more likely to purchase in
-the future. </li>
-<li>Acknowledge and fix issues in your app. It helps to be transparent and
-list known issues on your product details page proactively.  </li>
-<li>Publish updates as frequently as you are able, without sacrificing quality
-or annoying users with too-frequent updates. </li>
-<li>With each update, make sure to provide a summary of what's changed. You can
-enter this information in the Developer Console. Users will read it and
-appreciate that you are serious about improving the quality of your app. </li>
-</ul>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113477&topic=2364761&ctx=topic">Supporting your users
-</a></strong> &mdash; Help Center document describing options for supporting users.</li>
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=1153479">In-app Billing</a></strong> &mdash; Help Center document describing how to correctly set up In-app Billing.</li>
-<li><strong><a href="https://support.google.com/payments/answer/2741495?rd=1">Issuing Refunds</a></strong> &mdash;  -- Help Center document describing how to issue refunds.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-
-
diff --git a/docs/html/distribute/googleplay/publish/register.jd b/docs/html/distribute/googleplay/publish/register.jd
deleted file mode 100644
index faade81..0000000
--- a/docs/html/distribute/googleplay/publish/register.jd
+++ /dev/null
@@ -1,80 +0,0 @@
-page.title=Get Started with Publishing
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>Help topics</h2>
-<ul>
-  <li><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113468">Developer Registration</a></li>
-  <li><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138294&topic=2365624&ctx=topic">Supported Locations for Distributing Apps</a></li>
-  <li><a href="http://support.google.com/googleplay/android-developer/bin/topic.py?hl=en&topic=2364761">Policy and Best Practices</a></li>
-  <li><a href="http://support.google.com/googleplay/android-developer/">Developer Support</a></li>
-</ul>
-
-<h2>Get Started</h2>
-<ol>
-  <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
-</ol>
-
-</div>
-</div>
-
-<p>You can set up to start publishing on Google Play in only a few minutes. Here's how you do it: </p>
-
-<ul>
-<li>Register for a Google Play publisher account</li>
-<li>If you will sell apps, set up a Google Wallet Merchant Account</li>
-<li>Explore the Google Play Developer Console and learn about the tools for publishing</li>
-</ul>
-
-
-<h3>Register for a publisher account</h3>
-
-<p>The first step is to visit the Google Play Developer Console and register for a publisher account.</p>
-
-<p>Here's what you will do during registration: </p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>Tips</h2>
-  <ul>
-    <li>You need a Google account to register. You can create one during the process. </li>
-    <li>If you are an organization, consider registering a new Google account rather than using a personal account.</li>
-    <li>Review the <a href="https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138294">developer countries</a> and <a href="https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=150324">merchant countries</a> where you can distribute and sell apps.</li> 
-  </ul>
-</div></div>
-
-
-<ol>
-<li>Visit the Google Play Developer Console at <a
-href="https://play.google.com/apps/publish/">https://play.google.com/apps/publish/</a>.
-<li>Enter basic information about your <strong>developer identity</strong> &mdash; developer
-name, email address, and so on. You can modify this information later.</li>
-<li>Read and accept the <strong>Developer Distribution Agreement</strong> that applies to your
-country or region. Note that apps and store listings that you publish on Google Play must comply
-with the Developer Program Policies and US export law,</li>
-<li>Pay a <strong>$25 USD registration fee</strong> using Google Wallet. If you don't have
-a Google Wallet account, you can quickly set one up during the process.</li>
-</ol>
-
-<p>When your registration is verified, you’ll be notified at the email address you specified during registration.</p>
-
-<h3>Set up a Google Wallet Merchant account</h3>
- 
-<p>If you want to sell products on Google Play &mdash; priced apps, in-app products, or subscriptions &mdash; you will also need to set up a Google Wallet Merchant Account. You can do that at any time, but make sure to first review the list of <a href="https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=150324">merchant countries</a>.</p>
-
-<p>To set up a Merchant account from the Developer Console:</p>
-
-<ol>
-<li><strong>Sign in</strong> to your Google Play Developer Console at
-<a href="https://play.google.com/apps/publish/">https://play.google.com/apps/publish/</a>
-<li>Open <strong>Financial reports</strong> <img src="{@docRoot}images/distribute/console-reports.png"
-  style="vertical-align:baseline;margin:0"> on the side navigation.
-<li>Click <strong>Setup a Merchant Account now</strong>.</li>
-</ol>
-
-<p>This takes you to the Google Wallet site to sign up as a Merchant;
-you'll need information about your business available to complete this step.</p>
-
-<h3>Explore the Developer Console</h3>
-<p>When your registration is verified, you can sign in to your Developer Console, which will be the home for your app publishing operations and tools on Google Play. </p>
diff --git a/docs/html/distribute/googleplay/quality/core.jd b/docs/html/distribute/googleplay/quality/core.jd
deleted file mode 100644
index 9e23bcc..0000000
--- a/docs/html/distribute/googleplay/quality/core.jd
+++ /dev/null
@@ -1,804 +0,0 @@
-page.title=Core App Quality Guidelines
-@jd:body
-
-<div id="qv-wrapper"><div id="qv">
-<h2>Quality Criteria</h2>
-  <ol>
-    <li><a href="#ux">Design and Interaction</a></li>
-        <li><a href="#fn">Functionality</a></li>
-        <li><a href="#ps">Performance and Stability</a></li>
-        <li><a href="#listing">Google Play</a></li>
-
-  </ol>
-  
-  <h2>Testing</h2>
-  <ol>
-    <li><a href="#test-environment">Setting Up a Test Environment</a></li>
-        <li><a href="#tests">Test Procedures</a></li>
-        </ol>
-
-  <h2>You Should Also Read</h2>
-  <ol>
-    <li><a href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality Checklist</a></li>
-        <li><a href="{@docRoot}distribute/googleplay/strategies/app-quality.html">Improving App Quality</a></li>
-  </ol>
-  
-
-</div>
-</div>
-
-<p>App quality directly influences the long-term success of your app&mdash;in
-terms of installs, user rating and reviews, engagement, and user retention.
-Android users expect high-quality apps, even more so if they've spent money on
-them.</p>
-
-<p>This document helps you assess basic aspects of quality in your app through a
-compact set of <em>core app quality criteria</em> and associated tests. All
-Android apps should meet these criteria.</p>
-
-<p>Before publishing your app, make sure to test it against these criteria to
-ensure that it functions well on many devices, meets Android standards for
-navigation and design, and is prepared for promotional opportunities in the
-Google Play Store. Your testing will go well beyond what's described here&mdash;the
-purpose of this document is to specify the essential characteristics
-of basic quality so that you can include them in your test plans.</p>
-
-<p>If your app is targeting tablet devices, make sure that it delivers a rich,
-compelling experience to your tablet customers. See the <a
-href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality
-Checklist</a> for recommendations on ways to optimize your app for tablets.</p>
-
-
-<h2 id="ux">Visual Design and User Interaction</h2>
-
-<p>These criteria ensure that your app provides standard Android visual design
-and interaction patterns where appropriate, for a consistent and intuitive
-user experience.</p>
-
-<table>
-	<tr>
-		<th style="width:2px;">
-			Area
-		</th>
-		<th style="width:54px;">
-			ID
-		</th>
-		
-
-		<th>
-			Description
-		</th>
-		<th style="width:54px;">
-			Tests
-		</th>
-	</tr>
-	<tr id="UX-B1">
-	<td>Standard design</td>
-		<td>
-		UX-B1	
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">App follows <a href="{@docRoot}design/index.html">Android Design</a> guidelines and uses common <a href="{@docRoot}design/patterns/index.html">UI patterns and icons</a>:</p>
-			<ol style="margin-bottom:.5em;list-style-type:lower-alpha">
-			<li>App does not redefine the expected function of a system icon (such as the Back button).</li>
-			<li>App does not replace a system icon with a completely different icon if it triggers the standard UI behavior. </li>
-			<li>If the app provides a customized version of a standard system icon, the icon strongly resembles the system icon and triggers the standard system behavior.</li>
-			<li>App does not redefine or misuse Android UI patterns, such that icons or behaviors could be misleading or confusing to users.</li>
-			</ol>
-		</td>
-		<td><a href="#core">CR-all</a></td>
-	</tr>
-
-
-	<tr>
-		<td rowspan="3">Navigation</td>
-		<td id="UX-N1">
-			UX-N1
-		</td>
-
-		<td>
-			<p>App supports standard system <a href="{@docRoot}design/patterns/navigation.html">Back button navigation</a> and does not make use of any custom, on-screen "Back button" prompts.</p>
-		</td>
-		<td><a href="#core">CR-3</a></td>
-	</tr>
-	<tr>
-		<td id="UX-N2">
-			UX-N2 
-		</td>
-		<td>
-			<p>All dialogs are dismissable using the Back button.</p>
-		</td>
-		<td><a href="#core">CR-3</a></td>
-	</tr>
-
-	<tr  id="UX-N3">
-		<td>
-			UX-N3
-		</td>
-		<td>
-			Pressing the Home button at any point navigates to the Home screen of the device. 
-		</td>
-		<td><a href="#core">CR-1</a></td>
-	</tr>
-	<tr  id="UX-S1">
-			<td rowspan="2">Notifications</td>
-		<td>
-			UX-S1
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">Notifications follow Android Design <a href="{@docRoot}design/patterns/notifications.html">guidelines</a>. In particular:</p>
-			<ol style="margin-bottom:.5em;list-style-type:lower-alpha">
-			<li>Multiple notifications are stacked into a single notification object, where possible.</li>
-			<li>Notifications are persistent only if related to ongoing events (such as music playback or a phone call).</li>
-			<li>Notifications do not contain advertising or content unrelated to the core function of the app, unless the user has opted in.</li>
-			</ol>
-
-		</td>
-		<td><a href="#core">CR-11</a></td>
-	</tr>
-	<tr id="UX-S2">
-
-		<td>
-			UX-S2
-		</td>
-
-		<td>
-		
-			<p style="margin-bottom:.5em;">App uses notifications only to:</p>
-			<ol style="margin-bottom:.5em;list-style-type:lower-alpha">
-			<li>Indicate a change in context relating to the user personally (such as an incoming message), or</li>
-			<li>Expose information/controls relating to an ongoing event (such as music playback or a phone call).</li>
-			</ol>
-		</td>
-		<td><a href="#core">CR-11</a></td>
-	</tr>
-
-	</table>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}design/index.html">Android Design</a></strong> &mdash; Overview of design and user experience best practices for Android apps. </li>
-<li><strong><a href="{@docRoot}design/patterns/navigation.html">Navigation with Back and Up</a></strong> &mdash; Android Design document describing standard navigation patterns. </li>
-<li><strong><a href="{@docRoot}design/patterns/actionbar.html">Action Bar</a></strong> &mdash; Android Design document describing how to use the Action Bar. </li>
-<li><strong><a href="{@docRoot}design/style/iconography.html">Iconography</a></strong> &mdash;  Android Design describing how to use various types of icons.</li>
-<li><strong><a href="{@docRoot}design/patterns/notifications.html">Notifications</a></strong> &mdash;  Android Design document describing how to design and use notifications. </li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="fn">Functionality</h2>
-
-<p>These criteria ensure that your app provides expected functional behavior with the appropriate level of permissions. </p>
-
-<table>
-	<tr>
-		<th style="width:2px;">
-			Area
-		</th>
-		<th style="width:54px;">
-			ID
-		</th>
-		
-
-		<th>
-			Description
-		</th>
-		<th style="width:54px;">
-			Tests
-		</th>
-	</tr>
-
-	<tr id="FN-P1">
-	<td rowspan="2">Permissions</td>
-		<td>
-		FN-P1
-		</td>                                                                                                                                                                      
-		<td>App requests only the <em>absolute minimum</em> permissions that it needs to support core functionality.
-		</td>
-		<td rowspan="2"><a href="#core">CR-11</a></td>
-	</tr>
-	<tr id="FN-P2">
-		<td>
-			FN-P2
-		</td>                                                                                                                                                                      
-		<td><p style="margin-bottom:.5em;">App does not request permissions to access sensitive data (such as Contacts or the System Log) or services that can cost the user money (such as the Dialer or SMS), unless related to a core capability of the app.
-		</td>
-	</tr>
-	<tr id="FN-L1">
-		<td>Install location</td>
-		<td>
-			FN-L1
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">App functions normally when installed on SD card (if supported by app).</p>
-			
-			<p style="margin-bottom:.25em;">Supporting installation to SD card is recommended for most large apps (10MB+). See the <a href="{@docRoot}guide/topics/data/install-location.html">App Install Location</a> developer guide for information about which types of apps should support installation to SD card.</p>
-			</td>
-			
-			<td><a href="#SD-1">SD-1</a>
-			</td>
-	</tr>
-	<tr id="FN-A1">
-	<td rowspan="4">Audio</td>
-		<td>
-			FN-A1
-		</td>
-
-		<td>
-			Audio does not play when the screen is off, unless this is a core feature (for example, the app is a music player).
-		</td>
-		<td><a href="#core">CR-7</a></td>
-	</tr>
-	<tr id="FN-A2">
-		<td>
-			FN-A2
-		</td>
-		<td>
-			Audio does not <a href="http://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html">play behind the lock screen</a>, unless this is a core feature.
-		</td>
-		<td><a href="#core">CR-8</a></td>
-	</tr>
-	<tr id="FN-A3">
-		<td>
-			FN-A3
-		</td>
-		<td>
-			Audio does not play on the home screen or over another app, unless this is a core feature.
-		</td>
-		<td><a href="#core">CR-1, <br />CR-2</a></td>
-	</tr>
-	<tr id="FN-A4">
-		<td>
-			FN-A4
-		</td>
-		<td>
-			Audio resumes when the app returns to the foreground, or indicates to the user that playback is in a paused state.
-		</td>
-		<td><a href="#core">CR-1, CR-8</a></td>
-	</tr>
-	<tr id="FN-U1">
-	<td rowspan="3">UI and Graphics</td>
-		<td>
-			FN-U1
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">App supports both landscape and portrait orientations (if possible).</em></p>
-			<p style="margin-bottom:.25em;">Orientations expose largely the same features and actions and preserve functional parity.
-			Minor changes in content or views are acceptable.</p>
-		</td>
-		<td><a href="#core">CR-5</a></td>
-	</tr>
-	<tr id="FN-U2">
-		<td>
-			FN-U2
-		</td>
-		<td>
-		<p style="margin-bottom:.5em;">App uses the whole screen in both orientations and does not letterbox to account for orientation changes.</em></p>
-		<p style="margin-bottom:.25em;">Minor letterboxing to compensate for small variations in screen geometry is acceptable.</p>
-		</td>
-		<td><a href="#core">CR-5</a></td>
-	</tr>
-	<tr id="FN-U3">
-		<td>
-			FN-U3
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">App correctly handles rapid transitions between display orientations without rendering problems.</p>
-		</td>
-		<td><a href="#core">CR-5</a></td>
-	</tr>
-	
-	<tr  id="FN-S1">
-		<td rowspan="2">User/app state</td>
-		<td>
-			FN-S1
-		</td>
-		<td>
-		<p style="margin-bottom:.5em;">App should not leave any services running when the app is in the background, unless related to a core capability of the app.</p>
-		<p style="margin-bottom:.25em;">For example, the app should not leave services running to maintain a network connection for notifications, to maintain a Bluetooth connection, or to keep the GPS powered-on.</p>
-		</td>
-		<td><a href="#core">CR-6</a></td>
-	</tr>
-	<tr  id="FN-S2">
-		<td>
-			FN-S2
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">App correctly preserves and restores user or app state.</p>
-			<p style="margin-bottom:.25em;">App preserves user or app state when leaving the foreground and prevents accidental data loss due to back-navigation and other state changes. When returning to the foreground, the app must restore the preserved state and any significant stateful transaction that was pending, such as changes to editable fields, game progress, menus, videos, and other sections of the app or game.</p>
-			<ol style="margin-bottom:.25em;list-style-type:lower-alpha">
-			<li>When the app is resumed from the Recents app switcher, the app returns the user to the exact state in which it was last used.</li>
-			<li>When the app is resumed after the device wakes from sleep (locked) state, the app returns the user to the exact state in which it was last used.</li>
-			<li>When the app is relaunched from Home or All Apps, the app restores the app state as closely as possible to the previous state.</li>
-			<li>On Back keypresses, the app gives the user the option of saving any app or user state that would otherwise be lost on back-navigation.</li>
-			</ol>
-		</td>
-		<td><a href="#core">CR-1, CR-3, CR-5</a></td>
-	</tr>
-	
-</table>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html">Making Android Apps that Play Nice</a></strong> &mdash; Developer blog post discussing the audio lifecycle and expected audio behaviors for Android apps. </li>
-<li><strong><a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tasks and Back Stack</a></strong> &mdash; Developer guide describing how to implement back-navigation.</li>
-<li><strong><a href="{@docRoot}training/basics/activity-lifecycle/recreating.html">Recreating an Activity</a></strong> &mdash; Android Training class the shows how to preserve and restore app state.</li>
-
-</ul>
-</td>
-</tr>
-</table>
-
-
-<h2 id="ps">Performance and Stability</h2>
-
-<p>To ensure a high user rating, your app needs to perform well and stay
-responsive on all of the devices and form factors and screens that it is
-targeting. These criteria ensure that the app provides the basic performance,
-stability, and responsiveness expected by users.</p>
-
-<table>
-	<tr>
-		<th style="width:2px;">
-			Area
-		</th>
-		<th style="width:54px;">
-			ID
-		</th>
-		<th>
-			Description
-		</th>
-		<th style="width:54px;">
-			Tests
-		</th>
-	</tr>
-	<tr  id="PS-S1">
-		<td>Stability</td>
-		<td>
-			PS-S1
-		</td>
-		<td>
-			App does not crash, force close, freeze, or otherwise function abnormally on any targeted device.
-		</td>
-		<td><a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>, <a href="#HA-1">HA-1</a></td>
-	</tr>
-	
-	<tr id="PS-P1">
-	<td rowspan="2">Performance</td>
-		<td>
-			PS-P1
-		</td>
-		<td>
-			App loads quickly or provides onscreen feedback to the user (a progress indicator or similar cue) if the app
-			takes longer than two seconds to load.
-		</td>
-		<td>
-		    <a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>
-		</td>
-	</tr>
-	<tr id="PS-P2">
-
-		<td>
-			PS-P2
-		</td>
-		<td>
-			With StrictMode enabled (see <a href="#strictmode">StrictMode Testing</a>, below), no red flashes (performance warnings from StrictMode) are visible when exercising the app, including
-			during game play, animations and UI transitions, and any other part of the app.
-		</td>
-		<td>
-		    <a href="#PM-1">PM-1</a>
-		</td>
-	</tr>
-	<tr id="PS-M1">
-		<td>Media</td>
-		<td>
-			PS-M1
-		</td>
-		<td>
-			Music and video playback is smooth, without crackle, stutter, or other artifacts, during normal app usage and load.
-		</td>
-		<td>
-		    <a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>, <a href="#HA-1">HA-1</a>
-		</td>
-	</tr>
-	<tr id="PS-V1">
-		<td rowspan="2">Visual quality</td>
-	<td>
-			PS-V1
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">App displays graphics, text, images, and other UI elements without noticeable distortion, blurring, or pixelation.</p>
-			
-			<ol style="margin-bottom:.5em;list-style-type:lower-alpha">
-			<li>App provides high-quality graphics for all targeted screen sizes and form factors, including for <a href="{@docRoot}distribute/googleplay/quality/tablet.html">larger-screen devices such as tablets</a>.</li>
-			<li>No aliasing at the edges of menus, buttons, and other UI elements is visible.</li>
-			</ol>
-		</td>
-		<td rowspan="2"><a href="#core">CR-all</a></td>
-	</tr>
-	<tr id="PS-V2">
-		<td>
-			PS-V2
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">App displays text and text blocks in an acceptable manner. </p>
-			
-		 <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
-			<li>Composition is acceptable in all supported form factors, including for larger-screen devices such as tablets.</li>
-			<li>No cut-off letters or words are visible.</li>
-			<li>No improper word wraps within buttons or icons are visible.</li>
-			<li>Sufficient spacing between text and surrounding elements.</li>
-			</ol>
-		</td>
-
-	</tr>
-</table>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://android-developers.blogspot.com/2010/12/new-gingerbread-api-strictmode.html">Using StrictMode</a></strong> &mdash; Developer blog post discussing StrictMode and how to use it for performance monitoring in your app. </li>
-<li><strong><a href="{@docRoot}guide/practices/responsiveness.html">Designing for Responsiveness</a></strong> &mdash; Developer guide describing best practices for keeping your app responsive.</li>
-<li><strong><a href="http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html">Multithreading for Performance</a></strong> &mdash; Developer blog post discussing ways to improve performance through multi-threading.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-
-<h2 id="listing">Google Play</h2>
-
-<p>To launch your app successfully on Google Play, raise its ratings, and make
-sure that it is ready for promotional activities in the store, follow the
-criteria below.</p>
-
-<table>
-	<tr>
-		<th style="width:2px;">
-			Area
-		</th>
-		<th style="width:54px;">
-			ID
-		</th>
-		<th>
-			Description
-		</th>
-		<th style="width:54px;">
-			Tests
-		</th>
-	</tr>
-	<tr id="GP-P1">
-	<td rowspan="2">Policies</td>
-		<td>
-			GP-P1
-		</td>
-		<td>
-			App strictly adheres to the terms of the <a href="http://play.google.com/about/developer-content-policy.html">Google Play Developer Content Policy</a> and does not offer inappropriate content, does not use intellectual property or brand of others, and so on.
-		</td>
-		<td>
-		<a href="#gp">GP-all</a>
-		</td>
-	</tr>
-	
-	<tr id="GP-P2">
-		<td>
-			GP-P2
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">App maturity level is set appropriately, based on the 
-			<a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=188189">Content Rating Guidelines</a>.</p>
-			
-			<p style="margin-bottom:.25em;">Especially, note that apps that request permission to use the device location cannot be given the maturity level "Everyone". </p>
-		</td>
-			<td>
-		<a href="#gp">GP-1</a>
-		</td>
-	</tr>
-
-	<tr id="GP-D1">
-	<td rowspan="3">App&nbsp;Details Page</td>
-		<td>
-			GP-D1
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">App feature graphic follows the guidelines outlined in this
-			<a href="http://android-developers.blogspot.com/2011/10/android-market-featured-image.html">blog post</a>. Make sure that:</p>
-			
-			<ol style="margin-bottom:.5em;list-style-type:lower-alpha">
-				<li>The app listing includes a high-quality feature graphic.</li>
-				<li>The feature graphic does not contain device images, screenshots, or small text that will be illegible when scaled down and displayed on the smallest screen size that your app is targeting.</li>
-			    <li>The feature graphic does not resemble an advertisement.</li>
-			</ol>
-			
-		
-		</td>
-		
-				<td>
-		<a href="#gp">GP-1, GP-2</a>
-		</td>
-	</tr>
-	<tr id="GP-D2">
-		<td>
-			GP-D2
-		</td>
-		<td>
-			App screenshots and videos do not show or reference non-Android devices. 
-		</td>
-		<td rowspan="2"><a href="#gp">GP-1</a></td>
-	</tr>
-	<tr id="GP-D3">
-		<td>
-			GP-D3
-		</td>
-		<td>
-			App screenshots or videos do not 
-			represent the content and experience of your app in a misleading way.
-		</td>
-	</tr>
-	<tr id="GP-X1">
-		<td>User Support</td>
-		<td>
-			GP-X1
-		</td>
-		<td>Common user-reported bugs in the Reviews tab of the Google Play page are addressed if they are
-			reproducible and occur on many different devices. If a bug occurs on only a few devices,
-			you should still address it if those devices are particularly popular or new.
-		</td>
-		
-				<td>
-		<a href="#gp">GP-1</a>
-		</td>
-		
-	</tr>
-</table>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="https://play.google.com/apps/publish/">Launch Checklist</a></strong> &mdash; Recommendations on how to prepare your app for publishing, test it, and launch successfully on Google Play.</li>
-<li><strong><a href="http://play.google.com/about/developer-content-policy.html">Google Play Developer Program Policies</a></strong> — Guidelines for what is acceptable conent in Google Play. Please read and understand the and understand the policies before publishing.</p>
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&amp;answer=188189">Rating your application content for Google Play</a></strong> — Help Center document describing content ratings levels and how to choose the appropriate one for your app.</li>
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&amp;answer=1078870">Graphic Assets for your Application
-</a></strong> — Details about the graphic assets you need to upload before publishing.</li>
-<li><strong><a href="http://android-developers.blogspot.com/2011/10/android-market-featured-image.html">Google Play Featured Image Guidelines
-</a></strong> — Blog post discussing how to create an attractive, effective Featured Image for your app.</li>
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&amp;answer=113477&amp;topic=2364761&amp;ctx=topic">Supporting your users
-</a></strong> — Help Center document describing options for supporting users.</li>
-</ul>
-</td></tr>
-</table>
-
-
-<h2 id="test-environment">Setting Up a Test Environment</h2>
-
-<p>To assess the quality of your app, you need to set up a suitable
-hardware or emulator environment for testing. </p>
-
-<p>The ideal test environment would
-include a small number of actual hardware devices that represent key form
-factors and hardware/software combinations currently available to consumers.
-It's not necessary to test on <em>every</em> device that's on the market &mdash;
-rather, you should focus on a small number of representative devices, even using
-one or two devices per form factor. </p>
-
-<p>If you are not able to obtain actual hardware devices for testing, you should
-<a href="{@docRoot}tools/devices/index.html">set up emulated devices (AVDs)</a>
-to represent the most common form factors and
-hardware/software combinations.</p>
-
-<p>To go beyond basic testing, you can add more devices, more form factors, or
-new hardware/software combinations to your test environment. You can also
-increase the number or complexity of tests and quality criteria. </p>
-
-
-<h2 id="tests">
-  Test Procedures
-</h2>
-
-<p>These test procedures help you discover various types of quality issues in
-your app. You can combine the tests or integrate groups of tests together in
-your own test plans. See the sections above for references that associate
-specific criteria with specific tests. </p>
-
-<table>
-	<tr>
-		<th style="width:2px;">
-			Type
-		</th>
-		<th style="width:54px;">
-			Test
-		</th>
-		<th>
-			Description
-		</th>
-	</tr>
-	<tr>
-		<td rowspan="12" id="core">Core Suite</td>
-		<td>
-			CR-0
-		</td>
-		<td><p style="margin-bottom:.5em;">Navigate to all parts of the app &mdash; all screens, dialogs, settings, and all user flows. </p>
-		
-		<ol style="margin-bottom:.5em;list-style-type:lower-alpha">
-		<li>If the application allows for editing or content creation, game play, or media playback, make sure to enter those flows to create or modify content.</li>
-		<li>While exercising the app, introduce transient changes in network connectivity, battery function, GPS or location availability, system load, and so on. </li>
-			</ol>
-		</td>
-	</tr>
-	<tr id="tg2">
-		<td id="core">
-			CR-1
-		</td>
-		<td>From each app screen, press the device's Home key, then re-launch the app from the All Apps screen.
-		</td>
-	</tr>
-	<tr id="CR-2">
-		<td>
-			CR-2
-		</td>
-		<td>From each app screen, switch to another running app and then return to the app under test using the Recents app switcher.
-		</td>
-	</tr>
-
-	<tr id="CR-3">
-		<td>
-			CR-3
-		</td>
-		<td>From each app screen (and dialogs), press the Back button. 
-		</td>
-	</tr>
-		<tr id="CR-5">
-		<td>
-			CR-5
-		</td>
-		<td>From each app screen, rotate the device between landscape and portrait orientation at least three times.
-		</td>
-	</tr>
-	<tr id="CR-6">
-		<td>
-			CR-6
-		</td>
-		<td>Switch to another app to send the test app into the background. Go to Settings and check whether the test app has any services running while in the background. In Android 4.0 and higher, go to the Apps screen and find the app in the "Running" tab. In earlier versions, use "Manage Applications" to check for running services.
-		</td>
-	</tr>
-
-	
-	<tr  id="CR-7">
-		<td>
-			CR-7
-		</td>
-		<td>
-			Press the power button to put the device to sleep, then press the power button again to
-			awaken the screen.
-		</td>
-	</tr>
-	<tr id="CR-8">
-		<td>
-			CR-8
-		</td>
-		<td>
-			Set the device to lock when the power button is pressed. Press the power button to put the device to sleep, then press the power button again to
-			awaken the screen, then unlock the device.
-		</td>
-	</tr>
-	<tr id="CR-9">
-		<!-- Hardware features -->
-		<td>
-			CR-9
-		</td>
-		<td>
-			For devices that have slide-out keyboards, slide the keyboard in and out at least once.  For devices that have keyboard docks, attach the device to the keyboard dock.
-		</td>
-	</tr>
-	<tr id="CR-10">
-		<td>
-			CR-10
-		</td>
-		<td>
-			For devices that have an external display port, plug-in the external display.
-		</td>
-	</tr>
-	<tr id="CR-11">
-		<td>
-			CR-11
-		</td>
-		<td>Trigger and observe in the notications drawer all types of notifications that the app can display. Expand notifications where applicable (Android 4.1 and higher), and tap all actions offered.</td>
-	</tr>
-	<tr id="CR-12">
-		<td>
-			CR-12
-		</td>
-		<td>Examine the permissions requested by the app by going to Settings &gt; App Info.
-		</td>
-	</tr>
-	<tr id="tg3">
-	<td>Install on SD Card</td>
-		<td>
-			SD-1
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">Repeat <em>Core Suite</em> with app installed to <a href="{@docRoot}guide/topics/data/install-location.html">device SD card</a> (if supported by app).</p>
-			
-			<p style="margin-bottom:.25em;">To move the app to SD card, you can use Settings &gt; App Info &gt; Move to SD Card.</p>
-		</td>
-	</tr>
-	<tr id="tg3">
-			<td>Hardware acceleration</td>
-		<td>
-			HA-1
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">Repeat <em>Core Suite</em> with hardware acceleration enabled.</p>
-			
-			<p style="margin-bottom:.25em;">To force-enable hardware acceleration (where supported by device), add <code>hardware-accelerated="true"</code> to the <code>&lt;application&gt;</code> in the app manifest and recompile.</p>
-		</td>
-	</tr>
-	<tr id="tg3">
-			<td>Performance Monitoring</td>
-		<td>
-			PM-1
-		</td>
-		<td>
-		 <p style="margin-bottom:.5em;">Repeat <em>Core Suite</em> with StrictMode profiling enabled <a href="#strictmode">as described below</a>. <p style="margin-bottom:.25em;">Pay close attention to garbage collection and its impact on the user experience.</p>
-		</td>
-	</tr>
-	<tr  id="gp">
-		<td rowspan="3">Google Play</td>
-		<td>
-			GP-1
-		</td>
-		<td>
-			Sign into the <a href="https://play.google.com/apps/publish/">Developer Console</a> to review your developer profile, app description, screenshots, feature graphic, maturity settings, and user feedback. 
-		</td>
-	</tr>
-	<tr  id="GP-2">
-		<td>
-			GP-2
-		</td>
-		<td>
-			Download your feature graphic and screenshots and scale them down to match the display sizes on the devices and form factors you are targeting.
-		</td>
-	</tr>
-	<tr  id="GP-3">
-		<td>
-			GP-3
-		</td>
-		<td>
-			Review all graphical assets, media, text, code libraries, and other content packaged in the app or expansion file download.
-		</td>
-	</tr>
-	<tr  id="GP-4">
-	<td>Payments</td>
-		<td>
-			GP-4
-		</td>
-		<td>
-			Navigate to all screens of your app and enter all in-app purchase flows.
-		</td>
-</tr>
-
-</table>
-
-<h3 id="strictmode">
-Testing with StrictMode
-</h3>
-
-<p>For performance testing, we recommend enabling 
-{@link android.os.StrictMode} in your app
-and using it to catch operations on the main thread and other threads that could
-affect performance, network accesses, file reads/writes, and so on.</p>
-
-<p>You can set up a monitoring policy per thread using 
-{@link android.os.StrictMode.ThreadPolicy.Builder} and enable all supported monitoring in the
-<code>ThreadPolicy</code> using 
-{@link android.os.StrictMode.ThreadPolicy.Builder#detectAll()}.</p>
-
-<p>Make sure to enable <strong>visual notification</strong> of policy violations
-for the <code>ThreadPolicy</code> using {@link android.os.StrictMode.ThreadPolicy.Builder#penaltyFlashScreen() penaltyFlashScreen()}.</p>
diff --git a/docs/html/distribute/googleplay/quality/index.jd b/docs/html/distribute/googleplay/quality/index.jd
deleted file mode 100644
index ef537b1..0000000
--- a/docs/html/distribute/googleplay/quality/index.jd
+++ /dev/null
@@ -1,45 +0,0 @@
-page.title=App Quality
-@jd:body
-
-<p>App quality directly influences the long-term success of your app&mdash;in
-terms of installs, user rating and reviews, engagement, and user retention.
-Android users expect high-quality apps, even more so if they've spent money on
-them. At the same time, users enjoy and value apps that put a priority on
-continuous improvement. </p>
-
-<p>Before you publish an app on Google Play, it's important to make sure that
-your app meets the basic quality expectations of users, across all of the form
-factors and device types that the app is targeting. The documents in this
-section help you assess your app's fundamental quality and address any
-issues that you find. </p>
-
-<div class="vspace size-1">
-  &nbsp;
-</div>
-<div class="layout-content-row">
-  <div class="layout-content-col span-4">
-    <h4>
-      Core App Quality
-    </h4>
-    <p>
-      A set of core quality criteria that all Android apps should meet on all targeted devices.
-    </p><a href="{@docRoot}distribute/googleplay/quality/core.html">Learn more »</a>
-  </div>
-  <div class="layout-content-col span-4">
-    <h4>
-      Tablet App Quality
-    </h4>
-    <p>
-      A set recommendations for delivering the best possible experience to tablet users.
-    </p><a href="{@docRoot}distribute/googleplay/quality/tablet.html">Learn more »</a>
-  </div>
-  <div class="layout-content-col span-4">
-    <h4>
-      Improving App Quality
-    </h4>
-    <p>
-      Tips on continuously improving your app's quality, ratings, reviews, downloads, and engagement.
-    </p><a href="{@docRoot}distribute/googleplay/strategies/app-quality.html">Learn more
-    »</a>
-  </div>
-</div>
diff --git a/docs/html/distribute/googleplay/quality/tablet.jd b/docs/html/distribute/googleplay/quality/tablet.jd
deleted file mode 100644
index fe046d4..0000000
--- a/docs/html/distribute/googleplay/quality/tablet.jd
+++ /dev/null
@@ -1,969 +0,0 @@
-page.title=Tablet App Quality Checklist
-@jd:body
-
-<div id="qv-wrapper"><div id="qv">
-<h2>Checklist</h2>
-<ol>
-
-<li><a href="#core-app-quality">1. Test for Basic Tablet App Quality</a></li>
-<li><a href="#optimize-layouts">2. Optimize your layouts</a></li>
-<li><a href="#use-extra-space">3. Use the extra screen area</a></li>
-<li><a href="#use-tablet-icons">4. Use assets designed for tablets</a></li>
-<li><a href="#adjust-font-sizes">5. Adjust fonts and touch targets</a></li>
-<li><a href="#adjust-widgets">6. Adjust homescreen widgets</a></li>
-<li><a href="#offer-full-feature-set">7. Offer the app's full feature set</a></li>
-<li><a href="#android-versions">8. Target Android versions properly</a></li>
-<li><a href="#hardware-requirements">9. Declare dependencies properly</a></li>
-<li><a href="#support-screens">10. Declare tablet screens support</a></li>
-<li><a href="#google-play">11. Showcase your tablet UI</a></li>
-<li><a href="#google-play-best-practices">12. Follow publishing best practices</a></li>
-
-</ol>
-<h2>Testing</h2>
-<ol>
-<li><a href="#test-environment">Setting Up a Test Environment</a></li>
-</ol>
-</div></div>
-
-<p>Before you publish an app on Google Play, it's important to make sure that the app meets the basic expectations of tablet users through compelling features and an intuitive, well-designed UI. </p>
-
-<p>Tablets are a growing part of the Android installed base that offers new
-opportunities for <a
-href="{@docRoot}distribute/googleplay/spotlight/tablets.html">user engagement
-and monetization</a>. If your app is targeting tablet users, this document helps
-you focus on key aspects of quality, feature set, and UI that can have a
-significant impact on the app's success. Each focus area is given as checklist
-item, with each one comprising several smaller tasks or best practices.</p>
-
-<p>Although the checklist tasks below are numbered for convenience, 
-you can handle them in any order and address them to the extent that you feel
-is right for your app. In the interest of delivering the best possible product
-to your customers, follow the checklist recommendations
-to the greatest extent possible. </p>
-
-<p>As you move through the checklist, you'll find links to support resources
-that can help you address the topics raised in each task.</p>
-
-
-<h2 id="core-app-quality" style="margin-top:1.5em;">1. Test for basic tablet app quality</h2>
-
-<p>The first step in delivering a great tablet app experience is making sure
-that it meets the <em>core app quality criteria</em> for all of the devices
-and form factors that the app is targeting. For complete information, see the <a
-href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality Guidelines</a>. 
-</p>
-
-<p>
-  Before publishing, also ensure that your app passes several basic
-  technical checks and launch criteria, such as:
-</p>
-
-<ul>
-  <li><a href="#android-versions">Targets appropriate Android versions</a></li>
-  <li><a href="#hardware-requirements">Specifies any hardware dependencies properly</a></li>
-  <li><a href="#support-screens">Declares support for appropriate screens</a></li>
-  <li><a href="#use-extra-space">Uses all of the available screen space</a></li>
-  <li><a href="#google-play">Screenshots are uploaded to Google Play</a></li>
-</ul>
-
-<p>If your app is already uploaded to the Google Play Developer Console, you
-  can see how it is doing against these checks  
-  by visiting the <a href="#google-play-optimization-tips">Optimization
-  Tips page</a>.</p>
-
-
-<h2 id="optimize-layouts">2. Optimize your layouts for larger screens</h2>
-
-<p>Android makes it easy to develop an app that runs well on a wide range of
-device screen sizes and form factors. This broad compatibility works in your
-favor, since it helps you design a single app that you can distribute widely to
-all of your targeted devices. However, to give your users the best possible
-experience on each screen configuration &mdash; in particular on tablets
-&mdash; you need to optimize your layouts and other UI components for each
-targeted screen configuration. On tablets, optimizing your UI lets you take
-full advantage of the additional screen available, such as to offer new features,
-present new content, or enhance the experience in other ways to deepen user
-engagement.</p>
-
-<p>If you developed your app for handsets and now want to distribute it to
-tablets, you can start by making minor adjustments to your layouts, fonts, and
-spacing. In some cases &mdash; such as for 7-inch tablets or for a game with
-large canvas &mdash; these adjustments may be all
-you need to make your app look great. In other cases, such as for larger
-tablets, you can redesign parts of your UI to replace "stretched UI" with an
-efficient multipane UI, easier navigation, and additional content. </p>
-
-<p>Here are some suggestions:</p>
-
-<div style="width:390px;float:right;margin:1.5em;margin-top:0em;">
-<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-bad.png"
-style="width:390px;padding:4px;margin-bottom:0em;">
-<p class="image-caption" style="padding:0em .5em .5em 2em"><span
-style="font-weight:500;">Get rid of "stretched" UI</span>: On tablets, single-pane
-layouts lead to awkward whitespace and excessive line lengths. Use padding to
-reduce the width of UI elements and consider using multi-pane layouts.</p>
-</div>
-
-<ul>
-<li>Provide custom layouts as needed for <code>large</code> and
-<code>xlarge</code> screens. You can also provide layouts that are loaded based
-on the screen's <a href="{@docRoot}guide/practices/screens_support.html#NewQualifiers">shortest
-dimension</a> or the <a href="{@docRoot}guide/practices/screens_support.html#NewQualifiers">minimum
-available width and height</a>. </li>
-<li>At a minimum, customize dimensions such as font sizes, margins, spacing for
-larger screens, to improve use of space and content legibility. </li>
-<li>Adjust positioning of UI controls so that they are easily accessible to
-users when holding a tablet, such as toward the sides when in
-landscape orientation.</li>
-<li>Padding of UI elements should normally be larger on tablets than on handsets. A
-<a href="{@docRoot}design/style/metrics-grids.html#48dp-rhythm">48dp rhythm</a> (and a 16dp
-grid) is recommended.</li>
-<li>Adequately pad text content so that it is not aligned directly along screen edges.
-Use a minimum <code>16dp</code> padding around content near screen edges.</li>
-</ul>
-
-<p>In particular, make sure that your layouts do not appear "stretched"
-across the screen:</p>
-
-<ul>
-<li>Lines of text should not be excessively long &mdash; optimize for a maximum
-100 characters per line, with best results between 50 and 75.</li>
-<li>ListViews and menus should not use the full screen width.</li>
-<li>Use padding to manage the widths of onscreen elements or switch to a
-multi-pane UI for tablets (see next section).</li>
-</ul>
-
-<div class="rel-resources">
-  <h3>
-    Related resources
-  </h3>
-
-  <ul>
-    <li>
-      <a href=
-      "{@docRoot}design/style/metrics-grids.html">Metrics
-      and Grids</a>&mdash;Android Design document that explains how to create
-      layouts based on density-independent grids.
-    </li>
-
-    <li>
-      <a href=
-      "{@docRoot}design/style/devices-displays.html">Devices
-      and Displays</a>&mdash;Android Design document that explains how to
-      design a UI that works well on different devices and
-      screen sizes.
-    </li>
-
-    <li>
-      <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
-      Screens</a>&mdash;Developer documentation that explains the details of
-      managing UI for best display on multiple screen sizes.
-    </li>
-
-    <li>
-      <a href=
-      "{@docRoot}guide/practices/screens_support.html#ConfigurationExamples">
-      Configuration examples</a>&mdash;Examples of how to declare layouts and
-      other resources for specific screen sizes.
-    </li>
-  </ul>
-</div>
-
-
-<h2 id="use-extra-space">3. Take advantage of extra screen area available on tablets</h2>
-
-<div style="width:290px;float:right;margin:1.5em;margin-bottom:0;margin-top:0;">
-<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-good.png"
-style="width:280px;padding:4px;margin-bottom:0em;">
-<p class="image-caption" style="padding:0em .5em .5em 1.5em"><span
-style="font-weight:500;">Multi-pane layouts</span> result in a better visual
-balance on tablet screens, while offering more utility and legibility.</p>
-</div>
-
-<p>Tablet screens provide significantly more screen real estate to your app,
-especially when in landscape orientation. In particular, 10-inch tablets offer a
-greatly expanded  area, but even 7-inch tablets give you more space for
-displaying content and engaging users. </p>
-
-<p>As you consider the UI of your app when running on tablets, make sure that it
-is taking full advantage of extra screen area available on tablets. Here are
-some suggestions:</p>
-
-<ul>
-<li>Look for opportunities to include additional content or use an alternative
-treatment of existing content.</li>
-<li>Use <a href="{@docRoot}design/patterns/multi-pane-layouts.html">multi-pane
-layouts</a> on tablet screens to combine single views into a compound view. This
-lets you use the additional screen area more efficiently and makes it easier for
-users to navigate your app. </li>
-<li>Plan how you want the panels of your compound views to reorganize when
-screen orientation changes.</li>
-
-<div style="width:490px;margin:1.5em auto 1.5em 0;">
-<div style="">
-<img src="{@docRoot}images/ui-ex-single-panes.png"
-style="width:490px;padding:4px;margin-bottom:0em;" align="middle">
-<img src="{@docRoot}images/ui-ex-multi-pane.png" style="width:490px;padding:4px;margin-bottom:0em;">
-<p class="image-caption" style="padding:.5em"><span
-style="font-weight:500;">Compound views</span> combine several single views from a
-handset UI <em>(above)</em> into a richer, more efficient UI for tablets
-<em>(below)</em>. </p>
-</div>
-</div>
-
-<li>While a single screen is implemented as an {@link android.app.Activity}
-subclass, consider implementing individual content panels as {@link
-android.app.Fragment} subclasses. This lets you
-maximize code reuse across different form factors and across screens that
-share content.</li>
-<li>Decide on which screen sizes you'll use a multi-pane UI, then provide the
-different layouts in the appropriate screen size buckets (such as
-<code>large</code>/<code>xlarge</code>) or minimum screen widths (such as
-<code>sw600dp</code>/<code>sw720</code>).</li>
-</ul>
-
-<div class="rel-resources">
-  <h3>
-    Related resources
-  </h3>
-
-  <ul>
-    <li>
-      <a href="{@docRoot}design/patterns/multi-pane-layouts.html">Multi-pane
-      Layouts</a>&mdash;Android Design guide for using multi-pane UI, including
-      examples of how to flatten navigation and integrate more content into
-      your tablet UI.
-    </li>
-
-    <li>
-      <a href=
-      "{@docRoot}training/design-navigation/multiple-sizes.html">Planning for Multiple
-      Touchscreen Sizes</a>&mdash;Android Training class that walks you through
-      the essentials of planning an intuitive, effective navigation for tablets
-      and other devices.
-    </li>
-
-    <li>
-      <a href="{@docRoot}training/multiscreen/index.html">Designing for
-      Multiple Screens</a>&mdash;Android Training class that walks you through
-      the essentials of planning an intuitive, effective navigation for tablets
-      and other devices.
-    </li>
-  </ul>
-</div>
-
-
-<h2 id="use-tablet-icons">4. Use Icons and other assets that are designed
-for tablet screens</h2>
-
-<p>To ensure your app looks its best, provide icons and other bitmap
-assets for each density in the range commonly supported by tablets. Specifically, you should
-design your icons for the action bar, notifications, and launcher according to the
-<a href="{@docRoot}design/style/iconography.html">Iconography</a> guidelines and
-provide them in multiple densities, so they appear at the appropriate size on all screens
-without blurring or other scaling artifacts.</p>
-
-<p class="table-caption"><strong>Table 1</strong>. Raw asset sizes for icon types.<table>
-<tr>
-<th>Density</th>
-<th>Launcher</th>
-<th>Action Bar</th>
-<th>Small/Contextual</th>
-<th>Notification</th>
-</tr>
-<tr>
-<td><code>mdpi</code></td>
-<td>48x48 px</td>
-<td>32x32 px</td>
-<td>16x16 px</td>
-<td>24x24 px</td>
-</tr>
-<tr>
-<td><code>hdpi</code></td>
-<td>72x72 px</td>
-<td>48x48 px</td>
-<td>24x24 px</td>
-<td>36x36 px</td>
-</tr>
-<tr>
-<td><code>tvdpi</code></td>
-<td><em>(use hdpi)</em></td>
-<td><em>(use hdpi)</em></td>
-<td><em>(use hdpi)</em></td>
-<td><em>(use hdpi)</em></td>
-</tr>
-<tr>
-<td><code>xhdpi</code></td>
-<td>96x96 px</td>
-<td>64x64 px</td>
-<td>32x32 px</td>
-<td>48x48 px</td>
-</tr>
-<tr>
-<td><code>xxhdpi</code></td>
-<td>144x144 px</td>
-<td>96x96 px</td>
-<td>48x48 px</td>
-<td>72x72 px</td>
-</tr>
-
-</table>
-
-<p>Your app should supply a version of each icon and bitmap asset that's optimized
-for <strong>at least one</strong> the following common tablet screen densities:</p>
-
-<ul>
-  <li><code>hdpi</code></li>
-  <li><code>xhdpi</code></li>
-  <li><code>xxhdpi</code></li>
-</ul>
-
-<p>Other tips:</p>
-
-<ul>
-<li>When possible, use vector shapes for your icon designs so you can scale them
-without loss of detail and edge crispness.</li>
-<li>Use density-specific <a
-href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">
-resource qualifiers</a> to ensure that the proper icons are loaded for each screen density.</li>
-<li>Tablets and other large screen devices often request a launcher icon that is one density
-size larger than the device's actual density, so you should provide your launcher
-icon at the highest density possible. For example, if a tablet has an {@code xhdpi} screen,
-it will request the {@code xxhdpi} version of the launcher icon.</li>
-</ul>
-
-<div class="rel-resources">
-  <h3>
-    Related resources
-  </h3>
-
-  <ul>
-    <li>
-      <a href="{@docRoot}design/style/iconography.html">Iconography</a>&mdash;
-      Design guidelines and tips about how to create various types of icons.
-    </li>
-
-    <li>
-      <a href=
-      "{@docRoot}guide/topics/resources/providing-resources.html">Providing
-      Resources</a>&mdash;Developer documentation on how to provide
-      sets of layouts and drawable resources for specific ranges of device
-      screens.
-    </li>
-
-    <li>
-      <a href="{@docRoot}guide/practices/screens_support.html">Supporting
-      Multiple Screens</a>&mdash;API Guide documentation that
-      explains the details of managing UI for best display on multiple screen
-      sizes.
-    </li>
-
-    <li>
-      <a href=
-      "{@docRoot}training/basics/supporting-devices/screens.html">Supporting Different
-      Screens</a>&mdash;Android Training class that takes you
-      through the process of optimizing the user experience for different
-      screen sizes and densities.
-    </li>
-  </ul>
-</div>
-
-
-<h2 id="adjust-font-sizes">5. Adjust font sizes and touch targets for tablet screens</h2>
-
-<p>To make sure your app is easy to use on tablets, take some time to adjust the
-font sizes and touch targets in your tablet UI, for all of the screen
-configurations you are targeting. You can adjust font sizes through <a
-href="{@docRoot}guide/topics/ui/themes.html">styleable attributes</a> or <a
-href="{@docRoot}guide/topics/resources/more-resources.html#Dimension">dimension
-resources</a>, and you can adjust touch targets through layouts and bitmap
-drawables, as discussed above. </p>
-
-<p>Here are some considerations:</p>
-<ul>
-<li>Text should not be excessively large or small on tablet screen sizes and
-densities. Make sure that labels are sized appropriately for the UI elements they
-correspond to, and ensure that there are no improper line breaks in labels,
-titles, and other elements.</li>
-<li>The recommended touch-target size for onscreen elements is 48dp (32dp
-minimum) &mdash; some adjustments may be needed in your tablet UI. Read <a
-href="{@docRoot}design/style/metrics-grids.html">Metrics and
-Grids
-</a> to learn about implementation strategies to help most of your users. To
-meet the accessibility needs of certain users, it may be appropriate to use
-larger touch targets. </li>
-<li>When possible, for smaller icons, expand the touchable area to more than
-48dp using {@link android.view.TouchDelegate}
-or just centering the icon within the transparent button.</li>
-</ul>
-
-<div class="rel-resources">
-  <h3>
-    Related resources
-  </h3>
-
-  <ul>
-    <li>
-      <a href=
-      "{@docRoot}design/style/metrics-grids.html">Metrics
-      and Grids</a> &mdash;Android Design document that explains how to arrange
-      and size touch targets and other UI elements on the screen.
-    </li>
-
-    <li>
-      <a href="{@docRoot}design/style/typography.html">Typography</a>&mdash;Android
-      Design document that gives an overview of how to use typography in your
-      apps.
-    </li>
-
-    <li>
-      <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
-      Screens</a>&mdash;Developer documentation that explains the details of
-      managing UI for best display on multiple screen sizes.
-    </li>
-
-    <li>
-      <a href="{@docRoot}training/multiscreen/screendensities.html">Supporting
-      Different Densities</a>&mdash;Android Training class that shows you how
-      to provide sets of layouts and drawable resources for specific ranges of
-      device screens.
-    </li>
-  </ul>
-</div>
-
-
-<h2 id="adjust-widgets">6. Adjust sizes of home screen widgets for tablet screens</h2>
-
-<p>If your app includes a home screen widget, here are a few points to consider
-to ensure a great user experience on tablet screens: </p>
-
-<ul>
-<li>Make sure that the widget's default height and width are set appropriately
-for tablet screens, as well as the minimum and maximum resize height and width.
-</li>
-<li>The widget should be resizable to 420dp or more, to span 5 or more home
-screen rows (if this is a vertical or square widget) or columns (if this is a
-horizontal or square widget). </li>
-<li>Make sure that 9-patch images render correctly.</li>
-<li>Use default system margins.</li>
-<li>Set the app's <code>targetSdkVersion</code> to 14 or higher, if
-possible.</li>
-</ul>
-
-<div class="rel-resources">
-  <h3>
-    Related resources
-  </h3>
-
-  <ul>
-    <li>
-      <a href="{@docRoot}guide/topics/appwidgets/index.html#MetaData">Adding the
-      AppWidgetProviderInfo Metadata</a> &mdash;API Guide that explains how to
-      set the height and width dimensions of a widget.
-    </li>
-
-    <li>
-      <a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget
-      Design Guidelines</a>&mdash;API Guide that provides best practices and
-      techniques for designing and managing the size of widgets.
-    </li>
-  </ul>
-</div>
-
-
-<h2 id="offer-full-feature-set">7. Offer the app's full feature set to tablet users</h2>
-
-<p>Let your tablet users experience the best features of your app. Here are
-some recommendations:</p>
-
-<ul>
-<li>Design your app to offer at least the same set of features on tablets as it does on
-handsets. </li>
-<li>In exceptional cases, your app might omit or replace certain features on
-tablets if they are not supported by the hardware or use-case of most tablets.
-For example:
-<ul>
-<li>If the handset uses telephony features but telephony is not available on the
-current tablet, you can omit or replace the related functionality.</li>
-<li>Many tablets have a GPS sensor, but most users would not normally carry
-their tablets while running. If your phone app provides functionality to let the
-user record a GPS track of their runs while carrying their phones, the app would not need to
-provide that functionality on tablets because the use-case is not
-compelling.</li>
-</ul>
-</li>
-<li>If you will omit a feature or capability from your tablet UI, make sure
-that it is not accessible to users or that it offers “graceful degradation”
-to a replacement feature (also see the section below on hardware features).</li>
-</ul>
-
-<h2 id="android-versions">8. Target Android versions properly</h2>
-
-<p>To ensure the broadest possible distribution to tablets, make sure that your
-app properly targets the Android versions that support tablets. Initial support for
-tablets was added in <a href="{@docRoot}about/versions/android-3.0.html">Android 3.0</a>
-(API level 11). Unified UI
-framework support for tablets, phones, and other devices was introduced in <a
-href="{@docRoot}about/versions/android-4.0.html">Android 4.0</a> (API level 14) and is
-supported in later versions.
-
-<p>You can set the app's
-range of targeted Android versions in the manifest file, in the
-<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code>&lt;uses-sdk&gt;</code></a> element. In most cases, you can target Android versions properly by setting the element's <code>targetSdkVersion</code> attribute to the highest API level available.</p>
-
-<p style="margin-bottom:.5em;">At a minimum, check the <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code>&lt;uses-sdk&gt;</code></a>
-  element to make sure that:</p>
-
-      <ol style="list-style-type:lower-alpha;margin-top:0em;">
-        <li><code>targetSdkVersion</code> is declared with value 11 or higher (14 or higher is recommended), OR</li>
-        <li><code>minSdkVersion</code> is declared with value 11 or higher.</li>
-        <li>If a <code>maxSdkVersion</code> attribute is declared, it must have a value of 11 or higher. Note that, in general, the use of <code>maxSdkVersion</code> is <em>not recommended</em>.</li>
-</ol>
-
-<div class="rel-resources">
-<h3>
-  Related resources
-</h3>
-
-<ul>
-  <li>
-    <a href=
-    "{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">Android API
-    Levels</a>&mdash;Introduces API levels and how they relate to compatibility.
-    A reference of available API levels is included.
-  </li>
-  <li>
-    <a href="{@docRoot}training/basics/supporting-devices/platforms.html">Supporting Different Platform Versions</a>&mdash;Training class showing how to declare support for
-    minimum and target API levels in your app. 
-  </li>
-</ul>
-</div>
-
-<h2 id="hardware-requirements">9. Declare hardware feature dependencies properly</h2>
-
-<p>
-  Handsets and tablets typically offer slightly different hardware support for
-  sensors, camera, telephony, and other features. For example, many tablets are
-  available in a "Wi-Fi" configuration that does not include telephony support.
-</p>
-
-<p>
-  So that you can distribute a single APK broadly across your full customer
-  base of phones and tablets, make sure that your app doesn't declare
-  requirements for hardware features that aren't commonly available on tablets.
-  Instead, properly declare the hardware features as <em>not required</em> in the app
-  manifest, as described below.
-</p>
-
-<ul>
-<li>In your app manifest, locate any <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a>
-elements. In particular, look for hardware features that might not be
-available on some tablets, such as:
-
-<ul>
-<li><code>android.hardware.telephony</code></li>
-<li><code>android.hardware.camera</code> (refers to back camera), or</li>
-<li><code>android.hardware.camera.front</code></li>
-</ul></li>
-
-<li>Declare the <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a>
-elements as <em>not required</em> by including the <code>android:required=”false”</code>
-attribute.
-
-<p>
-  For example, here's the proper way to declare a dependency on
-  <code>android.hardware.telephony</code>, such that you can still
-  distribute the app broadly, even to devices that don't offer telephony:
-</p>
-
-<pre>&lt;uses-feature android:name="android.hardware.telephony" android:required="false" /&gt;</pre></li>
-
-<li>Similarly, check the manifest for <a href="/guide/topics/manifest/permission-element.html"><code>&lt;permission&gt;</code></a> elements that 
-<a href="/guide/topics/manifest/uses-feature-element.html#permissions">imply hardware
-feature requirements</a> that not be appropriate for tablets. If you find such
-permissions, make sure to explicitly declare a corresponding
-<code>&lt;uses-feature&gt;</code> element for the features and includes the
-<code>android:required=”false”</code> attribute.</li>
-</ul>
-
-
-<p>
-  After declaring hardware features as <em>not required</em>, make sure to test
-  your app on a variety of devices. The app should function normally when the
-  hardware features it uses are not available, and it should offer "graceful
-  degradation" and alternative functionality where appropriate.
-</p>
-
-<p>
-  For example, if an app normally uses GPS to set the location but GPS is not
-  supported on the device, the app could let the user set the location manually
-  instead. The app can check for device hardware capabilities at runtime and handle
-  as needed.
-</p>
-
-<div class="rel-resources">
-<h3>
-  Related resources
-</h3>
-
-<ul>
-  <li>
-    <a href=
-    "{@docRoot}guide/topics/manifest/uses-feature-element.html#permissions">Permissions
-    that Imply Feature Requirements</a>&mdash;A list of permissions that may
-    cause unwanted filtering if declared in your app's manifest.
-  </li>
-  <li>
-    <a href=
-    "{@docRoot}guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a>&mdash;Description
-    and reference documentation for the <code>&lt;uses-feature&gt;</code>
-    manifest element.
-  </li>
-
-  <li>
-    <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#testing">Testing
-    the features required by your application</a>&mdash;Description of how to
-    determine the actual set of hardware and software requirements (explicit or
-    implied) that your app requires.
-  </li>
-</ul>
-</div>
-
-<h2 id="support-screens">10. Declare support for tablet screens</h2>
-
-<p>To ensure that you can distribute your app to a broad range of tablets, your app should
-declare support for tablet screen sizes in its manifest file, as follows:</p>
-
-<ul>
-  <li>A
-  <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code>&lt;supports-screens&gt;</code></a>
-  element, if declared, must not specify <code>android:largeScreens="false"</code>
-  or <code>android:xlargeScreens="false"</code>.</li>
-  <li>For apps targeting <code>minSdkVersion</code> value less than 13, a
-  <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code>&lt;supports-screens&gt;</code></a>
-  element must be declared with both <code>android:largeScreens="true"</code> and
-  <code>android:xlargeScreens="true"</code>.</li>
-</ul>
-
-<p>If the app declares a
-<a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html"><code>&lt;compatible-screens&gt;</code></a>
-element in the manifest, the element should include attributes that specify
-<em>all of the size and density combinations for tablet screens</em> that the
-app supports. Note that, if possible, you should avoid using the
-<a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html"><code>&lt;compatible-screens&gt;</code></a>
-element in your app.</p>
-
-<div class="rel-resources">
-  <h3>
-    Related resources
-  </h3>
-
-  <ul>
-    <li>
-      <a href=
-      "{@docRoot}guide/practices/screens_support.html#DeclaringScreenSizeSupport">Declaring
-      Screen Size Support</a>&mdash;Developer documentation that explains the
-      details of managing UI for best display on multiple screen sizes.
-    </li>
-  </ul>
-</div>
-
-
-<h2 id="google-play">11. Showcase your tablet UI in Google Play</h2>
-
-<p>
-  After you've done the work to create an rich, optimized UI for your tablet
-  app, make sure that you let your customers know about it! Here are some key
-  ways to promote your tablet app to users on Google Play.
-</p>
-
-<h4>
-  Upload screenshots of your tablet UI
-</h4>
-
-<p>
-  Tablet users want to know what your app is like on a tablet device, not on a
-  phone. If you developed a tablet app, make sure to upload screenshots
-  of your tablet UI to the Google Play Developer Console. Here are some guidelines:
-  </p>
-
-<ul style="margin-top:0;">
-  <li>Your screenshots should show the core functionality of your app, not a
-  startup or sign-in page. Wherever users will spend most of their time, that's
-  what you should show in your screenshots.
-  </li>
-
-  <li>Add screenshots taken on both 7-inch and 10-inch tablets.
-  </li>
-
-  <li>It's recommended that you add screenshots taken in both landscape and
-  portrait orientations, if possible.
-  </li>
-
-  <li>Use screen captures if possible. Avoid showing actual device hardware in your
-  screenshots.</li>
-
-  <li>The recommended resolution of your tablet screenshots is <strong>1280 x 720</strong>
-  or higher in each orientation.
-  </li>
-
-  <li>You can upload as many as 8 screenshots of your tablet UI for 7-inch tablets
-  and an additional 8 for 10-inch tablets.
-  </li>
-</ul>
-
-<h4>
-  Update your app description and release notes
-</h4>
-
-<ul>
-  <li>In your app description, make sure to highlight that your app offers
-  tablet-optimized UI and great features for tablet users. Consider adding some
-  detail about how your tablet UI works and why users will like it.
-  </li>
-
-  <li>Include information about tablet support in the app's release notes and
-  update information.
-  </li>
-</ul>
-
-<h4>
-  Update your promotional video
-</h4>
-
-<p>
-  Many users view an app's promotional video to get an idea of what the app is
-  like and whether they'll enjoy it. For tablet users, capitalize on this
-  interest by highlighting your app's tablet UI in your promotional video. Here
-  are some tips and guidelines:
-</p>
-
-<ul>
-  <li>Add one or more shots of your app running on a tablet. To engage with
-  tablet users most effectively, it's recommended that you promote your tablet
-  UI in approximately equal proportion to your phone UI.
-  </li>
-
-  <li>Show your tablet UI as early as possible in the video. Don't assume that
-  tablet users will wait patiently through a feature walkthrough on a phone UI.
-  Ideally, you should engage them immediately by showing the tablet UI within
-  the first 10 seconds, or at the same point that you introduce the phone UI.
-  </li>
-
-  <li>To make it clear that you are showing a tablet UI, include shots of your
-  app running on a hand-held tablet device.
-  </li>
-
-  <li>Highlight your app's tablet UI in the video's narrative or voiceover.
-  </li>
-</ul>
-
-<h4>
-  Feature your tablet UI in your promotional campaigns
-</h4>
-
-<p>
-  Make sure to let tablet users know about your tablet UI in your promotional
-  campaigns, web site, social posts, advertisements, and elsewhere. Here are
-  some suggestions:
-</p>
-
-<ul>
-  <li>Plan a marketing or advertising campaign that highlights the use of your
-  app on tablets.</li>
-
-  <li>Show your tablet app at its best in your promotional campaigns&mdash;use the <a href=
-  "{@docRoot}distribute/promote/device-art.html">Device Art Generator</a> to
-  quickly generate a high-quality promotional image of your app running on a
-  7-inch or 10-inch tablet, in the orientation of your choice, with or without
-  drop-shadow and screen glare. It's as simple as capture, drag, and drop.
-  </li>
-
-  <li>Include a Google Play badge in your online promotions to let users link
-  directly to your app's store listing. You can generate a badge in a variety
-  of languages using the <a href=
-  "{@docRoot}distribute/googleplay/promote/badges.html">Badge Generator</a>.
-  </li>
-</ul>
-
-<div class="rel-resources">
-  <h3>
-    Related resources
-  </h3>
-
-  <ul>
-    <li>
-      <a href="{@docRoot}distribute/googleplay/publish/preparing.html">Publishing
-      Checklist</a>
-      &mdash;Recommendations on how to prepare your app for publishing, test
-      it, and launch successfully on Google Play.
-    </li>
-
-    <li>
-      <a href="https://play.google.com/apps/publish/">Google Play
-      Developer Console</a>&mdash;The tools console for publishing
-      your app to Android users.
-    </li>
-    <li>
-      <a href=
-      "{@docRoot}distribute/googleplay/promote/badges.html">Google Play
-      Badge Generator</a>&mdash;Create "Get it on Google Play" badges for your
-      app in a variety of languages with a single click. 
-    </li>
-    <li>
-      <a href=
-      "{@docRoot}distribute/promote/device-art.html">Device Art
-      Generator</a>&mdash;Drag and drop tool that lets you instantly create production-
-      ready art showing your app running on a tablet device. 
-    </li>
-  </ul>
-</div>
-
-<h2 id="google-play-best-practices">12. Follow best practices for publishing in Google Play</h2>
-
-<p>Here are some best practices for delivering a successful tablet app on Google Play.</p>
-
-<h4 id="google-play-optimization-tips">Check out your app's Optimization Tips</h4>
-
-<p>The Google Play Developer Console now offers an Optimization Tips page that
-lets you quickly check how your app is doing against basic guidelines for tablet app
-distribution and quality. To visit the page, sign into the Developer Console,
-load the app from All Applications, and click Optimization Tips in
-the left navigation.</p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2 style="line-height:1em;">How to send feedback</h2>
-
-<p>Please use the link below to send
-feedback or request a manual review of your Optimization Tips.</p>
-
-<p>Make sure to read the relevant sections of the Tablet App Quality
-Guidelines prior to sending feedback.</p>
-
-<p><strong><a href="https://support.google.com/googleplay/android-developer/contact/tabletq"
-target="_googleplay" style="white-space:nowrap">Designed for Tablets Contact Form &raquo;</a></strong></p>
-</div>
-</div>
-
-<p>The Developer Console creates your app's Optimization Tips page
-by running a series of checks to verify basic quality
-criteria. If it finds any issues, it alerts you to them as "To Do"
-items in the Optimization Tips page.</p>
-
-<p>If you've developed a tablet experience for your app, make sure
-to visit the Optimization Tips page to see how your app is doing
-against the basic checks.  If there are any issues listed, we
-recommend addressing them in your app and uploading a new binary for
-distribution, if needed. </p>
-
-<p>If the Optimization Tips page lists "To Do" issues that you feel don't
-apply to your app or affect its quality on tablets, please notify us
-using the <a href="https://support.google.com/googleplay/android-developer/contact/tabletq"
-target="_googleplay" style="white-space:nowrap">Designed for Tablets Contact Form &raquo;</a>. We
-will review your app and update your Optimization Tips page as
-appropriate.</p>
-
-
-<h4>Confirm the app's filtering</h4>
-
-<p>After you've uploaded the app to the <a href="https://play.google.com/apps/publish/">Developer Console</a>, check the APK's Supported Devices list to make sure that the app is not filtered from tablet devices that you want to target.</p>
-
-<h4>Distribute as a single APK</h4>
-
-<p>
-  It's recommended that you publish your app as a single APK for all screen
-  sizes (phones and tablets), with a single Google Play listing. This approach
-  has several important advantages.
-</p>
-
-<ul style="margin-top:.25em;">
-  <li>Easier for users to find your app from search, browsing, or promotions
-  </li>
-
-  <li>Easier for users to restore your app automatically if they get a new
-  device.
-  </li>
-
-  <li>Your ratings and download stats are consolidated across all devices.
-  </li>
-
-  <li>Publishing a tablet app in a second listing can dilute ratings for your
-  brand.
-  </li>
-</ul>
-
-<p>
-  If necessary, you can alternatively choose to deliver your app using <a href=
-  "{@docRoot}google/play/publishing/multiple-apks.html">Multiple APK Support</a>,
-  although in most cases using a single APK to reach all devices is strongly
-  recommended.
-</p>
-
-<div class="rel-resources">
-<h3>Related resources</h3>
-<ul>
-<li><a href="{@docRoot}distribute/googleplay/publish/preparing.html">Publishing
-      Checklist</a>&mdash;
-  Recommendations on how to prepare your app for publishing, test it, and launch
-  successfully on Google Play.</li>
-<li><a href="https://play.google.com/apps/publish/">Google Play Developer
-  Console</a>&mdash;The tools console for publishing your app to Android users.</li>
-</ul>
-</div>
-
-
-<h2 id="test-environment">Setting Up a Test Environment for Tablets</h2>
-
-<p>To assess the quality of your app on tablets &mdash; both for core app quality
-and tablet app quality &mdash; you need to set up a suitable
-hardware or emulator environment for testing. </p>
-
-<p>The ideal test environment would
-include a small number of actual hardware devices that represent key form
-factors and hardware/software combinations currently available to consumers.
-It's not necessary to test on <em>every</em> device that's on the market &mdash;
-rather, you should focus on a small number of representative devices, even using
-one or two devices per form factor.  The table below provides an overview of
-devices you could use for testing.</p>
-
-<p>If you are not able to obtain actual hardware devices for testing, you should
-<a href="{@docRoot}tools/devices/index.html">set up emulated devices (AVDs)</a>
-to represent the most common form factors and
-hardware/software combinations. See the table below for suggestions on the emulator
-configurations to use. </p>
-
-<p>To go beyond basic testing, you can add more devices, more form factors, or
-new hardware/software combinations to your test environment. For example, you
-could include mid-size tablets, tablets with more or fewer hardware/software
-features, and so on. You can also increase the number or complexity of tests
-and quality criteria. </p>
-
-<p class="table-caption"><strong>Table 1</strong>. A typical tablet test environment might
-include one or two devices from each row in the table below, with one of the
-listed platform versions, screen configurations, and hardware feature configurations.</p>
-
-<table>
-<tr>
-<th>Type</th>
-<th>Size</th>
-<th>Density</th>
-<th>Version</th>
-<th>AVD Skin</th>
-</tr>
-
-<tr>
-<td>7-inch tablet</td>
-<td><span style="white-space:nowrap"><code>large</code> or</span><br /><code>-sw600</code></td>
-<td><code>hdpi</code>,<br /><code>tvdpi</code></td>
-<td>Android 4.0+ (API level 14 and higher)</td>
-<td>WXGA800-7in</td>
-</tr>
-<tr>
-<td><span style="white-space:nowrap">10-inch</span> tablet</td>
-<td><span style="white-space:nowrap"><code>xlarge</code> or</span><br /><code>-sw800</code></td>
-<td><code>mdpi</code>,<br /><code>hdpi</code>,<br /><code>xhdpi</code></td>
-<td>Android 3.2+ (API level 13 and higher)</td>
-<td>WXGA800</td>
-</tr>
-</table>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/spotlight/games.jd b/docs/html/distribute/googleplay/spotlight/games.jd
deleted file mode 100644
index 1fbc03f..0000000
--- a/docs/html/distribute/googleplay/spotlight/games.jd
+++ /dev/null
@@ -1,245 +0,0 @@
-page.title=Developer Stories: Google Play Game Services
-walkthru=0
-header.hide=0
-
-@jd:body
-
-<p>One of the goals of <a href="https://developers.google.com/games/">Google
-Play game services</a> is to allow developers to focus on what they’re good at
-as game developers &mdash; creating great gaming experiences for their users, by
-building on top of what Google is good at: mobile and cloud services. Integral
-to that is an easy integration process, one that provides a whole host of
-features with little engineering work required.</p>
-
-<p>The gaming studios below understood the opportunity that Google Play game
-services unlocked, and are starting to see real results following their
-successful integrations. </p>
-
-<div style="margin-bottom:2em;"><!-- START STORY -->
-
-<h3>Concrete Software &mdash;  Straightforward, easy to implement</h3>
-
-<img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
-  -moz-border-radius: 5px;
-  border-radius: 5px height:78px;
-  width: 78px;
-  float: left;
-  margin: 12px 20px 9px 20px;"
-  src="//lh6.ggpht.com/_UOay5HBxf077suKYzmikU2IbnYOJub3X0inz-LoUsVh4TX758BEyArjoR7owXijkAA=w124">
-
-<div style="list-style: none;height:100%;
-  float: right;
-  border-top: 1px solid #9C0;
-  width: 220px;
-  margin: 4px 20px;padding: .5em;">
-  
-  <h5>About the developer</h5> 
-    <ul>
-      <li><a href="https://play.google.com/store/apps/developer?id=Concrete%20Software%2C%20Inc.">Concrete Software</a>, 
-      makers of <a href="https://play.google.com/store/apps/details?id=com.concretesoftware.pbachallenge_androidmarket&hl=en">PBA
-      Bowling Challenge</a></li>
-      <li>Added support for multiplayer, leaderboards and achievements through Google Play game
-      services</li>
-    </ul>
-
-    <h5>Results</h5> 
-    <ul>
-      <li>Session lengths have increased more than 15%</li>
-    </ul>
-    
-    <div style="padding:.5em 0 0 1em;">
-      <a href="https://play.google.com/store/apps/details?id=com.concretesoftware.pbachallenge_androidmarket&hl=en">
-       <img alt="Android app on Google Play" src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
-      </a>
-    </div>
-</div>
-
-<div style="line-height:1.4em;">
-<p style="margin-top:0;margin-bottom:12px;">Concrete Software added several
-features from Google Play game services into one of their top titles,
-<a href="https://play.google.com/store/apps/details?id=com.concretesoftware.pbachallenge_androidmarket">PBA
-Bowling Challenge</a>, including support for multiplayer, leaderboards, and
-achievements.</p>
-
-<p>So far, their users have loved the new additions: average session length
-is up more than 15%. Keith Pichelman, CEO of Concrete Software, explains: </p>
-
-<p>"The Google Play game services were straightforward and easy to implement. We
-had been researching options for multiplayer services, so when Google Play game
-services came out, it was an easy decision for us. Not only were they easy to
-integrate, but the features have worked flawlessly. </p>
-
-<p>"PBA Bowling Challenge now has real-time multiplayer which our users instantly
-were thrilled with; you can see in the reviews how people immediately raved about
-the new game experience. </p>
-
-<p>"We also included achievements, leaderboards, and most recently cloud
-synchronization from the Google Play game services as well. Using the game
-services in PBA Bowling Challenge was a huge success, enough so that we are now
-going back to our other titles, adding the features to them as well."</p>
-</div>
-
-<div style="clear:both;margin-top:40px;width:auto;">
-  
-  <img src="{@docRoot}images/distribute/concrete-pbc-gpgames.jpg">
-
-  <div style="width:600px;margin-top:0px;padding:0 90px;">
-    <p class="image-caption"><span style="font-weight:500;">Session lengths up:</span>
-    After adding support for multiplayer with Google Play game services, Concrete
-    Software saw an increase in session lengths of more than 15% for PBA Bowling
-    Challenge.</p>
-  </div>
-</div>
-</div> <!-- END STORY -->
-
-<div style="margin:3em auto"><!-- START STORY -->
-
-<h3>Glu: It’s a must-have for all titles</h3>
-
-<img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
-  -moz-border-radius: 5px;
-  border-radius: 5px height:78px;
-  width: 78px;
-  float: left;
-  margin: 12px 20px 30px 20px;"
-  src="//lh4.ggpht.com/Q7mQJsdhulW4_s039R9aaRhQkGnyzLkhF00j5EnyhHOivijnyi7P7b5A8qG0xk1r-jQ=w124">
-          
-<div style="list-style: none;height:100%;
-  float: right;
-  border-top: 1px solid #9C0;
-  width: 220px;
-  margin: 4px 20px;padding: .5em;">
-
-  <h5>About the developer</h5> 
-    <ul>
-      <li><a href="https://play.google.com/store/apps/developer?id=Glu+Mobile">Glu
-      Mobile</a>, creators of <a href="https://play.google.com/store/apps/details?id=com.glu.ewarriors2">Eternity
-      Warriors 2</a></li>
-      <li>Has already integrated 5 titles with Google Play game services</li>
-    </ul>
-
-  <h5>Results</h5> 
-    <ul>
-      <li>In Eternity Warriors 2, 7-day user retention is up 40%</li>
-      <li>20% increase in play sessions per day as well</li>
-    </ul>
-
-    <div style="padding:.5em 0 0 1em;">
-      <a href="https://play.google.com/store/apps/details?id=com.glu.ewarriors2">
-        <img alt="Android app on Google Play" src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
-      </a>
-    </div>
-</div>
-
-<div style="line-height:1.4em;">
-<p style="margin-top:0;margin-bottom:12px;">Glu was one of the first developers
-to integrate Google Play game services, with
-<a href="https://play.google.com/store/apps/details?id=com.glu.ewarriors2">Eternity
-Warriors 2</a>. Based on this first success, Glu has integrated game services
-into several more games, including Samurai vs. Zombies 2, Frontline Commando:
-D-Day, Contract Killer 2, and Zombies Ate My Friends.</p>
-
-<p>Already supported in Eternity Warriors 2, they’ve seen a 40% increase in 7-day
-user retention and a 20% increase in play sessions per day. Sourabh Ahuja, Glu's
-Vice President of Android Development, explains:</p>
-
-<p>“Multiplayer, leaderboards, achievements &mdash; these are all things that we
-had to build individually for our titles. The availability of these features in
-Google Play game services helps us make our games stickier, and it’s awesome that
-it comes directly from Google. </p>
-
-<p>"It’s flexible enough that we were able to make it interoperable with our
-in-house systems. We look forward to utilizing game services extensively across
-our portfolio."</p>
-</div>
-
-<div style="clear:both;margin-top:40px;width:auto;">
-
-  <img src="{@docRoot}images/distribute/glu-ew-gpgames.jpg"></a>
-
-  <div style="width:600px;margin-top:0px;padding:0 90px;">
-    <p class="image-caption"><span style="font-weight:500;">User retention up:</span>
-    Glu saw a 40% increase in 7-day user retention for Eternity Warriors 2 after
-    integrating with Google Play game services.</p>
-  </div>
-</div>
-</div> <!-- END STORY -->
-
-
-<div style="margin-bottom:2em;"><!-- START STORY -->
-
-<h3>Vector-Unit: An awesome multiplayer experience</h3>
-
-<img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
-  -moz-border-radius: 5px;
-  border-radius: 5px height:78px;
-  width: 78px;
-  float: left;
-  margin: 12px 20px 9px 20px;" src=
-  "https://lh3.ggpht.com/dTUrKLffqXHJtPuIlp8fjDhROuzrTcpidbNFprugR65hMrPLX7Omd8SGop0xMXXKzcw=w124">
-  
-<div style="list-style: none;height:100%;
-  float: right;
-  border-top: 1px solid #9C0;
-  width: 220px;
-  margin: 4px 20px;padding: .5em;">
-  
-  <h5>About the developer</h5> 
-    <ul>
-      <li><a href="https://play.google.com/store/apps/developer?id=Vector+Unit">Vector
-      Unit</a>, creators of <a href="https://play.google.com/store/apps/details?id=com.vectorunit.red">Riptide
-      GP2</a></li>
-      <li>Added multiplayer to Riptide GP2 through Google Play game services </li>
-    </ul>
-
-  <h5>Results</h5> 
-    <ul>
-      <li>With an easy multiplayer solution, they were able to focus on the
-      gameplay</li>
-      <li>Early reviews of Riptide GP2 called multiplayer “one of the sweetest
-      cherries on top!”</li>
-    </ul>
-
-  <div style="padding:.5em 0 0 1em;">
-    <a href="https://play.google.com/store/apps/details?id=com.vectorunit.red">
-      <img alt="Android app on Google Play" src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
-    </a>
-  </div>
-</div>
-
-<div style="line-height:1.4em;">
-<p style="margin-top:0;margin-bottom:12px;">Vector Unit just launched their
-latest title, <a href="https://play.google.com/store/apps/details?id=com.vectorunit.red">Riptide
-GP2</a>, with Google Play game services integration, and it has one of the strongest
-integrations of multiplayer yet. Early reviews call multiplayer “one of the sweetest
-cherries on top!”.</p>
-
-<p>Ralf Knoesel, CTO of Vector Unit, tells more about how they've used Google Play game
-services:</p>
-    
-<p>“We wanted to provide a really compelling multiplayer experience for our users, and
-Google Play game services allowed us to do just that. With multiplayer, you can show off
-your skills and your custom-tuned hydro jet in 4-way online battles with friends and
-players around the world. </p>
-
-<p>"By providing an easy way to power this multiplayer experience, we were able to focus
-on making the gameplay come alive &mdash; like the stunts, which are more daring and
-slicker than ever (with more of them to master), or the realistic detail of the water
-splashing against the camera lens.”</p>
-
-</div>
-
-<div style="clear:both;margin-top:40px;width:auto;">
-  
-  <img src="{@docRoot}images/distribute/vector-unit-rt-gpgames.jpg"></a>
-
-  <div style="width:600px;margin-top:0px;padding:0 90px;">
-    <p class="image-caption"><span style="font-weight:500;">Multiplayer and more:</span>
-    Google Play game services helped Vector Unit pack an awesome multiplayer experience
-    into Riptide GP 2, so they could focus on building a great gaming experience.</p>
-  </div>
-</div>
-</div> <!-- END STORY -->
-
-
-
diff --git a/docs/html/distribute/googleplay/spotlight/index.jd b/docs/html/distribute/googleplay/spotlight/index.jd
deleted file mode 100644
index fc2e162..0000000
--- a/docs/html/distribute/googleplay/spotlight/index.jd
+++ /dev/null
@@ -1,162 +0,0 @@
-page.title=Spotlight
-page.tags="videos, google play, monetize, inapp"
-meta.tags="stories, googleplay, monetizing, landing"
-page.image=/images/video-kiwi.jpg
-walkthru=0
-header.hide=0
-
-@jd:body
-
-
-<p>Android developers, their apps, and their successes with Android and Google Play. </p>
-
-<div id="Kiwi" style="background: #F0F0F0;
-            border-top: 1px solid #DDD;
-            padding: 0px 0 24px 0;
-            overflow: auto;
-            clear:both;
-            margin-bottom:40px;
-            margin-top:30px;">
-   <div style="padding:0 0 0 29px;">
-        <h4>Developer Story: Kiwi, Inc.</h4>
-          <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
-            -moz-border-radius: 5px;
-            border-radius: 5px height:78px;
-            width: 78px;
-            float: left;
-            margin: 17px 20px 9px 0;" 
-            src="//lh4.ggpht.com/qUI-8MJy70l4qoVBR_sx-56ckR_m0R_ZXcJ1DiTYUR3R_owWzsCFTYkAk4p5DMnaSdY3=w124" >
-          <div style="width:700px;">
-          <p style="margin-top:26px;
-                    margin-bottom:12px;">
-          Android-first developer <a href="//play.google.com/store/apps/developer?id=Kiwi,+Inc." target="_android">Kiwi, Inc.</a> has had 5 titles in the top 25 grossing on Google Play, including <a href="https://play.google.com/store/apps/details?id=com.kiwi.shipwrecked" target="_android">Shipwrecked: Lost Island</a>, <a href="https://play.google.com/store/apps/details?id=com.kiwi.monsterpark" target="_android">Monsterama Park</a>, and <a href="https://play.google.com/store/apps/details?id=com.kiwi.mysteryestate" target="_android">Hidden Object: Mystery Estate</a>. Hear how Google Play helped them double revenue every six months with features like instant updates, staged rollouts, and more.</p>
-           </div>
-           <iframe style="float:left;
-             margin-right:24px;
-             margin-top:14px;" width="700" height="394" src=
-             "http://www.youtube.com/embed/WWArLD6nqrk?HD=1;rel=0;origin=developer.android.com;" frameborder="0" allowfullscreen>
-           </iframe>
-   </div>
-</div>
-<div style="background: #F0F0F0;
-            border-top: 1px solid #DDD;
-            padding: 0px 0 24px 0;
-            overflow: auto;
-            clear:both;
-            margin-bottom:40px;
-            margin-top:30px;">
-   <div style="padding:0 0 0 29px;">
-        <h4>Developer Story: Colopl</h4>
-          <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
-            -moz-border-radius: 5px;
-            border-radius: 5px height:78px;
-            width: 78px;
-            float: left;
-            margin: 17px 20px 9px 0;" 
-            src="//lh3.ggpht.com/sx2ILNaXQYOsHfR91T5tUWGlfXE1FutHCBN02Fll6mi9gIaG6RZCGbeJMtIvOoegCPTh=w124" >
-          <div style="width:700px;">
-          <p style="margin-top:26px;
-                    margin-bottom:12px;">
-          The creators of Kuma The Bear, Japan-based <a href="https://play.google.com/store/apps/developer?id=COLOPL,+Inc." target="_android">Colopl</a>, talk about how Google Play and Android allowed them to grow their business to become one of the most profitable games publishers in APAC to date. </p>
-           </div>
-           <iframe style="float:left;
-             margin-right:24px;
-             margin-top:14px;" width="700" height="394" src=
-             "http://www.youtube.com/embed/CbpoZeQCNe4?HD=1;rel=0;origin=developer.android.com;" frameborder="0" allowfullscreen>
-           </iframe>
-   </div> 
-</div>
-
-<div style="background: #F0F0F0;
-            border-top: 1px solid #DDD;
-            padding: 0px 0 24px 0;
-            overflow: auto;
-            clear:both;
-            margin-bottom:40px;
-            margin-top:30px;">
-   <div style="padding:0 0 0 29px;">
-        <h4>Developer Story: redBus.in</h4>
-          <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
-            -moz-border-radius: 5px;
-            border-radius: 5px height:78px;
-            width: 78px;
-            float: left;
-            margin: 17px 20px 9px 0;" src=
-            "//lh4.ggpht.com/kvI2XfzBPGBDASvxvP18MCCj7YPEmLcG4nh1BlYW4XzaW12gg3iXtcM2ZqDnAfLLB9ed=w124">
-          <div style="width:700px;">
-          <p style="margin-top:26px;
-                    margin-bottom:12px;">
-          Bangalore-based developers <a href="//play.google.com/store/apps/details?id=in.redbus.android">redBus.in</a> are bringing the sophistication and convenience of air-travel booking to bus transit. Hear how Android is helping them deliver a superior travel experience to millions of daily bus riders in India.</p>
-           </div>
-           <iframe style="float:left;
-             margin-right:24px;
-             margin-top:14px;" width="700" height="394" src=
-             "http://www.youtube.com/embed/O8i4HUw7JYA?HD=1;rel=0;origin=developer.android.com;" frameborder="0" allowfullscreen>
-           </iframe>
-   </div> 
-</div>
-
-<div style="background: #F0F0F0;
-            border-top: 1px solid #DDD;
-            padding: 0px 0 24px 0;
-            overflow: auto;
-            clear:both;
-            margin-bottom:40px;
-            margin-top:30px;">
-   <div style="padding:0 0 0 29px;">
-        <h4>Developer Story: Smule</h4>
-          <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
-            -moz-border-radius: 5px;
-            border-radius: 5px height:78px;
-            width: 78px;
-            float: left;
-            margin: 17px 20px 9px 0;" src=
-            "//lh6.ggpht.com/z5wl9PuHl9JfO54uefjRTUX70SuLY-1DRpPxQ5mg7XEDfnYhBDssh1RrPZjN1tbwzhg=w124">
-          <div style="width:700px;">
-          <p style="margin-top:26px;
-                    margin-bottom:12px;">
-          The creators of <a href="//play.google.com/store/apps/details?id=com.smule.autorap">AutoRap</a>, <a href="//play.google.com/store/apps/details?id=com.smule.magicpiano">Magic Piano</a>, and <a href="//play.google.com/store/apps/details?id=com.smule.songify">Songify</a> talk about their experiences launching on Android, the explosive global growth they’ve seen on Google Play, and some of the techniques they use to market and monetize their products effectively across the world.</p>
-           </div>
-           <iframe style="float:left;
-             margin-right:24px;
-             margin-top:14px;" width="700" height="394" src=
-             "http://www.youtube.com/embed/RRelFvc6Czo?HD=1;rel=0;origin=developer.android.com;" frameborder="0" allowfullscreen>
-           </iframe>
-   </div> 
-</div>
-
-<div style="background: #F0F0F0;
-            border-top: 1px solid #DDD;
-            padding: 0px 0 24px 0;
-            overflow: auto;
-            clear:both;
-            margin-bottom:-10px;
-            margin-top:30px;">
-   <div style="padding:0 0 0 29px;">
-        <h4>Developer Story: Robot Invader</h4>
-          <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
-            -moz-border-radius: 5px;
-            border-radius: 5px height:78px;
-            width: 78px;
-            float: left;
-            margin: 17px 20px 9px 0;" src=
-            "//g0.gstatic.com/android/market/com.robotinvader.knightmare/hi-256-0-9e08d83bc8d01649e167131d197ada1cd1783fb0">
-          <div style="width:700px;">
-          <p style="margin-top:26px;margin-bottom:12px;">Robot Invader chose 
-              Android and Google Play as the launch platform for their first game,<br /> 
-              <a data-g-event="Developers Page" data-g-label="Case Study Link" href=
-              "//play.google.com/store/apps/details?id=com.robotinvader.knightmare"><em>Wind-up
-              Knight</em></a>.
-           </p>
-           <p>
-              Hear from the developers how Android helped them reach millions of users 
-              and more than 100 device models with a single app binary, then iterate rapidly to ensure
-              a great user experience.
-           </p>
-           </div>
-           <iframe style="float:left;
-             margin-right:24px;
-             margin-top:14px;" width="700" height="394" src=
-             "http://www.youtube.com/embed/hTtlLiUTowY" frameborder="0" allowfullscreen></iframe>
-   </div> 
-</div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/spotlight/localization.jd b/docs/html/distribute/googleplay/spotlight/localization.jd
deleted file mode 100644
index ae5993d..0000000
--- a/docs/html/distribute/googleplay/spotlight/localization.jd
+++ /dev/null
@@ -1,328 +0,0 @@
-page.title=Developer Stories: Localization in Google Play
-walkthru=0
-header.hide=0
-
-@jd:body
-
-<p>
-  As you build your app and distribute it across the world through Google Play,
-  localization becomes an increasingly important tool to reach more users.
-  Localization involves a <a href=
-  "{@docRoot}distribute/googleplay/publish/localizing.html">variety of tasks</a>, but
-  most important is creating quality translations of your app's UI strings and
-  marketing materials.
-</p>
-
-<p>
-  Managing the translation process across multiple languages can be a
-  challenge, especially if you need to locate translators on your own. That’s
-  why Google Play offers the App Translation Service right from the Developer
-  Console. It's a single place where you can go to source professional
-  translators, get cost estimates, and then send your strings and other
-  materials for translation.
-</p>
-
-<p>
-  Here are some stories from developers who have used Google Play's App Translation
-  Service to localize their apps and the results they've seen as they've
-  expand their offerings beyond a single language.
-</p>
-
-<!-- START STORY -->
-
-<div style="margin-bottom:2em;padding-top:10px;" id="zombieragdoll">
-
-<h3 style="line-height:1.25em">Zombie Ragdoll: Improved user engagement<br /> with localized versions</h3>
-
-  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
-            -moz-border-radius: 5px;
-            border-radius: 5px height:78px;
-            width: 78px;
-            float: left;
-            margin: 12px 20px 9px 20px;" src=
-            "https://lh4.ggpht.com/m-Ew8c8C_nGctbP6PSPGOaVNnGFryReOE2yHXJ9Z6Prk1nsDyx5w5TmWfg-P5N3HypA=w124">
-
-  <div style="list-style: none;height:100%;
-  float: right;
-  border-top: 1px solid #9C0;
-  width: 220px;
-  margin: 4px 20px;padding: .5em;">
-
-    <h5>About the app</h5>
-
-    <ul>
-      <li><a href="https://play.google.com/store/apps/details?id=com.rvappstudios.zombieragdoll">Zombie Ragdoll</a></li>
-      <li>A fun zombie-based physics game</li>
-    </ul>
-
-    <h5>Localization Results</h5>
-
-    <ul>
-      <li>Increased engagement because of appeal of the localized version</li>
-      <li>80% of installs came from users of non-English languages</li>
-      </ul>
-
-    <div style="padding:.5em 0 0 1em;">
-      <a href="https://play.google.com/store/apps/details?id=com.rvappstudios.zombieragdoll">
-        <img alt="Android app on Google Play"
-         src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
-      </a>
-
-    </div>
-  </div>
-
-  <div style="line-height:1.4em;">
-
-<p>
-  The 2013 Google I/O talks about <a href=
-  "https://developers.google.com/events/io/sessions/326345917">Building Android
-  Apps for a Global Audience</a> and <a href=
-  "https://developers.google.com/events/io/sessions/326455375">What’s New for
-  Developers in Google Play</a> inspired developers at RV AppStudios to go global
-  from very beginning for their new game, Zombie Ragdoll. They launched Zombie
-  Ragdoll in August 2013, localized into 20 languages.
-</p>
-
-<p>
-  They quickly saw the impact of their decision to ship simultaneously in
-  multiple languages through increased non-English installs and improved
-  engagement with users worldwide. In addition, they started getting
-  significant usage in countries where their apps had not been as popular
-  before. They are seeing great traction in countries like Vietnam, Russia,
-  Philippines and Thailand.
-</p>
-
-<p>
-  Vivek Dave, founder of RV AppStudios, credits the success of Zombie Ragdoll
-  to localization:
-</p>
-
-<p>
-  "The value of localization is clear, it helps discoverability and helps
-  connect with the users in other countries. So when the localization
-  opportunity arose, we immediately jumped on it. Android is worldwide, and we
-  would be severely limiting ourselves if we focused on English as the only
-  language.
-</p>
-
-<p>
-  "The App Translation Service offered in the Google Play Developer Console is
-  extremely easy to use and the pricing is very attractive. Developers with
-  limited localization experience can easily create, upload, and translate
-  their app."
-</p>
-
-
-<p>
-  RV AppStudios not only localizes the text within the game, but also localizes
-  the game assets to a specific country/culture. Dave says, “Users want a
-  personalized experience, and by offering a localized game with translation of
-  text and graphic assets, we believe users will connect at a much deeper level
-  with the game.”
-</p>
-
-
-  <div style="margin-top:8px;float:left;margin-right:24px;">
-    <img src="{@docRoot}images/distribute/zombie-ragdoll-n5-land.jpg" style="width:470px;">
-  </div>
-
-
-    <div style="margin-top:128px;">
-      <p class="img-caption"><strong>Hindi version of Zombie Ragdoll</strong>:
-      Localized screenshots and videos in the app's Google Play listing go a
-      long way toward increasing the number of installs.</p>
-    </div>
-
-  </div>
-
-</div> <!-- END STORY -->
-
-<!-- START STORY -->
-
-<div style="margin-bottom:2em;padding-top:18px;clear:both;" id="sayhichat">
-
-<h3>SayHi Chat: Install growth and user engagement<br />
-  from professional translations</h3>
-
-  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
-            -moz-border-radius: 5px;
-            border-radius: 5px height:78px;
-            width: 78px;
-            float: left;
-            margin: 12px 20px 9px 20px;" src=
-            "https://lh5.ggpht.com/qiL6CF1Hktz618T3mbGrxvm_OoeheQ78FgG7zr90C2MCRiz4IDQsbKuHT4xQGiWEU8o=w124">
-
-  <div style="list-style: none;height:100%;
-  float: right;
-  border-top: 1px solid #9C0;
-  width: 220px;
-  margin: 4px 20px;padding: .5em;">
-
-    <h5>About the app</h5>
-
-    <ul>
-      <li><a href="https://play.google.com/store/apps/details?id=com.unearby.sayhi">SayHi Chat,
-      Love, Meet, Dating</a></li>
-      <li>A social app to help you find people nearby</li>
-    </ul>
-
-    <h5>Localization Results</h5>
-
-    <ul>
-      <li>120% growth in language installs for new languages added</li>
-      <li>~20% increase in revenue and ~50% increase in User Reviews in the new
-        languages</li>
-      </ul>
-
-    <div style="padding:.5em 0 0 1em;">
-      <a href="https://play.google.com/store/apps/details?id=com.unearby.sayhi">
-        <img alt="Android app on Google Play"
-         src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
-      </a>
-
-    </div>
-  </div>
-
-  <div style="line-height:1.4em;">
-
-<p>
-  The SayHi Chat app started out only in Japanese, Chinese and English. It soon
-  became one of the most popular apps in Japan, Hong Kong, and Taiwan. The
-  SayHi team realized it was time to launch in more languages, as the language
-  barrier was restricting how fast SayHi could grow globally. </p>
-
-  <p>Yan Shi, senior
-  developer at SayHi, says: "We checked Google Analytics for our DAU and user
-  growth numbers in each country, we also looked at total Android and iOS users
-  in those markets before finalizing our next set of languages.
-</p>
-
-  <div style="margin-top:8px;float:left;width:270px;">
-    <img src="{@docRoot}images/distribute/hichat-n5-port.jpg" style="width:240px;margin-right:48px;">
-  </div>
-
-<p>
-  SayHi used the App Translation Service to launch in 13 additional languages
-  in August 2013 and immediately saw 120% increase in install rates. In
-  addition, they are seeing their app ranked in Top 10 apps in countries like
-  Poland and Italy.
-</p>
-
-<p>Notably, they saw steady growth in Spain after replacing their previous
-  non-professional Spanish translation with a professional one produced through
-  the App Translation Service.</p>
-
-<p>
-  Yan Shi adds, “The App Translation Service is really easy to use and
-  the completion time for translation requests is very good.”
-</p>
-
-    <div style="width:600px;margin-top:98px;padding:0;">
-      <p class="img-caption"><strong>Arabic version of SayHi Chat</strong>:
-        User engagement increased significantly with
-        the localized version.</p>
-    </div>
-
-  </div>
-</div> <!-- END STORY -->
-
-
-<div style="margin-bottom:2em;clear:both;padding-top:18px;" id="g4a"><!-- START STORY -->
-
-<h3 style="line-spacing:1.25em;">G4A Indian Rummy: Benefitting from ease-of-use and<br /> fast turnaround time</h3>
-
-  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
-            -moz-border-radius: 5px;
-            border-radius: 5px height:78px;
-            width: 78px;
-            float: left;
-            margin: 12px 20px 9px 20px;" src=
-            "https://lh4.ggpht.com/IxSyQgO0LWzPRoLfCrER06-0kr6aMAa2azF7eNYB30EBZAGOLYJUZulknPockbTlDYU=w124">
-
-  <div style="list-style: none;height:100%;
-  float: right;
-  border-top: 1px solid #9C0;
-  width: 220px;
-  margin: 4px 20px;padding: .5em;">
-
-    <h5>About the app</h5>
-
-    <ul>
-      <li><a href="https://play.google.com/store/apps/details?id=org.games4all.android.games.indianrummy.prod">G4A Indian Rummy</a></li>
-      <li>A card game in which the players try to form sets and sequences of cards</li>
-    </ul>
-
-    <h5>Localization Results</h5>
-
-    <ul>
-      <li>Double the number of users in French and German languages</li>
-      <li>300% increase in user engagement with localized version</li>
-      </ul>
-
-    <div style="padding:.5em 0 0 1em;">
-      <a href="https://play.google.com/store/apps/details?id=com.rvappstudios.zombieragdoll">
-        <img alt="Android app on Google Play"
-         src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
-      </a>
-    </div>
-  </div>
-
-  <div style="line-height:1.4em;">
-
-<p>
-  Games4All (G4A) is the developer of Indian Rummy and a variety of games that
-  they distribute broadly to users around the world. After noticing that
-  certain apps had become especially popular in specific countries, they
-  decided to localize those apps. Initially they used a local agency to do
-  the translation and got great results &mdash; the number of users in
-  that language increased tremendously when they released the localized
-  version.
-</p>
-
-<p>
-  Building on that success, G4A expanded their localization goals but
-  found that translation quality varied across their vendors and costs limited the
-  language/game combinations they could try. That's when G4A decided to try the
-  App Translation Service.
-</p>
-
-<p>
-  Founder Pieter Olivier says, "When we heard that the App Translation
-  Service was available in the Developer Console, we jumped at the opportunity.
-  We've now been using the App Translation Service for several months and found
-  that the cost per translation is much lower than with local companies and the
-  process is much easier."
-</p>
-
-<p>So far, G4A has translated the game Indian Rummy into five languages through
-   the App Translation Service.</p>
-
-<p>
-  Olivier continues, "The first thing we did was convert all of our texts into
-  the strings.xml format. After that using the service was extremely easy and
-  straightforward. In contrast, our previous experiences with translation
-  agencies were much more difficult: files often required extensive conversion
-  operations to make them usable, and turnaround times varied wildly.
-</p>
-
-<p>
-  "With the App Translation Service, the turnaround time is usually measured in
-  days instead of weeks that we were used to with traditional translation
-  agencies."
-</p>
-
-  <div style="margin-top:14px;float:left;margin-right:24px;">
-    <img src="{@docRoot}images/distribute/indian-rummy-n4-land.jpg" style="width:470px;">
-  </div>
-
-    <div style="margin-top:158px;">
-      <p class="img-caption"><strong>Dutch
-      version of Indian Rummy</strong>: Making slight changes to games rules based on
-      local nuances was key to success of the game.</p>
-    </div>
-
-  </div>
-
-
-
-</div> <!-- END STORY -->
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/spotlight/tablets.jd b/docs/html/distribute/googleplay/spotlight/tablets.jd
deleted file mode 100644
index 7a98755..0000000
--- a/docs/html/distribute/googleplay/spotlight/tablets.jd
+++ /dev/null
@@ -1,367 +0,0 @@
-page.title=Developer Stories: The Opportunity of Android Tablets
-walkthru=0
-header.hide=0
-
-@jd:body
-
-
-<p>More and more, developers are investing in a full tablet experience
-for their apps and are seeing those investments pay off big. The increased
-screen area on tablets opens up a world of possibilities, allowing for more
-engagement with the user &mdash; which can mean an increase in usage as well as
-more monetization opportunities. And with the growing wave of Android tablets that
-continue to hit the market, it’s an important piece of any developer’s mobile
-offering. </p>
-
-<p>Here are some stories from developers who are seeing real results as they
-expand their offering to include Android tablets.</p>
-
-
-<div style="margin-bottom:2em;" id="rememberthemilk"><!-- START STORY -->
-
-<h3>Remember The Milk: Lifting installs with tablet design</h3>
-
-  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
-            -moz-border-radius: 5px;
-            border-radius: 5px height:78px;
-            width: 78px;
-            float: left;
-            margin: 12px 20px 9px 20px;" src=
-            "//lh3.ggpht.com/xmnal18taauP2mjQFEhr1PhcItQ_W32IRuaD86IoL2U_4E-mfeKiliKtkISgOuA6Ln9n=w124">
-          
-  <div style="list-style: none;height:100%;
-  float: right;
-  border-top: 1px solid #9C0;
-  width: 220px;
-  margin: 4px 20px;padding: .5em;">
-  
-
-    <h5>About the app</h5> 
-    
-    
-    <ul>
-      <li><a href="//play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">Remember The Milk</a></li>
-      <li>A feature-packed to-do list app; never forget the milk (or anything else) again</li>
-    </ul>
-
-    <h5>Tablet Results</h5> 
-
-    <ul>
-      <li>83% jump in tablet installs following update </li>
-      <li>Nexus 7 is most popular Android device for app </li>
-      <li>Single APK for phones and tablets</li>
-      </ul>
-    
-    <div style="padding:.5em 0 0 1em;">
-      <a href="//play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">
-        <img alt="Android app on Google Play"
-         src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
-      </a>
-      
-    </div>
-  </div>
-
-  <div style="line-height:1.4em;">
-    <p style="margin-top:0;margin-bottom:12px;">When the Android tablet guidelines
-      came out in 2012, the team at Remember The Milk had already been thinking about
-      a redesign for their <a href="//play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">feature-packed
-      to-do list app</a>. Omar Kilani, Co-founder of Remember The Milk, explains how
-      <a href="//blog.rememberthemilk.com/2013/04/the-all-new-remember-the-milk-for-android-and-tablets-too/">updating</a>
-      their app to meet the tablet guidelines lead to an 83% jump in tablet installs: </p>
-
-    <p>“We took this as an opportunity to think about how we were going to approach
-      Android tablets differently from a user experience perspective. The guidelines
-      were a helpful resource, and with the extra screen real estate tablets afford,
-      users have the opportunity to see all of their data in context and drill down
-      on more items. All of this is accomplished using a single APK on Play, even though
-      the phone and tablet versions each capture completely different use cases for us.”</p>
-
-    <p>“In the month after updating, we saw our tablet installs on Google Play jump 83%,
-      and the Nexus 7 is now the most popular Android device amongst our users. For us,
-      designing for tablets was an investment that has really paid off.”</p>
-
-    <p>The team also came out with a number of other goodies &mdash; including a new set of
-      widgets and richer notifications, and more ways to provide an immersive experience
-      for their users.</p>
-  </div>
-
-  <div style="clear:both;margin-top:30px;width:auto;">
-  
-    <img src="{@docRoot}images/distribute/rememberthemilk.png">
-
-    <div style="width:600px;margin-top:0px;padding:0 90px;">
-      <p class="image-caption"><span style="font-weight:500;">Tablet redesign led to lift
-      in installs</span>: Following the redesign of the Android app, in part to meet the tablet
-      design criteria, Remember The Milk saw an 83% increase in tablet installs.</p>
-    </div>
-
-  </div>
-
-</div> <!-- END STORY -->
-
-
-<div style="margin-bottom:2em;" id="mint"><!-- START STORY -->
-
-<h3>Mint: More screen real estate = more engagement</h3>
-
-  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
-            -moz-border-radius: 5px;
-            border-radius: 5px height:78px;
-            width: 78px;
-            float: left;
-            margin: 12px 20px 9px 20px;" src=
-            "https://lh5.ggpht.com/0xAIZJ1uE05b4RHNHgBBTIH6nRdPTY660T104xY7O2GbHXwab6YVmpU5yYg8yacfBg=w124">
-          
-  <div style="list-style: none;height:100%;
-  float: right;
-  border-top: 1px solid #9C0;
-  width: 220px;
-  margin: 4px 20px;padding: .5em;">
-  
-
-    <h5>About the app</h5> 
-    
-    
-    <ul>
- <li><a href="http://play.google.com/store/apps/details?id=com.mint">Mint.com Personal Finance</a> by Intuit Inc.</li>
-      <li>Financial management app targeting 7- to 10-inch tablets and phones</li>
-    </ul>
-
-    <h5>Tablet Results</h5> 
-
-    <ul>
-      <li>Able to offer richer UI features</li>
-      <li>Much higher user engagement</li>
-      <li>Longer sessions &mdash; more Android tablet users have sessions longer than 5 minutes</li>
-      </ul>
-    
-    <div style="padding:.5em 0 0 1em;">
-<a href="http://play.google.com/store/apps/details?id=com.mint">
-  <img alt="Android app on Google Play"
-       src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
-</a>
-      
-    </div>
-  </div>
-
-  <div style="line-height:1.4em;">
-    <p style="margin-top:0;margin-bottom:12px;">When Intuit was thinking about
-expanding their Mint mobile offering to include a version optimized for Android
-tablets, they knew that taking the layout that worked for phones and simply
-showing an enlarged version wouldn’t take full advantage of the opportunities
-that tablets afford.</p>
-    
-    <p>“We knew we had a lot more real estate, and we wanted to provide a more
-immersive experience for our users” said Ken Sun, Intuit Group Product Manager
-at Mint.</p>
-
-<p>Intuit’s Mint app, which has a 4-star rating on Google Play, brings a number
-of features to Android tablets that aren’t available for phones, including a
-more visual presentation of personal financial data.</p>
-
-<p>“Whereas our app for phones is used throughout the day for quick sessions,
-we’ve seen a larger percentage of our tablet usage happen in the evening, for
-much longer sessions,” said Sun. “People are doing a lot more than just checking
-their spending. They’re looking at historical trends, re-categorizing
-transactions, analyzing the data and setting financial goals for the future
-&mdash; digging much deeper and being more thoughtful. One example is how much
-users are interacting with their own budgets in the tablet app.  Customer budget
-operations (view, edit, drill-down, etc.) are 7x higher on Android tablets than
-they are on phones.”</p>
-
-<p>Fifty percent more Android tablet users have Mint sessions of 5 minutes or
-longer than they do on phones.  “We’ve found that phone usage is indicative of a
-customer’s regular financial check-in, while tablet usage points towards more
-analysis and interaction with that customer’s personal financial data.  This is
-the sort of immersive engagement experience we were looking for; the tablet and
-phone apps serve as great complements to each other."</p>
-  </div>
-
-  <div style="clear:both;margin-top:40px;width:auto;">
-  
-    <img src="{@docRoot}images/distribute/mint.png">
-
-    <div style="width:600px;margin-top:0px;padding:0 90px;">
-      <p class="image-caption"><span style="font-weight:500;">Making the most of tablet screens</span>: Mint used the extra screen area on tablets to offer quick access to additional tools and information.</p>
-    </div>
-
-  </div>
-
-</div> <!-- END STORY -->
-
-
-<div style="margin:3em auto"><!-- START STORY -->
-
-
-<h3>TinyCo: Monetization opportunities abound on tablets</h3>
-
-  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
-            -moz-border-radius: 5px;
-            border-radius: 5px height:78px;
-            width: 78px;
-            float: left;
-            margin: 12px 20px 30px 20px;" src=
-            "https://lh6.ggpht.com/QTy7lOGRTS58NW4XEeym2sxpWKDmRNod_n3kBrHlqTRIyzIv2gkw8DfwiR4GIAdxiHw=w124">
-
-          
-  <div style="list-style: none;height:100%;
-  float: right;
-  border-top: 1px solid #9C0;
-  width: 220px;
-  margin: 4px 20px;padding: .5em;">
-
-    <h5>About the app</h5> 
-
-    <ul>
-                <li><a href="http://play.google.com/store/apps/details?id=com.tinyco.village">Tiny Village</a> by TinyCo</li>
-            <li>Game targeting 7- to 10-inch tablets and phones</li>
-    </ul>
-
-    <h5>Tablet Results</h5> 
-
-    <ul>
-      <li>35% higher average revenue per paying user (ARPPU)</li>
-      <li>Consistent increase in user retention</li>
-      <li>3x increase in downloads to Android tablets in the last 6 months</li>
-    </ul>
-    
-    <div style="padding:.5em 0 0 1em;">
-<a href="http://play.google.com/store/apps/details?id=com.tinyco.village">
-  <img alt="Android app on Google Play"
-       src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
-</a>
-      
-    </div>
-  </div>
-
-  <div style="line-height:1.4em;">
-    <p style="margin-top:0;margin-bottom:12px;">
-    
-<p>Over a year ago, app developer TinyCo, makers of a suite of games such as
-Tiny Monsters, decided to prioritize launching across multiple platforms
-effectively. They chose Android as one of their primary launch platforms because
-of its large installed base and global reach. They also knew that the growing
-base of Android tablet users represented a huge opportunity.</p>
-    
-    <p>Tiny Village was their first title to take advantage of the strategy, and
-it proved to be a winning one &mdash; especially in terms of Android
-tablets.</p>
-    
-    <p> “With continued optimization of the gameplay experience and a genuine
-commitment to our Android offering through our Griffin engine, all of our
-metrics started to rise,” said Rajeev Nagpal, Head of Product at TinyCo. In
-fact, they’ve seen Android tablet downloads more than triple in the last six
-months.</p>
-
-    <p>One of the first things they noticed about usage of Tiny Village on
-tablets was an increase in average revenue per paying user (ARPPU)&mdash;about 35%
-higher than on smaller-screen devices such as phones. Additionally, average
-revenue per user ARPU is now about 35% higher as well. “The game is just much
-more immersive on tablet.”</p>
-
-    <p>In addition to an increase in monetization metrics, they’ve also seen a
-consistent increase in retention over other platforms. “These are really
-important metrics for games &mdash; if you can get users to both stay around
-longer and spend more while they’re there, you have a recipe for success.”</p>
-  </div>
-
-  <div style="clear:both;margin-top:40px;width:auto;">
-  
-    <img src="{@docRoot}images/distribute/tinyvillage.png">
-
-    <div style="width:600px;margin-top:0px;padding:0 90px;">
-      <p class="image-caption"><span style="font-weight:500;">More monetization
-on tablets</span>: On Android tablets TinyCo has seen higher ARPPU and user
-retention than on phones.</p>
-    </div>
-
-  </div>
-
-</div> <!-- END STORY -->
-
-
-<div style="margin-bottom:2em;"><!-- START STORY -->
-
-<h3>Instapaper: Riding the growing wave of Android tablets</h3>
-
-
-  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
-            -moz-border-radius: 5px;
-            border-radius: 5px height:78px;
-            width: 78px;
-            float: left;
-            margin: 12px 20px 9px 20px;" src=
-            "https://lh3.ggpht.com/30KKcrIFO8V_wRfhnHaI9l0CLH_orIVFE7Xywtr9TBxAf0hi2BaZkKyBOs63Yfavpg=w124">
-
-          
-  <div style="list-style: none;height:100%;
-  float: right;
-  border-top: 1px solid #9C0;
-  width: 220px;
-  margin: 4px 20px;padding: .5em;">
-  
-  
-  
-
-    <h5>About the app</h5> 
-    <ul>
-                <li><a href="http://play.google.com/store/apps/details?id=com.instapaper.android">Instapaper</a> by Mobelux</li>
-      <li>Content-browsing utility that targets 7- to 10-inch tablets and phones</li>
-    </ul>
-
-    <h5>Tablet Results</h5> 
-
-    <ul>
-      <li>Tablets are now 50% of the app's installed base.</li>
-    </ul>
-    
-    <div style="padding:.5em 0 0 1em;">
-<a href="http://play.google.com/store/apps/details?id=com.instapaper.android">
-  <img alt="Android app on Google Play"
-       src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
-</a>
-      
-    </div>
-  </div>
-
-  <div style="line-height:1.4em;">
-    <p style="margin-top:0;margin-bottom:12px;">Instapaper for Android is an app
-for saving web content to read later. Developer Mobelux decided that creating a
-great UI for Android tablet users would be an essential part of their initial launch
-plan.</p>
-    
-    <p>The app launched at the beginning of the summer of 2012, just in time to
-take advantage of a new tide of Android tablets, including the <span
-style="white-space:nowrap;">Nexus 7</span> tablet. The app has since seen huge
-popularity among tablet users, in particular, on Nexus 7. On the day that
-pre-orders of Nexus 7 began arriving, Mobelux saw a 600% jump in downloads of
-its app on Google Play.</p>
-
-    <p>“We saw a promising new set of Android tablets about to hit the market
-and wanted to position ourselves to be ready for them” said Jeff Rock of
-Mobelux. “It was a market that others were hesitant to explore, but the decision
-to prioritize tablets has paid off very well for us.”</p>
-
-    <p>Since that initial 600% jump in downloads, Instapaper for Android has
-continued to see a successful run on Android tablets. In fact, Android tablets
-now represent about 50% of their installed base. “With more and more Android
-tablets coming online, we’re excited to see how our investment in Android
-tablets continues to pay off.”</p>
-  </div>
-
-  <div style="clear:both;margin-top:40px;width:auto;">
-  
-    <img src="{@docRoot}images/distribute/instapaper.png">
-
-    <div style="width:600px;margin-top:0px;padding:0 90px;">
-      <p class="image-caption"><span style="font-weight:500;">Popular with
-tablet users</span>: A great tablet UI and browsing convenience make Instapaper
-popular with Android tablet users.</p>
-    </div>
-
-  </div>
-
-</div> <!-- END STORY -->
-
-
-
diff --git a/docs/html/distribute/googleplay/start.jd b/docs/html/distribute/googleplay/start.jd
new file mode 100644
index 0000000..6dc397b
--- /dev/null
+++ b/docs/html/distribute/googleplay/start.jd
@@ -0,0 +1,163 @@
+page.title=Get Started with Publishing
+page.metaDescription=Start publishing on Google Play in minutes by registering for a developer account.
+meta.tags="publishing"
+page.tags="google play", "publishing", "register", "signup"
+page.image=/distribute/images/getting-started.jpg
+
+@jd:body
+
+<div class="top-right-float" style="margin-right:24px;margin-top:-18px">
+  <a href="https://play.google.com/apps/publish/"><img src=
+  "{@docRoot}images/gp-start-button.png"></a>
+</div>
+
+<p>
+  Start publishing on Google Play in minutes by:
+</p>
+
+<ul>
+  <li>Registering for a Google Play publisher account
+  </li>
+
+  <li>Setting up a Google Wallet Merchant Account, if you will sell apps or
+  in-app products.
+  </li>
+
+  <li>Exploring the <a href="https://play.google.com/apps/publish/">Google Play
+  Developer Console</a> and publishing tools.
+  </li>
+</ul>
+
+<p>
+  When you're ready, use the Start button to go to the Developer Console.
+</p>
+
+<div class="headerLine">
+  <h1>
+    Register for a Publisher Account
+  </h1>
+
+  <hr>
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <h2>
+      Tips
+    </h2>
+
+    <ul>
+      <li>You need a Google account to register. You can create one during the
+      process.
+      </li>
+
+      <li>If you are an organization, consider registering a new Google account
+      rather than using a personal account.
+      </li>
+
+      <li>Review the <a href=
+      "https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138294">
+        developer countries</a> and <a href=
+        "https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=150324">
+        merchant countries</a> where you can distribute and sell apps.
+      </li>
+    </ul>
+  </div>
+</div>
+
+<ol>
+  <li>Visit the <a href="https://play.google.com/apps/publish/">Google Play
+  Developer Console</a>.
+  </li>
+
+  <li>Enter basic information about your <strong>developer identity</strong>
+  &mdash; name, email address, and so on. You can modify this information
+  later.
+  </li>
+
+  <li>Read and accept the <strong>Developer Distribution Agreement</strong> for
+  your country or region. Note that apps and store listings that you publish on
+  Google Play must comply with the Developer Program Policies and US export
+  law.
+  </li>
+
+  <li>Pay a <strong>$25 USD registration fee</strong> using Google Wallet. If
+  you don't have a Google Wallet account, you can quickly set one up during the
+  process.
+  </li>
+
+  <li>When your registration is verified, you’ll be notified at the email
+  address you entered during registration.
+  </li>
+</ol>
+
+<div class="headerLine">
+  <h1 id="merchant-account">
+    Set Up a Google Wallet Merchant Account
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure" style="width:200px;">
+  <img src="{@docRoot}images/gp-start-wallet-icon.png">
+</div>
+
+<p>
+  If you want to sell priced apps, in-app products, or subscriptions, you’ll
+  need a Google Wallet Merchant Account. You can set one up at any time, but
+  first review the list of <a href=
+  "https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=150324">
+  merchant countries</a>.<br>
+  <br>
+  To set up a Google Wallet Merchant Account:<br>
+  <br>
+</p>
+
+<ol>
+  <li>
+    <strong>Sign in</strong> to your Google Play Developer Console at <a href=
+    "https://play.google.com/apps/publish/" target=
+    "_blank">https://play.google.com/apps/publish/</a>.
+  </li>
+
+  <li>Open <strong>Financial reports</strong> <img src=
+  "{@docRoot}images/distribute/console-reports.png"> on the side navigation.
+  </li>
+
+  <li>Click <strong>Setup a Merchant Account now</strong>.
+  </li>
+</ol>
+
+<p>
+  This takes you to the Google Wallet site; you'll need information about your
+  business to complete this step.
+</p>
+
+<div class="headerLine">
+  <h1>
+    Explore the Developer Console
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  When your registration is verified, you can sign in to your Developer
+  Console, which is the home for your app publishing operations and tools on
+  Google Play.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-dc-home.png" class="border-img">
+</div>
+
+<div class="headerLine">
+<h1 id="related-resources">Related Resources</h1><hr />
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/googleplay/gettingstarted"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
diff --git a/docs/html/distribute/googleplay/strategies/app-quality.jd b/docs/html/distribute/googleplay/strategies/app-quality.jd
deleted file mode 100644
index eb2cd2b..0000000
--- a/docs/html/distribute/googleplay/strategies/app-quality.jd
+++ /dev/null
@@ -1,121 +0,0 @@
-page.title=Improving App Quality After Launch
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>Strategies</h2>
-<ol>
-<li><a href="#listen">Listen to Your Users</a></li>
-<li><a href="#stability">Improve Stability and Eliminate Bugs</a></li>
-<li><a href="#responsiveness">Improve UI Responsiveness</a></li>
-<li><a href="#usability">Improve Usability</a></li>
-<li><a href="#appearance">Professional Appearance and Aesthetics</a></li>
-<li><a href="#features">Deliver the Right Set of Features</a></li>
-<li><a href="#integrate">Integrate with the System and Third-Party Apps</a></li>
-<li><a href="#details">Pay Attention to Details</a></li>
-</ol>
-
-<h2>You Should Also Read</h2>
-<ol>
-<li><a href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality Guidelines</a></li>
-<li><a href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality Checklist</a></li>
-</ol>
-
-</div>
-</div>
-
-<p>
-With thousands of new apps being published in Google Play every week, it's important to look for any available way to get the most visibility and the highest ratings possible.  One way of improving your app's visibility in the ecosystem is by deploying well-targeted mobile advertising campaigns and cross-app promotions. Another time-tested method of fueling the impression-install-ranking cycle is simply: <em>improve the product</em>!</p>
-<p>
-A better app can go a very long way: a higher quality app will translate to higher user ratings, generally better rankings, more downloads, and higher retention (longer install periods). High-quality apps also have a much higher likelihood of getting some unanticipated positive publicity such as being featured in Google Play or getting social media buzz.</p>
-<p>
-The upside to having a higher-quality app is obvious. However, it's not always clear how to make an app "better".  This document looks at some of the key factors in app quality and ways of improving your app over time, after you've launched the app.</p>
-
-<h2 id="listen">Listen to Your Users</h2>
-<p>
-Most ways of measuring the "success" of an app are dependent on user behavior. User-related metrics such as number of downloads, daily active installs, retention rates, and so on highlight the importance of users. If you aren't doing so already, it's a good idea to start thinking of your app's quality as it relates to your users.</p>
-<p>
-The most obvious way to listen to users is by reading and addressing comments on your app in Google Play. Although the comments aren't always productive or constructive, some will provide valuable insight on aspects of your app that you may not have consciously considered before. It's important to remember that users have the opportunity to change their ratings and comments about an app as much as they'd like.</p>
-<p>
-One way to reach users and help them address their concerns is to set up your own support and discussion destination(s). There are some great support tools out there that can put you in touch with your users directly, from forums such as <a href="http://groups.google.com">Google Groups</a> to comprehensive customer support products and destinations. Once you get set up with such a tool, make sure to fill in the support link in your Google Play product details page &mdash; users do click through to these.</p>
-<p>
-Another way to better listen to your users is by having a public beta or trusted tester program. It's crucial to have some amount of real user testing before releasing something in Google Play. Fortunately, you can distribute your apps to users outside of Google Play via a website; this website can require a login or be publicly accessible&nbsp;&mdash;&nbsp;it's entirely up to you. Take advantage of this opportunity by offering your next planned update to some early adopters, before submitting to Google Play. You'll be surprised by how many little, yet impactful, improvements can come out of crowd-sourced, real-user testing.</p>
-
-
-<h2 id="stability">Improve Stability and Eliminate Bugs</h2>
-
-<p>
-The effect of overall app stability of ratings and user satisfaction is very well-known and there are many tools and techniques for testing and profiling your app on different devices and user scenarios.</p>
-<p>
-One noteworthy and yet relatively underused tool for catching stability issues such as crashes is the <a href="{@docRoot}tools/help/monkey.html">UI/Application Exerciser Monkey</a> (Monkey). Monkey will send random UI events to your app's activities, allowing you to trigger user flows that can uncover stability problems.</p>
-<p>
-Also, with the Google error-reporting features built into most Android devices, users now have a way to report application crashes to developers. The error reports show up in aggregate in the Google Play Developer Console. Make sure to read these reports often and act on them appropriately.</p>
-<p>
-Last, keep an external bug and feature request tracker and let users know how to find it. This will enable them to engage with the app at a closer level, by following features and bugs that affect them. User frustration with app problems can be effectively managed with diligent issue tracking and communication. Some of the community support tools listed above offer issue tracking features, and if your project is open source, most popular repository hosting sites will offer this as well.</p>
-
-<h2 id="responsiveness">Improve UI Responsiveness</h2>
-<p>
-One sure-fire way to lose your users is to give them a slow, unresponsive UI. Research has shown that <a href="http://googleresearch.blogspot.com/2009/06/speed-matters.html">speed matters</a>... for any interface, be it desktop, web, or mobile. In fact, the importance of speed is amplified on mobile devices since users often need their information on the go and in a hurry.</p>
-<p>
-You can improve your apps's UI responsiveness by moving long-running operations off the main thread to worker threads. Android offers built-in debugging facilities such as StrictMode for analyzing your app's performance and activities on the main thread. You can see more recommendations in <a href="http://www.youtube.com/watch?v=c4znvD-7VDA">Writing Zippy Android Apps</a>, a developer session from Google I/O 2010,</p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h3>More resources</h3>
-<ul>
-<li><a href="{@docRoot}design/index.html">Android Design</a></li>
-<li><a href="{@docRoot}guide/practices/performance.html">Designing for Performance</a></li>
-<li><a href="{@docRoot}guide/practices/responsiveness.html">Designing for Responsiveness</a>
-<li><a href="{@docRoot}guide/practices/seamlessness.html">Designing for Seamlessness</a>
-</li>
-</ul>
-</div></div>
-<p>
-A great way to improve UI performance is to minimize the complexity of your layouts. If you open up <a href="{@docRoot}tools/help/hierarchy-viewer.html">hierarchyviewer</a> and see that your layouts are more than 5 levels deep, it may be time to simplify your layout. Consider refactoring those deeply nested LinearLayouts into RelativeLayout. The impact of View objects is cumulative &mdash; each one costs about 1 to 2 KB of memory, so large view hierarchies can be a recipe for disaster, causing frequent VM garbage collection passes which block the main (UI) thread. You can learn more in <a href="http://www.youtube.com/watch?v=wDBM6wVEO70">World of ListView</a>, another session at Google I/O.</p>
-<p>
-Lastly, pointed out in the blog post <a href="http://android-developers.blogspot.com/2010/10/traceview-war-story.html">Traceview War Story</a>, tools like <a href="{@docRoot}tools/help/traceview.html">traceview</code> and <a href="{@docRoot}tools/help/ddms.html">ddms</a> can be your best friends in improving your app by profiling method calls and monitoring VM memory allocations, respectively.</p>
-
-
-<h2 id="usability">Improve Usability</h2>
-<p>
-In usability and in app design too, you should listen carefully to your users. Ask a handful of real Android device users (friends, family, etc.) to try out your app and observe them as they interact with it. Look for cases where they get confused, are unsure of how to proceed, or are surprised by certain behaviors. Minimize these cases by rethinking some of the interactions in your app, perhaps working in some of the <a href="http://www.youtube.com/watch?v=M1ZBjlCRfz0">user interface patterns</a> the Android UI team discussed at Google I/O.</p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<p>
-As you are designing or evaluating your app's UI, make sure to read and become familiar with the <a href="/design/index.html">Android Design</a> guidelines. Included are many examples of UI patterns, styles, and building blocks, as well as tools for the design process.</p>
-</div></div>
-
-<p>
-In the same vein, two problems that can plague some Android user interfaces are small tap targets and excessively small font sizes. These are generally easy to fix and can make a big impact on usability and user satisfaction. As a general rule, optimize for ease of use and legibility, while minimizing, or at least carefully balancing, information density.</p>
-
-<p>
-Another way to incrementally improve usability, based on real-world data, is to implement <a href="http://code.google.com/mobile/analytics/docs/">Analytics</a> throughout your app to log usage of particular sections. Consider demoting infrequently used sections to the overflow menu in the <a href="{@docRoot}design/patterns/actionbar.html">Action bar</a>, or removing them altogether. For often-used sections and UI elements, make sure they're immediately obvious and easily accessible in your app's UI so that users can get to them quickly.</p>
-<p>
-Lastly, usability is an extensive and well-documented subject, with close ties to interface design, cognitive science, and other disciplines.</p>
-
-<h2 id="appearance">Professional Appearance and Aesthetics</h2>
-<p>
-There's no substitute for a real user interface designer&nbsp;&mdash;&nbsp;ideally one who's well-versed in mobile and Android, and ideally handy with both interaction and visual design. One popular venue to post openings for designers is <a href="http://jobs.smashingmagazine.com">jobs.smashingmagazine.com</a>, and leveraging social networks can also surface great talent.</p>
-<p>
-If you don't have the luxury of working with a UI designer, there are some ways in which you can improve your app's appearance yourself. First, get familiar with Adobe Photoshop, Adobe Fireworks, or some other raster image editing tool. Mastering the art of the pixel in these apps takes time, but honing this skill can help build polish across your interface designs. Also, master the resources framework by studying the framework UI assets and layouts and reading through the <a href="{@docRoot}guide/topics/resources/index.html">resources documentation</a>. Techniques such as 9-patches and resource directory qualifiers are somewhat unique to Android, and are crucial in building flexible yet aesthetic UIs.</p>
-<p>
-Before you get too far in designing your app and writing the code, make sure to visit the Android Design site and learn about the vision, the building blocks, and the tools of designing beautiful and inspiring user interfaces.</p>
-
-<h2 id="features">Deliver the Right Set of Features</h2>
-<p>
-Having the <em>right</em> set of features in your app is important. It's often easy to fall into the trap of feature-creep, building as much functionality into your app as possible. Providing instant gratification by immediately showing the most important or relevant information is crucial on mobile devices. Providing too much information can be as frustrating (or even more so) than not providing enough of it.</p>
-<p>
-Again, listen to your users by collecting and responding to feature requests. Be careful, though, to take feature requests with a grain of salt. Requests can be very useful in aggregate, to get a sense of what kinds of functionality you should be working on, but not every feature request needs to be implemented.</p>
-
-<h2 id="integrate">Integrate with the System and Third-Party apps</h2>
-<p>
-A great way to deliver a delightful user experience is to integrate tightly with the operating system. Features like <a href="{@docRoot}guide/topics/appwidgets/index.html">Home screen widgets</a>, <a href="{@docRoot}design/patterns/notifications.html">rich notifications</a>, <a href="{@docRoot}guide/topics/search/index.html">global search integration</a>, and {@link android.widget.QuickContactBadge Quick Contacts} are fairly low-hanging fruit in this regard. </p>
-
-<p>For some app categories, basic features like home screen widgets are par for the course. Not including them is a sure-fire way to tarnish an otherwise positive user experience. Some apps can achieve even tighter OS integration with Android's contacts, accounts, and sync APIs. </p>
-<p>
-Third-party integrations can provide even more user delight and give the user a feeling of device cohesiveness. It's also a really nice way of adding functionality to your app without writing any extra code (by leveraging other apps' functionalities). For example, if you're creating a camera app, you can allow users to edit their photos in another app before saving them to their collection, if they have that third-party application installed. More information on this subject is available in the Android Training class <a href="{@docRoot}training/basics/intents/index.html">Interacting with Other Apps</a>.</p>
-
-<h2 id="details">Pay Attention to Details</h2>
-<p>
-One particular detail to pay close attention to is your app's icon quality and consistency. Make sure your app icons (especially your launcher icon) are crisp and pixel-perfect at all resolutions, and follow the <a href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">icon guidelines</a> as much as possible. If you're having trouble or don't have the resources to design the icons yourself, consider using the <a href="http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html">Android Asset Studio</a> tool to generate a set.</p>
diff --git a/docs/html/distribute/googleplay/strategies/featuring.jd b/docs/html/distribute/googleplay/strategies/featuring.jd
deleted file mode 100644
index 4c4e67e..0000000
--- a/docs/html/distribute/googleplay/strategies/featuring.jd
+++ /dev/null
@@ -1,4 +0,0 @@
-page.title=Preparing for Featuring
-@jd:body
-
-<p>Placeholder...</p>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/strategies/index.jd b/docs/html/distribute/googleplay/strategies/index.jd
deleted file mode 100644
index 3794bbf..0000000
--- a/docs/html/distribute/googleplay/strategies/index.jd
+++ /dev/null
@@ -1,33 +0,0 @@
-page.title=Success Strategies
-page.metaDescription=
-header.hide=1
-footer.hide=1
-
-@jd:body
-
-
-
-<style>
-#landing-graphic-container {
-  position: relative;
-}
-
-#text-overlay {
-  position: absolute;
-  left: 0;
-  top: 472px;
-  width: 280px;
-}
-</style>
-
-<div id="landing-graphic-container">
-  <div id="text-overlay">
-   Strategies for building ratings, improving reviews, monetizing, and more.  
-    <br><br>
-    <a href="/distribute/googleplay/promote/product-pages.html" class="landing-page-link">Preparing for Featuring</a>
-  </div>
-
-  <a href="{@docRoot}distribute/googleplay/promote/index.html">
-    <img src="{@docRoot}design/media/index_landing_page.png">
-  </a>
-</div>
\ No newline at end of file
diff --git a/docs/html/distribute/images/about-play-education.jpg b/docs/html/distribute/images/about-play-education.jpg
new file mode 100644
index 0000000..1fe6b2c
--- /dev/null
+++ b/docs/html/distribute/images/about-play-education.jpg
Binary files differ
diff --git a/docs/html/distribute/images/about-play.jpg b/docs/html/distribute/images/about-play.jpg
new file mode 100644
index 0000000..e62cb58
--- /dev/null
+++ b/docs/html/distribute/images/about-play.jpg
Binary files differ
diff --git a/docs/html/distribute/images/advertising.jpg b/docs/html/distribute/images/advertising.jpg
new file mode 100644
index 0000000..9625671
--- /dev/null
+++ b/docs/html/distribute/images/advertising.jpg
Binary files differ
diff --git a/docs/html/distribute/images/advertising.png b/docs/html/distribute/images/advertising.png
new file mode 100644
index 0000000..5dc0ed4
--- /dev/null
+++ b/docs/html/distribute/images/advertising.png
Binary files differ
diff --git a/docs/html/distribute/images/alt-distribution.jpg b/docs/html/distribute/images/alt-distribution.jpg
new file mode 100644
index 0000000..39c0514
--- /dev/null
+++ b/docs/html/distribute/images/alt-distribution.jpg
Binary files differ
diff --git a/docs/html/distribute/images/android-support-card.jpg b/docs/html/distribute/images/android-support-card.jpg
new file mode 100644
index 0000000..b1883c0
--- /dev/null
+++ b/docs/html/distribute/images/android-support-card.jpg
Binary files differ
diff --git a/docs/html/distribute/images/build-buzz.jpg b/docs/html/distribute/images/build-buzz.jpg
new file mode 100644
index 0000000..3f83a1a
--- /dev/null
+++ b/docs/html/distribute/images/build-buzz.jpg
Binary files differ
diff --git a/docs/html/distribute/images/core-quality-guidelines.jpg b/docs/html/distribute/images/core-quality-guidelines.jpg
new file mode 100644
index 0000000..d0c2479
--- /dev/null
+++ b/docs/html/distribute/images/core-quality-guidelines.jpg
Binary files differ
diff --git a/docs/html/distribute/images/create-listing.jpg b/docs/html/distribute/images/create-listing.jpg
new file mode 100644
index 0000000..befb936
--- /dev/null
+++ b/docs/html/distribute/images/create-listing.jpg
Binary files differ
diff --git a/docs/html/distribute/images/default.jpg b/docs/html/distribute/images/default.jpg
new file mode 100644
index 0000000..8050744
--- /dev/null
+++ b/docs/html/distribute/images/default.jpg
Binary files differ
diff --git a/docs/html/distribute/images/developer-console.jpg b/docs/html/distribute/images/developer-console.jpg
new file mode 100644
index 0000000..09f4a86
--- /dev/null
+++ b/docs/html/distribute/images/developer-console.jpg
Binary files differ
diff --git a/docs/html/distribute/images/ecommerce.jpg b/docs/html/distribute/images/ecommerce.jpg
new file mode 100644
index 0000000..0b2efdc
--- /dev/null
+++ b/docs/html/distribute/images/ecommerce.jpg
Binary files differ
diff --git a/docs/html/distribute/images/edu-guidelines.jpg b/docs/html/distribute/images/edu-guidelines.jpg
new file mode 100644
index 0000000..280dcfee
--- /dev/null
+++ b/docs/html/distribute/images/edu-guidelines.jpg
Binary files differ
diff --git a/docs/html/distribute/images/expand-into-new-markets.jpg b/docs/html/distribute/images/expand-into-new-markets.jpg
new file mode 100644
index 0000000..0f17f13
--- /dev/null
+++ b/docs/html/distribute/images/expand-into-new-markets.jpg
Binary files differ
diff --git a/docs/html/distribute/images/freemium.jpg b/docs/html/distribute/images/freemium.jpg
new file mode 100644
index 0000000..6919202
--- /dev/null
+++ b/docs/html/distribute/images/freemium.jpg
Binary files differ
diff --git a/docs/html/distribute/images/getting-started.jpg b/docs/html/distribute/images/getting-started.jpg
new file mode 100644
index 0000000..47f524a
--- /dev/null
+++ b/docs/html/distribute/images/getting-started.jpg
Binary files differ
diff --git a/docs/html/distribute/images/gp-app-practices.png b/docs/html/distribute/images/gp-app-practices.png
new file mode 100644
index 0000000..0afc4cb
--- /dev/null
+++ b/docs/html/distribute/images/gp-app-practices.png
Binary files differ
diff --git a/docs/html/distribute/images/gp-edu-apps-image.jpg b/docs/html/distribute/images/gp-edu-apps-image.jpg
new file mode 100644
index 0000000..8785db1
--- /dev/null
+++ b/docs/html/distribute/images/gp-edu-apps-image.jpg
Binary files differ
diff --git a/docs/html/distribute/images/gp-games-practices.png b/docs/html/distribute/images/gp-games-practices.png
new file mode 100644
index 0000000..e2b63c5
--- /dev/null
+++ b/docs/html/distribute/images/gp-games-practices.png
Binary files differ
diff --git a/docs/html/distribute/images/gp-optimize-card.jpg b/docs/html/distribute/images/gp-optimize-card.jpg
new file mode 100644
index 0000000..4c91f1c
--- /dev/null
+++ b/docs/html/distribute/images/gp-optimize-card.jpg
Binary files differ
diff --git a/docs/html/distribute/images/gpfe-faq.jpg b/docs/html/distribute/images/gpfe-faq.jpg
new file mode 100644
index 0000000..cf10a95
--- /dev/null
+++ b/docs/html/distribute/images/gpfe-faq.jpg
Binary files differ
diff --git a/docs/html/distribute/images/know-your-user.jpg b/docs/html/distribute/images/know-your-user.jpg
new file mode 100644
index 0000000..9336125
--- /dev/null
+++ b/docs/html/distribute/images/know-your-user.jpg
Binary files differ
diff --git a/docs/html/distribute/images/launch-checklist.jpg b/docs/html/distribute/images/launch-checklist.jpg
new file mode 100644
index 0000000..c571c9e
--- /dev/null
+++ b/docs/html/distribute/images/launch-checklist.jpg
Binary files differ
diff --git a/docs/html/distribute/images/localization-checklist.jpg b/docs/html/distribute/images/localization-checklist.jpg
new file mode 100644
index 0000000..26765fe
--- /dev/null
+++ b/docs/html/distribute/images/localization-checklist.jpg
Binary files differ
diff --git a/docs/html/distribute/images/payment-method.jpg b/docs/html/distribute/images/payment-method.jpg
new file mode 100644
index 0000000..a9f8b19
--- /dev/null
+++ b/docs/html/distribute/images/payment-method.jpg
Binary files differ
diff --git a/docs/html/distribute/images/play-education.jpg b/docs/html/distribute/images/play-education.jpg
new file mode 100644
index 0000000..8780993
--- /dev/null
+++ b/docs/html/distribute/images/play-education.jpg
Binary files differ
diff --git a/docs/html/distribute/images/premium.jpg b/docs/html/distribute/images/premium.jpg
new file mode 100644
index 0000000..210fddb
--- /dev/null
+++ b/docs/html/distribute/images/premium.jpg
Binary files differ
diff --git a/docs/html/distribute/images/subscription.jpg b/docs/html/distribute/images/subscription.jpg
new file mode 100644
index 0000000..9b6f112
--- /dev/null
+++ b/docs/html/distribute/images/subscription.jpg
Binary files differ
diff --git a/docs/html/distribute/images/tablet-guidelines-color.jpg b/docs/html/distribute/images/tablet-guidelines-color.jpg
new file mode 100644
index 0000000..ffb1a03
--- /dev/null
+++ b/docs/html/distribute/images/tablet-guidelines-color.jpg
Binary files differ
diff --git a/docs/html/distribute/images/tablet-guidelines.jpg b/docs/html/distribute/images/tablet-guidelines.jpg
new file mode 100644
index 0000000..b16b48c
--- /dev/null
+++ b/docs/html/distribute/images/tablet-guidelines.jpg
Binary files differ
diff --git a/docs/html/distribute/index.jd b/docs/html/distribute/index.jd
index 6c6e113..da960ce 100644
--- a/docs/html/distribute/index.jd
+++ b/docs/html/distribute/index.jd
@@ -1,38 +1,21 @@
-page.title=Distribute Apps
+page.title=Distribute Your Apps
 page.viewport_width=970
+section.landing=true
 header.hide=1
+nonavpage=true
+page.metaDescription=The most visited store in the world for Android apps. Cloud-connected and always synced, it's never been easier for users to find and download your apps.
 
 @jd:body
-    
-    
-<div class="marquee">
-  <div class="madin-img" style="position:absolute;margin-left:42px;margin-top:76px;">
-    <img src="{@docRoot}images/home/google-play.png">
-  </div>
-  <div class="copy" style="position:relative;left:480px;width:360;">
-    <h1 style="margin-bottom:10px;">Your Apps on Google Play</h1>
-    <p>The most visited store in the world for Android apps.  Cloud-connected and always synced,
-    it's never been easier for users to find and download your apps.</p>
-    <p><a class="button" href="https://play.google.com/apps/publish/"
-      >Go to Developer Console &raquo;</a></p>
-  </div>
-</div>
 
-<div class="distribute-features col-13" style="clear:both;margin-top:246px;">
-  <ul>
-    <li><h5>Growth Engine</h5>
-    A billion downloads a month and growing. Get your apps in front of millions of users at Google's scale.<br />
-    <a href="{@docRoot}distribute/googleplay/about/visibility.html">Read More ›</a>
-    <li><h5>Build Your Business</h5> Sell your app in over 130 countries.  Flexible monetization options with in-app purchase, subscriptions, and more. <br />
-    <a href="{@docRoot}distribute/googleplay/about/monetizing.html">Read More ›</a></li>
-    <li class="last"><h5>Distribution Control</h5> Deliver your apps to the users you want, on the devices you want, on <em>your</em> schedule. <br />
-    <a href="{@docRoot}distribute/googleplay/about/distribution.html">Read More ›</a></li>
-  </ul>
-</div>
-
-
-
-    
-
-
+  <div class="resource-widget resource-carousel-layout col-16" 
+    style="height:420px;margin-top:20px;padding-top:0"
+    data-query="type:youtube+tag:googleplay+tag:developerstory+tag:featured, type:blog+tag:googleplay+tag:distribute+tag:featured"
+    data-sortOdrder="-timestamp"
+    data-maxResults="4"></div>
+  
+  <div class="resource-widget resource-flow-layout col-16"
+    data-query="collection:launch/static"
+    data-sortOrder=""
+    data-cardSizes="6x6,6x6,6x2x3,12x6,6x6,6x2x3,6x6,6x6,12x6,6x6"
+    data-maxResults="24"></div>
 
diff --git a/docs/html/distribute/monetize/ads.jd b/docs/html/distribute/monetize/ads.jd
new file mode 100644
index 0000000..40120c3
--- /dev/null
+++ b/docs/html/distribute/monetize/ads.jd
@@ -0,0 +1,114 @@
+page.title=Monetize with Ads
+page.metaDescription=Ads are a quick and easy way to incorporate a monetization option into both your free and paid apps.
+page.tags="monetizing", "free", "freemium", "ads"
+page.image=/distribute/images/advertising.png
+
+@jd:body
+
+<div class="figure">
+  <img src="{@docRoot}distribute/images/advertising.jpg" style="width:460px;">
+</div>
+
+<p>
+  In-app advertising offers a quick and easy way to incorporate a monetization
+  option into both your <a href=
+  "{@docRoot}distribute/monetize/freemium.html">freemium</a>, <a href=
+  "{@docRoot}distribute/monetize/premium.html">premium</a>, and <a href=
+  "{@docRoot}distribute/monetize/subscriptions.html">subscription</a> apps. </p>
+
+<p>Using <a href=
+  "http://www.google.com/ads/admob/monetize.html#subid=us-en-et-dac">AdMob</a>
+  and the <a href="{@docRoot}google/play-services/ads.html">Google
+  Mobile Ads SDK</a> included in Google Play Services, you’re able to add
+  advertising into your apps, with just a few lines of code.
+</p>
+
+<p>
+  When including ads in your apps you should consider:
+</p>
+
+<ul>
+  <li>
+    <p>
+      <strong>Placement within your apps</strong> &mdash; Well placed ads will
+      optimize your revenue by making it more likely that users will ‘click
+      through’. Poorly placed ads can result in low click-through rates, and in
+      the worse cases poor rating and users rapidly abandoning your apps. You
+      can get advice on how to best place ads from the developer training on
+      <a href=
+      "{@docRoot}training/monetization/ads-and-ux.html">using
+      ads</a>.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <strong>Ad formats</strong> &mdash; Every app offers a different type of
+      experience for users, so it’s important to consider the format of ads
+      you’re using to ensure it’s compatible with the experience. While banner
+      ads may work well for a flashlight utility app, an immersive gaming app
+      may benefit more from a video interstitial. Mismatched ad formats may
+      negatively affect your users’ experience and ad revenue, so try to select
+      formats that fit well with the content and flow of your apps.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <strong>Maximizing your performance</strong> &mdash; Ensure you’re optimizing
+      your advertising revenue by maximizing your CPMs <em>and</em> fill rate.
+      Often ad providers will cite very high CPMs but will have a low fill rate
+      that can severely decrease your effective CPM, so look at both of these
+      figures. Also consider using a <a href=
+      "https://support.google.com/admob/v2/answer/3063564?hl=en&amp;ref_topic=3063091#subid=us-en-et-dac">
+      mediation</a> solution if you’d like to use multiple ad providers in your
+      apps. Look for solutions that offer yield management or <a href=
+      "https://support.google.com/admob/v2/answer/3379794?hl=en&amp;ref_topic=3379793#subid=us-en-et-dac">
+      network optimization</a> features to serve the highest paying ad for each
+      impression.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <strong>Exercising control options</strong> &mdash; A variety of ads promoting a
+      broad selection of other services or apps may show up within you apps.
+      Depending on your goals and the type of experience you want to provide
+      your users, it may make sense to <a href=
+      "https://support.google.com/admob/v2/answer/3150235?hl=enl#subid=us-en-et-dac">
+      block</a> certain advertisements from appearing. Some developers don’t
+      want apps in a similar category showing to their users, but some don’t
+      mind.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <strong>Cross promoting your other apps</strong> &mdash; Ads can be used for
+      more than just earning revenue. Consider using <a href=
+      "https://support.google.com/admob/v2/answer/3210452?hl=en#subid=us-en-et-dac">
+      house ads</a> within your apps to create awareness and promote your
+      entire portfolio of apps. When launching new apps, an easy way to quickly
+      attract users is to promote directly to your existing customers.
+    </p>
+  </li>
+</ul>
+
+<p>
+  To start monetizing with ads sign up for <a href=
+  "http://www.google.com/ads/admob/#subid=us-en-et-dac">AdMob</a> and integrate
+  the <a href="https://developers.google.com/mobile-ads-sdk/download">Google
+  Mobile Ads SDK</a> into your apps. If you also need to manage direct deals
+  with advertisers, consider using <a href=
+  "http://www.google.com/doubleclick/publishers/small-business/index.html#subid=us-en-et-dac">
+  DoubleClick for Publishers Small Business</a>.
+</p>
+
+<div class="headerLine"><h1 id="related-resources">Related resources</h1><hr></div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/monetize/advertising"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/monetize/ecommerce.jd b/docs/html/distribute/monetize/ecommerce.jd
new file mode 100644
index 0000000..b3f790d
--- /dev/null
+++ b/docs/html/distribute/monetize/ecommerce.jd
@@ -0,0 +1,59 @@
+page.title=E-commerce
+page.image=/distribute/images/ecommerce.jpg
+page.metaImage=With Instant Buy you can sell physical goods and services from your web pages.
+page.tags="monetizing", "physical goods", "wallet"
+@jd:body
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-ecom-0.png" style="width:300px;">
+  <p class="img-caption">
+    Product Purchase with Instant Buy
+  </p>
+</div>
+
+<p>
+  With Google Wallet Instant Buy, you've the added flexibility of selling
+  physical goods and services, such as clothing or movie tickets, through your
+  apps using <a href=
+  "https://developers.google.com/wallet/instant-buy/">Instant Buy for
+  Android</a> in the US.
+</p>
+
+<p>
+  You can use this option where your app is the store-front for retail or
+  webtail operations. However, you can also combine it with your <a href=
+  "{@docRoot}distribute/monetize/premium.html">premium</a> and <a href=
+  "{@docRoot}distribute/monetize/freemium.html">freemium</a> apps by offering
+  related products.
+</p>
+
+<p>
+  Your customers purchase goods and services with any Google Wallet payment
+  method &mdash; credit card, gift card, or Wallet balance. Google Wallet
+  Instant Buy helps you minimize user data entry by enabling your payment flow
+  to retrieve information directly from the user’s wallet.
+</p>
+
+<p>
+  You also keep your existing payment infrastructure and leverage Google Wallet
+  to optimize your payment flow &mdash; users can make purchases in as a few as
+  two clicks and the flow is simplified with features to retrieve information
+  directly from the user’s wallet and intelligent auto-completion of addresses.
+  To get started, set up a <a href=
+  "{@docRoot}distribute/googleplay/start.html#merchant-account">Merchant
+  Account</a>.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="related-resources">
+    Related Resources
+  </h1>
+
+  <hr>
+</div>
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/monetize/ecommerce"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/monetize/freemium.jd b/docs/html/distribute/monetize/freemium.jd
new file mode 100644
index 0000000..ec86d19
--- /dev/null
+++ b/docs/html/distribute/monetize/freemium.jd
@@ -0,0 +1,80 @@
+page.title=Monetize Freemium Apps
+page.image=/distribute/images/freemium.jpg
+page.metaDescription=Use Google Play In-app Billing and other tools to monetize your free apps.
+page.tags="in-app", "billing", "iap", "monetizing"
+@jd:body
+
+<p>
+  Users are more likely to download free apps and games compared to priced
+  ones. However, we provide you with a number of ways to monetize free apps,
+  using <a href="{@docRoot}google/play/billing/index.html">In-app
+  Billing</a>. With this tool you can sell digital goods that are:
+</p>
+
+<ul>
+  <li>Durable &mdash; once purchased the item will always be available to the
+  user, such as additional app features.
+  </li>
+
+  <li>Consumable &mdash; items that might be used progressively or expire after
+  a period of time, such as a game booster or news subscription.
+  </li>
+</ul>
+
+<p>
+  A basic approach is to offer a free download with limited features or full
+  features for a limited time. Then use an in-app purchase to unlock the full,
+  unlimited app.
+</p>
+
+<div class="center-img" style="width:620px">
+<div style="float:right; width:300px; padding-left:1em;">
+  <img src="{@docRoot}images/gp-freemium-1.jpg" class="border-img">
+  <p class="img-caption">
+  Consumable product purchase
+  </p>
+</div>
+
+<div style="width:300px;float:left;">
+  <img src="{@docRoot}images/gp-freemium-0.jpg" class="border-img">
+  <p class="img-caption">
+  Durable goods purchase
+  </p>
+</div>
+</div>
+
+<p class="clearfloat">
+  A more advanced approach is to offer a range of features and content items
+  through in-app purchases. For example, in games you can offer users new
+  levels, playing pieces, or other game features. In apps you can offer
+  features or functionality that enhance the user experience either by
+  extending existing features or offering new ones. Using this approach you can
+  generate a continuing revenue stream from each app install.
+</p>
+
+<p>
+  Any item offered as an in-app purchase can also be offered as a subscription.
+</p>
+
+<p>
+  To get started with In-app Billing you need to set-up a Google Wallet
+  <a href="{@docRoot}distribute/googleplay/start.html#merchant-account">Merchant
+  Account</a> from Developer Console. You then define <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#in-app-products">in-app
+  products</a> in the Developer Console, integrate the In-app Billing API into
+  your apps, and add the mechanisms to unlock features or deliver content.
+</p>
+
+<div class="headerLine">
+  <h1 id="related-resources">
+  Related Resources
+  </h1>
+
+  <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/monetize/freemium"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3,9x3,9x3,9x3,6x3,6x3"
+  data-maxResults="6"></div>
diff --git a/docs/html/distribute/monetize/index.jd b/docs/html/distribute/monetize/index.jd
new file mode 100644
index 0000000..7350a24
--- /dev/null
+++ b/docs/html/distribute/monetize/index.jd
@@ -0,0 +1,36 @@
+page.title=Monetize
+section.landing=true
+nonavpage=true
+
+@jd:body
+
+<p>
+  There are many ways to make money with your apps on Google Play, and we offer
+  a variety of tools to make it easy. Take advantage of Google Play’s
+  phenomenal growth by using one or more of the business models available.
+</p>
+
+<p>
+  To get started, set up your <a href=
+  "{@docRoot}distribute/googleplay/start.html#merchant-account">Merchant Account</a>
+  from your Developer Console. This will not only help you get paid, but also
+  help you track where your money is coming from.
+</p>
+
+<div class="dynamic-grid">
+
+  <div class="resource-widget resource-flow-layout landing col-16"
+    data-query="collection:distribute/monetize"
+    data-cardSizes="6x6"
+    data-maxResults="9">
+  </div>
+
+<h3>Related resources</h3>
+
+  <div class="resource-widget resource-flow-layout col-16"
+    data-query="tag:monetizing"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x3"
+    data-maxResults="6">
+  </div>
+</div>
diff --git a/docs/html/distribute/monetize/monetize_toc.cs b/docs/html/distribute/monetize/monetize_toc.cs
new file mode 100644
index 0000000..aeb6cf8
--- /dev/null
+++ b/docs/html/distribute/monetize/monetize_toc.cs
@@ -0,0 +1,47 @@
+<ul id="nav">
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/monetize/premium.html">
+            <span class="en">Premium</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/monetize/freemium.html">
+            <span class="en">Freemium</span>
+          </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/monetize/subscriptions.html">
+          <span class="en">Subscriptions</span>
+        </a
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/monetize/ecommerce.html">
+          <span class="en">E-commerce</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/monetize/ads.html">
+          <span class="en">Ads</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/monetize/payments.html">
+          <span class="en">Purchasing</span>
+        </a>
+    </div>
+  </li>
+
+</ul>
+
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
+
diff --git a/docs/html/distribute/monetize/payments.jd b/docs/html/distribute/monetize/payments.jd
new file mode 100644
index 0000000..37b4d44
--- /dev/null
+++ b/docs/html/distribute/monetize/payments.jd
@@ -0,0 +1,104 @@
+page.title=Convenient, Frictionless Purchasing
+page.image=/distribute/images/payment-method.jpg
+page.metaDescription=Users can purchase instantly with a choice of payment methods.
+page.tags="google play", "payments", "gift card"
+
+@jd:body
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-start-wallet-icon.png" style="width:200px;">
+</div>
+
+<p>
+  Google Play makes it fast and easy for your customers to buy your products,
+  whether from a phone, a tablet, or a desktop computer. They can purchase
+  instantly with a streamlined, consistent purchasing process and convenient
+  payment methods.
+</p>
+
+<div class="headerLine">
+  <h1 id="dcb">
+  Direct Carrier Billing
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Users pay by charging their monthly carrier bills . The benefit of Direct
+  Carrier Billing is that it opens up markets where credit cards are less
+  common, as purchases are charged to your customers’ monthly mobile phone
+  bills. This option is available to users in key markets
+  around the world. Many more will get the option in the months ahead.
+</p>
+
+<div class="headerLine">
+  <h1 id="credit">
+  Credit Cards
+  </h1>
+  <hr>
+</div>
+
+<p>
+  Users can pay using any credit card that they’ve registered in Google Play.
+  Credit Cards added to Google Play are stored in the user’s Google Wallet and
+  available for in-app purchases and instant buys too. To make it easy for
+  users to get started, registration is offered as a part of the initial device
+  setup process.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="gift-cards">
+  Google Play Gift Cards
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-payments-1.png">
+</div>
+
+<p>
+  Gift cards enable users to add value to their Google Play balance by entering
+  a unique code printed on a card purchased online or from major retailers.
+  More information gift cards can be found <a href=
+  "http://play.google.com/intl/en-US_us/about/giftcards/" target=
+  "_android">here</a>.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="balance">
+  Google Play Balance
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-balance.png">
+</div>
+
+<p>
+  Google Play balance, also known as stored value, is a stored account balance
+  in Google Play. Users can increase their balance by redeeming <a href=
+  "https://play.google.com/intl/en-US_us/about/giftcards/">gift cards</a> or by
+  earning rewards through the <a href=
+  "https://play.google.com/store/apps/details?id=com.google.android.apps.paidtasks&amp;hl=en">
+  Google Opinions Rewards app</a>, and they can use their balance to make
+  purchases of apps, games, or other content.
+</p>
+
+<p>
+  The payment methods available to users may vary based on location, carrier
+  network, and other factors.
+</p>
+ 
+<div class="headerLine clearfloat"><h1 id="related-resources">Related Resources</h1><hr></div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/monetize/paymentmethods"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="8"></div>
+
diff --git a/docs/html/distribute/monetize/premium.jd b/docs/html/distribute/monetize/premium.jd
new file mode 100644
index 0000000..b66cd03
--- /dev/null
+++ b/docs/html/distribute/monetize/premium.jd
@@ -0,0 +1,49 @@
+page.title=Monetize Premium Apps
+page.image=/distribute/images/premium.jpg
+page.metaDescription=Charging users to download your apps is a simple, convenient monetization model.
+page.tags="monetizing", "paid"
+
+@jd:body
+
+<div class="figure"><img src="{@docRoot}images/gp-premium-0.png" />
+<p class="img-caption" style="width:300px">Paid app</p>
+</div>
+<p>
+  Charging users to download your apps is a simple, convenient monetization
+  model. After creating your <a href=
+  "/distribute/googleplay/start.html#merchant-account">Merchant
+  Account</a>, you <a href=
+  "/distribute/googleplay/developer-console.html#selling-pricing-your-products">set prices for your
+  apps</a> in the Developer Console. You can optionally include advertising or use
+  <a href="{@docRoot}google/play/billing/index.html">In-app
+  Billing</a> to sell additional features or content.
+</p>
+
+<p>
+  This model could work well for any app or game, but might be particularly
+  relevant to those with extensive features or that address a narrow niche in
+  the market. Certain categories of apps, such as games for children, should be
+  monetized by paying for them up front instead of advertising or in-app
+  purchases.
+</p>
+
+<p>
+  However, this model may limit your apps monetization potential, particularly
+  in developing markets. You may be able to achieve greater revenue using the
+  <a href="{@docRoot}distribute/monetize/freemium.html">freemium</a>, <a href=
+  "{@docRoot}distribute/monetize/subscriptions.html">subscriptions</a> or
+  <a href="{@docRoot}distribute/monetize/ads.html">advertising</a> models.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1>
+  Related Resources
+  </h1>
+  <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/monetize/premium"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
\ No newline at end of file
diff --git a/docs/html/distribute/monetize/subscriptions.jd b/docs/html/distribute/monetize/subscriptions.jd
new file mode 100644
index 0000000..a838e30
--- /dev/null
+++ b/docs/html/distribute/monetize/subscriptions.jd
@@ -0,0 +1,71 @@
+page.title=Monetize with Subscriptions
+page.image=/distribute/images/subscription.jpg
+page.metaDescription=Sell subscriptions to your products to create continuing revenue streams.
+page.tags="in-app", "iap", "monetizing", "free", "trials"
+@jd:body
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-subscription-0.jpg">
+  <p class="img-caption" style="width:300px;">
+  In-App Subscriptions
+  </p>
+</div>
+
+<p>
+  Subscriptions provide an excellent opportunity to create continuing revenue
+  streams. Subscriptions are similar to digital goods offered through <a href=
+  "{@docRoot}google/play/billing/index.html">In-app Billing</a> but made
+  available on a recurring monthly or annual basis.
+</p>
+
+<p>
+  When users purchase subscriptions in your apps, Google Play handles all
+  checkout details so your apps never have to directly process any financial
+  transactions. Google Play processes all payments for subscriptions through
+  Google Wallet, just as it does for standard in-app products and app
+  purchases. This ensures a consistent and familiar purchase flow for your
+  users and reduces cart abandonment rates.
+</p>
+
+<p>
+  At a basic level you can offer use of your apps or access to their content on
+  a subscription basis, using a <a href=
+  "{@docRoot}google/play/billing/billing_subscriptions.html#trials">free trial
+  subscription</a> to allow users to explore the apps or content.
+</p>
+
+<p>
+  A more advanced approach is to offer specific features or content items as
+  subscriptions within your apps. This way you can offer users basic or core
+  features or content for free or part of the initial purchase and extended
+  features or content as subscriptions. You can have multiple subscriptions
+  active in an app at any one time.
+</p>
+
+<p>
+  To get started with subscriptions you need to set-up a Google Wallet <a href=
+  "{@docRoot}distribute/googleplay/start.html#merchant-account">Merchant
+  Account</a> from the Developer Console. You then define subscriptions for
+  published or draft apps in the <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#in-app-billing">In-app
+  Products</a> section of the Developer Console, integrate the In-app Billing
+  API into your apps, and add the mechanisms to unlock subscribed features or
+  deliver content.
+</p>
+
+<div class="sidebox" style="width:400px;float:left;margin-left:0">
+  <p>
+  <strong>Tip:</strong> Due to some direct carrier billing limits, we
+  recommend monthly subscriptions. Annual subscriptions may exceed limits,
+  causing the purchase to be blocked and you to lose that revenue.
+  </p>
+</div>
+
+<div class="headerLine clearfloat"><h1 id="related-resources">Related Resources</h1><hr></div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/monetize/subscriptions"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/open.jd b/docs/html/distribute/open.jd
deleted file mode 100644
index f9e9c3b..0000000
--- a/docs/html/distribute/open.jd
+++ /dev/null
@@ -1,107 +0,0 @@
-page.title=Open Distribution
-@jd:body
-
-<p>As an open platform, Android offers choice. You
-distribute your Android apps to users in any way you want, using any
-distribution approach or combination of approaches that meets your needs. 
-From publishing in an app marketplace to serving your apps from a web site or
-emailing them directly users, you are never locked into any
-particular distribution platform.</p>
-
-<p>The process for building and packaging your app for distribution is the same,
-regardless of how you will distribute your app. This saves you time and lets you
-automate parts of the process as needed. You can read <a 
-href="{@docRoot}tools/publishing/preparing.html">Preparing 
-for Release</a> for more information.</p>
-
-<p>The sections below highlight some of the alternatives for distributing
-your apps to users.</p>
-
-<h2 id="publishing-marketplace">Distributing through an App Marketplace</h2>
-
-<p>Usually, to reach the broadest possible audience, you would distribute your
-apps through a marketplace, such as Google Play.</p>
-
-<p>Google Play is the premier marketplace for Android apps and is particularly
-useful if you want to distribute your applications to a large global audience.
-However, you can distribute your apps through any app marketplace you want or
-you can use multiple marketplaces.</p>
-
-<h2 id="publishing-email">Distributing your application through email</h2>
-
-<div class="figure" style="width:246px">
-  <img src="{@docRoot}images/publishing/publishing_via_email.png"
-       alt="Screenshot showing the graphical user interface users see when you send them an app"
-       style="width:240px;" />
-  <p class="img-caption">
-    <strong>Figure 1.</strong> Users can simply click <strong>Install</strong> when you send them
-    an application via email.
-  </p>
-</div>
-
-<p>The easiest and quickest way to release your application is to send it to users through
-email. To do this, you prepare your application for release and then attach it to an email
-and send it to a user. When users open your email message on their Android-powered device,
-the Android system will recognize the APK and display an <strong>Install Now</strong>
-button in the email message (see figure 1). Users can install your application by touching the
-button.</p>
-
-<p class="note"><strong>Note:</strong> The <strong>Install Now</strong> button
-shown in Figure 1 appears only if users have configured their device to allow
-installation from <a href="#unknown-sources">unknown sources</a> and have opened your 
-email with the native Gmail application.</p>
-
-<p>Distributing applications through email is convenient if you are sending your application to
-only a few trusted users, but it provides few protections from piracy and unauthorized
-distribution; that is, anyone you send your application to can simply forward it to someone else.</p>
-
-<h2 id="publishing-website">Distributing through a web site</h2>
-
-<p>If you do not want to release your app on a marketplace like Google Play, you
-can make the app available for download on your own website or server, including
-on a private or enterprise server. To do this, you must first prepare your
-application for release in the normal way. Then all you need to do is host the
-release-ready APK file on your website and provide a download link to users.
-</p>
-
-<p>When users browse to the download link from their Android-powered devices,
-the file is downloaded and Android system automatically starts installing it on
-the device. However, the installation process will start automatically only if
-users have configured their Settings to allow the installation of apps from
-<a href="#unknown-sources">unknown sources</a>.</p>
-
-<p>Although it is relatively easy to release your application on your own
-website, it can be inefficient. For example, if you want to monetize your
-application you will have to process and track all financial transactions
-yourself and you will not be able to use Google Play's <a
-href="{@docRoot}google/play/billing/index.html">In-app Billing service</a>
-to sell in-app products. In addition, you will not be able to use the <a
-href="{@docRoot}google/play/licensing/index.html">Licensing service</a> to
-help prevent unauthorized installation and use of your application.</p>
-
-
-<h2 id="unknown-sources">User Opt-In for Apps from Unknown Sources</h2>
-
-<div class="figure" style="width:246px;margin-top:0;">
-  <img src="{@docRoot}images/publishing/publishing_unknown_sources_sm.png"
-       alt="Screenshot showing the setting for accepting download and install of
-       apps from unknown sources." style="width:240px;" />
-  <p class="img-caption">
-    <strong>Figure 2.</strong> Users must enable the <strong>Unknown sources</strong>
-    setting before they can install apps not downloaded from Google Play. 
-  </p>
-</div> 
-
-<p>Android protects users from inadvertent download and install of apps from
-locations other than Google Play (which is trusted). It blocks such installs
-until the user opts-in <strong>Unknown sources</strong> in
-Settings&nbsp;<strong>&gt;</strong>&nbsp;Security, shown in Figure 2. To allow
-the installation of applications from other sources, users need to enable the
-Unknown sources setting on their devices, and they need to make this
-configuration change <em>before</em> they download your application to their
-devices.</p> 
-
-<p class="note">Note that some network providers do not allow users to install
-applications from unknown sources.</p>
-
-
diff --git a/docs/html/distribute/promote/device-art.jd b/docs/html/distribute/promote/device-art.jd
deleted file mode 100644
index b3b414e..0000000
--- a/docs/html/distribute/promote/device-art.jd
+++ /dev/null
@@ -1,693 +0,0 @@
-page.title=Device Art Generator
-@jd:body
-
-<p>The device art generator allows you to quickly wrap your app screenshots in real device artwork.
-This provides better visual context for your app screenshots on your web site or in other
-promotional materials.</p>
-
-<p class="note"><strong>Note</strong>: Do <em>not</em> use graphics created here in your 1024x500
-feature image or screenshots for your Google Play app listing.</p>
-
-<hr>
-
-<div class="supported-browser">
-
-<div class="layout-content-row">
-  <div class="layout-content-col span-3">
-    <h4>Step 1</h4>
-    <p>Drag a screenshot from your desktop onto a device to the right.</p>
-  </div>
-  <div class="layout-content-col span-10">
-    <ul class="device-list primary"></ul>
-    <a href="#" id="archive-expando">Older devices</a>
-    <ul class="device-list archive"></ul>
-  </div>
-</div>
-
-<hr>
-
-<div class="layout-content-row">
-  <div class="layout-content-col span-3">
-    <h4>Step 2</h4>
-    <p>Customize the generated image and drag it to your desktop to save.</p>
-    <p id="frame-customizations">
-      <input type="checkbox" id="output-shadow" checked="checked" class="form-field-checkbutton">
-      <label for="output-shadow">Shadow</label><br>
-      <input type="checkbox" id="output-glare" checked="checked" class="form-field-checkbutton">
-      <label for="output-glare">Screen Glare</label><br><br>
-      <a class="button" id="rotate-button">Rotate</a>
-    </p>
-  </div>
-  <div class="layout-content-col span-10">
-    <!-- position:relative fixes an issue where dragging an image out of a inline-block container
-         produced no drag feedback image in Chrome 28. -->
-    <div id="output" style="position:relative">No input image.</div>
-  </div>
-</div>
-
-</div>
-
-<div class="unsupported-browser" style="display: none">
-  <p class="warning"><strong>Error:</strong> This page requires 
-    <span id="unsupported-browser-reason">certain features</span>, which your web browser
-    doesn't support. To continue, navigate to this page on a supported web browser, such as
-    <strong>Google Chrome</strong>.</p>
-  <a href="https://www.google.com/chrome/" class="button">Get Google Chrome</a>
-  <br><br>
-</div>
-
-<style>
-  h4 {
-    text-transform: uppercase;
-  }
-
-  .device-list {
-    padding: 0;
-    margin: 0;
-  }
-
-  .device-list li {
-    display: inline-block;
-    vertical-align: bottom;
-    margin: 0;
-    margin-right: 20px;
-    text-align: center;
-  }
-
-  .device-list li .thumb-container {
-    display: inline-block;
-  }
-
-  .device-list li .thumb-container img {
-    margin-bottom: 8px;
-    opacity: 0.6;
-
-    -webkit-transition: -webkit-transform 0.2s, opacity 0.2s;
-       -moz-transition:    -moz-transform 0.2s, opacity 0.2s;
-            transition:         transform 0.2s, opacity 0.2s;
-  }
-
-  .device-list li.drag-hover .thumb-container img {
-    opacity: 1;
-
-    -webkit-transform: scale(1.1);
-       -moz-transform: scale(1.1);
-            transform: scale(1.1);
-  }
-
-  .device-list li .device-details {
-    font-size: 13px;
-    line-height: 16px;
-    color: #888;
-  }
-
-  .device-list li .device-url {
-    font-weight: bold;
-  }
-
-  #archive-expando {
-    display: block;
-    font-size: 13px;
-    font-weight: bold;
-    color: #333;
-    text-transform: uppercase;
-    margin-top: 16px;
-    padding-top: 16px;
-    padding-left: 28px;
-    border-top: 1px solid transparent;
-    background: transparent url({@docRoot}assets/images/styles/disclosure_down.png)
-                no-repeat scroll 0 8px;
-    -webkit-transition: border 0.2s;
-       -moz-transition: border 0.2s;
-            transition: border 0.2s;
-  }
-
-  #archive-expando.expanded {
-    background-image: url({@docRoot}assets/images/styles/disclosure_up.png);
-    border-top: 1px solid #ccc;
-  }
-
-  .device-list.archive {
-    max-height: 0;
-    overflow: hidden;
-    opacity: 0;
-
-    -webkit-transition: max-height 0.2s, opacity 0.2s;
-       -moz-transition: max-height 0.2s, opacity 0.2s;
-            transition: max-height 0.2s, opacity 0.2s;
-  }
-
-  .device-list.archive.expanded {
-    opacity: 1;
-    max-height: 300px;
-  }
-
-  #output {
-    color: #f44;
-    font-style: italic;
-  }
-
-  #output img {
-    max-height: 500px;
-  }
-</style>
-<script>
-  // Global variables
-  var g_currentImage;
-  var g_currentDevice;
-  var g_currentObjectURL;
-  var g_currentBlob;
-
-  // Global constants
-  var MSG_INVALID_INPUT_IMAGE = 'Invalid screenshot provided. Screenshots must be PNG files '
-      + 'matching the target device\'s screen aspect ratio in either portrait or landscape.';
-  var MSG_NO_INPUT_IMAGE = 'Drag a screenshot (in PNG format) from your desktop onto a '
-      + 'target device above.'
-  var MSG_GENERATING_IMAGE = 'Generating device art&hellip;';
-
-  var MAX_DISPLAY_HEIGHT = 126; // XOOM, to fit into 200px wide
-
-  // Device manifest.
-  var DEVICES = [
-    {
-      id: 'nexus_5',
-      title: 'Nexus 5',
-      url: 'http://www.google.com/nexus/5/',
-      physicalSize: 5,
-      physicalHeight: 5.43,
-      density: 'XXHDPI',
-      landRes: ['shadow', 'back', 'fore'],
-      landOffset: [436,306],
-      portRes: ['shadow', 'back', 'fore'],
-      portOffset: [304,436],
-      portSize: [1080,1920],
-    },
-    {
-      id: 'nexus_7',
-      title: 'Nexus 7',
-      url: 'http://www.google.com/nexus/7/',
-      physicalSize: 7,
-      physicalHeight: 8,
-      actualResolution: [1200,1920],
-      density: 'XHDPI',
-      landRes: ['shadow', 'back', 'fore'],
-      landOffset: [326,245],
-      portRes: ['shadow', 'back', 'fore'],
-      portOffset: [244,326],
-      portSize: [800,1280]
-    },
-    {
-      id: 'nexus_10',
-      title: 'Nexus 10',
-      url: 'http://www.google.com/nexus/10/',
-      physicalSize: 10,
-      physicalHeight: 7,
-      actualResolution: [1600,2560],
-      density: 'XHDPI',
-      landRes: ['shadow', 'back', 'fore'],
-      landOffset: [227,217],
-      portRes: ['shadow', 'back', 'fore'],
-      portOffset: [217,223],
-      portSize: [800,1280]
-    },
-    {
-      id: 'xoom',
-      title: 'Motorola XOOM',
-      url: 'http://www.google.com/phone/detail/motorola-xoom',
-      physicalSize: 10,
-      physicalHeight: 6.61,
-      density: 'MDPI',
-      landRes: ['shadow', 'back', 'fore'],
-      landOffset: [218,191],
-      portRes: ['shadow', 'back', 'fore'],
-      portOffset: [199,200],
-      portSize: [800,1280],
-      archived: true
-    },
-    {
-      id: 'nexus_7_2012',
-      title: 'Nexus 7 (2012)',
-      url: 'http://www.google.com/nexus/7/',
-      physicalSize: 7,
-      physicalHeight: 7.81,
-      density: '213dpi',
-      landRes: ['shadow', 'back', 'fore'],
-      landOffset: [315,270],
-      portRes: ['shadow', 'back', 'fore'],
-      portOffset: [264,311],
-      portSize: [800,1280],
-      archived: true
-    },
-    {
-      id: 'nexus_4',
-      title: 'Nexus 4',
-      url: 'http://www.google.com/nexus/4/',
-      physicalSize: 4.7,
-      physicalHeight: 5.27,
-      density: 'XHDPI',
-      landRes: ['shadow', 'back', 'fore'],
-      landOffset: [349,214],
-      portRes: ['shadow', 'back', 'fore'],
-      portOffset: [213,350],
-      portSize: [768,1280],
-      archived: true
-    },
-    {
-      id: 'galaxy_nexus',
-      title: 'Galaxy Nexus',
-      url: 'http://www.android.com/devices/detail/galaxy-nexus',
-      physicalSize: 4.65,
-      physicalHeight: 5.33,
-      density: 'XHDPI',
-      landRes: ['shadow', 'back', 'fore'],
-      landOffset: [371,199],
-      portRes: ['shadow', 'back', 'fore'],
-      portOffset: [216,353],
-      portSize: [720,1280],
-      archived: true
-    },
-    {
-      id: 'nexus_s',
-      title: 'Nexus S',
-      url: 'http://www.google.com/phone/detail/nexus-s',
-      physicalSize: 4.0,
-      physicalHeight: 4.88,
-      density: 'HDPI',
-      landRes: ['shadow', 'back', 'fore'],
-      landOffset: [247,135],
-      portRes: ['shadow', 'back', 'fore'],
-      portOffset: [134,247],
-      portSize: [480,800],
-      archived: true
-    }
-  ];
-
-  DEVICES = DEVICES.sort(function(x, y) { return x.physicalSize - y.physicalSize; });
-
-  var MAX_HEIGHT = 0;
-  for (var i = 0; i < DEVICES.length; i++) {
-    MAX_HEIGHT = Math.max(MAX_HEIGHT, DEVICES[i].physicalHeight);
-  }
-
-  // Setup performed once the DOM is ready.
-  $(document).ready(function() {
-    if (!checkBrowser()) {
-      return;
-    }
-
-    polyfillCanvasToBlob();
-    setupUI();
-
-    // Set up Chrome drag-out
-    $.event.props.push("dataTransfer");
-    document.body.addEventListener('dragstart', function(e) {
-      var target = e.target;
-      if (target.classList.contains('dragout')) {
-        e.dataTransfer.setData('DownloadURL', target.dataset.downloadurl);
-      }
-    }, false);
-  });
-
-  /**
-   * Returns the device from DEVICES with the given id.
-   */
-  function getDeviceById(id) {
-    for (var i = 0; i < DEVICES.length; i++) {
-      if (DEVICES[i].id == id)
-        return DEVICES[i];
-    }
-    return;
-  }
-
-  /**
-   * Checks to make sure the browser supports this page. If not,
-   * updates the UI accordingly and returns false.
-   */
-  function checkBrowser() {
-    // Check for browser support
-    var browserSupportError = null;
-
-    // Must have <canvas>
-    var elem = document.createElement('canvas');
-    if (!elem.getContext || !elem.getContext('2d')) {
-      browserSupportError = 'HTML5 canvas.';
-    }
-
-    // Must have FileReader
-    if (!window.FileReader) {
-      browserSupportError = 'desktop file access';
-    }
-
-    if (browserSupportError) {
-      $('.supported-browser').hide();
-
-      $('#unsupported-browser-reason').html(browserSupportError);
-      $('.unsupported-browser').show();
-      return false;
-    }
-
-    return true;
-  }
-
-  function setupUI() {
-    $('#output').html(MSG_NO_INPUT_IMAGE);
-
-    $('#frame-customizations').hide();
-
-    $('#output-shadow, #output-glare').click(function() {
-      createFrame();
-    });
-
-    // Build device list.
-    $.each(DEVICES, function() {
-      var resolution = this.actualResolution || this.portSize;
-      var scaleFactorText = '';
-      if (resolution[0] != this.portSize[0]) {
-        scaleFactorText = '<br>' + (100 * (this.portSize[0] / resolution[0])).toFixed(0) +
-            '% size output';
-      } else {
-        scaleFactorText = '<br>&nbsp;';
-      }
-
-      $('<li>')
-          .append($('<div>')
-              .addClass('thumb-container')
-              .append($('<img>')
-                  .attr('src', 'device-art-resources/' + this.id + '/thumb.png')
-                  .attr('height',
-                      Math.floor(MAX_DISPLAY_HEIGHT * this.physicalHeight / MAX_HEIGHT))))
-          .append($('<div>')
-              .addClass('device-details')
-              .html((this.url
-                  ? ('<a class="device-url" href="' + this.url + '">' + this.title + '</a>')
-                  : this.title) +
-                  '<br>' +  this.physicalSize + '" @ ' + this.density +
-                  '<br>' + (resolution[0] + 'x' + resolution[1]) + scaleFactorText))
-          .data('deviceId', this.id)
-          .appendTo(this.archived ? '.device-list.archive' : '.device-list.primary');
-    });
-
-    // Set up "older devices" expando.
-    $('#archive-expando').click(function() {
-      if ($(this).hasClass('expanded')) {
-        $(this).removeClass('expanded');
-        $('.device-list.archive').removeClass('expanded');
-      } else {
-        $(this).addClass('expanded');
-        $('.device-list.archive').addClass('expanded');
-      }
-      return false;
-    });
-
-    // Set up drag and drop.
-    $('.device-list li')
-        .live('dragover', function(evt) {
-          $(this).addClass('drag-hover');
-          evt.dataTransfer.dropEffect = 'link';
-          evt.preventDefault();
-        })
-        .live('dragleave', function(evt) {
-          $(this).removeClass('drag-hover');
-        })
-        .live('drop', function(evt) {
-          $('#output').empty().html(MSG_GENERATING_IMAGE);
-          $(this).removeClass('drag-hover');
-          g_currentDevice = getDeviceById($(this).closest('li').data('deviceId'));
-          evt.preventDefault();
-          loadImageFromFileList(evt.dataTransfer.files, function(data) {
-            if (data == null) {
-              $('#output').html(MSG_INVALID_INPUT_IMAGE);
-              return;
-            }
-            loadImageFromUri(data.uri, function(img) {
-              g_currentFilename = data.name;
-              g_currentImage = img;
-              createFrame();
-              // Send the event to Analytics
-              _gaq.push(['_trackEvent', 'Distribute', 'Create Device Art', g_currentDevice.title]);
-            });
-          });
-        });
-
-    // Set up rotate button.
-    $('#rotate-button').click(function() {
-      if (!g_currentImage) {
-        return;
-      }
-
-      var w = g_currentImage.naturalHeight;
-      var h = g_currentImage.naturalWidth;
-      var canvas = $('<canvas>')
-          .attr('width', w)
-          .attr('height', h)
-          .get(0);
-
-      var ctx = canvas.getContext('2d');
-      ctx.rotate(-Math.PI / 2);
-      ctx.translate(-h, 0);
-      ctx.drawImage(g_currentImage, 0, 0);
-
-      loadImageFromUri(canvas.toDataURL('image/png'), function(img) {
-        g_currentImage = img;
-        createFrame();
-      });
-    });
-  }
-
-  /**
-   * Generates the frame from the current selections (g_currentImage and g_currentDevice).
-   */
-  function createFrame() {
-    var port;
-
-    var aspect1 = g_currentImage.naturalWidth / g_currentImage.naturalHeight;
-    var aspect2 = g_currentDevice.portSize[0] / g_currentDevice.portSize[1];
-
-    if (aspect1 == aspect2) {
-      port = true;
-    } else if (aspect1 == 1 / aspect2) {
-      port = false;
-    } else {
-      alert('The screenshot must have an aspect ratio of ' +
-          aspect2.toFixed(3) + ' or ' + (1 / aspect2).toFixed(3) +
-          ' (ideally ' + g_currentDevice.portSize[0] + 'x' + g_currentDevice.portSize[1] +
-          ' or ' + g_currentDevice.portSize[1] + 'x' + g_currentDevice.portSize[0] + ').');
-      $('#output').html(MSG_INVALID_INPUT_IMAGE);
-      return;
-    }
-
-    // Load image resources
-    var res = port ? g_currentDevice.portRes : g_currentDevice.landRes;
-    var resList = {};
-    for (var i = 0; i < res.length; i++) {
-      resList[res[i]] = 'device-art-resources/' + g_currentDevice.id + '/' +
-          (port ? 'port_' : 'land_') + res[i] + '.png'
-    }
-
-    var resourceImages = {};
-    loadImageResources(resList, function(r) {
-      resourceImages = r;
-      continueWithResources_();
-    });
-
-    function continueWithResources_() {
-      var width = resourceImages['back'].naturalWidth;
-      var height = resourceImages['back'].naturalHeight;
-      var offset = port ? g_currentDevice.portOffset : g_currentDevice.landOffset;
-      var size = port
-          ? g_currentDevice.portSize
-          : [g_currentDevice.portSize[1], g_currentDevice.portSize[0]];
-
-      var canvas = document.createElement('canvas');
-      canvas.width = width;
-      canvas.height = height;
-
-      var ctx = canvas.getContext('2d');
-      if (resourceImages['shadow'] && $('#output-shadow').is(':checked')) {
-        ctx.drawImage(resourceImages['shadow'], 0, 0);
-      }
-      ctx.drawImage(resourceImages['back'], 0, 0);
-      ctx.fillStyle = '#000';
-      ctx.fillRect(offset[0], offset[1], size[0], size[1]);
-      ctx.drawImage(g_currentImage, offset[0], offset[1], size[0], size[1]);
-      if (resourceImages['fore'] && $('#output-glare').is(':checked')) {
-        ctx.drawImage(resourceImages['fore'], 0, 0);
-      }
-
-      window.URL = window.URL || window.webkitURL;
-      if (canvas.toBlob && window.URL.createObjectURL) {
-        if (g_currentObjectURL) {
-          window.URL.revokeObjectURL(g_currentObjectURL);
-          g_currentObjectURL = null;
-        }
-        if (g_currentBlob) {
-          if (g_currentBlob.close) {
-            g_currentBlob.close();
-          }
-          g_currentBlob = null;
-        }
-
-        canvas.toBlob(function(blob) {
-          if (!blob) {
-            continueWithFinalUrl_(canvas.toDataURL('image/png'));
-            return;
-          }
-          g_currentBlob = blob;
-          g_currentObjectURL = window.URL.createObjectURL(blob);
-          continueWithFinalUrl_(g_currentObjectURL);
-        }, 'image/png');
-      } else {
-        continueWithFinalUrl_(canvas.toDataURL('image/png'));
-      }
-    }
-
-    function continueWithFinalUrl_(imageUrl) {
-      var filename = g_currentFilename
-          ? g_currentFilename.replace(/^(.+?)(\.\w+)?$/, '$1_framed.png')
-          : 'framed_screenshot.png';
-
-      var $link = $('<a>')
-          .attr('download', filename)
-          .attr('href', imageUrl)
-          .append($('<img>')
-              .addClass('dragout')
-              .attr('src', imageUrl)
-              .attr('draggable', true)
-              .attr('data-downloadurl', ['image/png', filename, imageUrl].join(':')))
-          .appendTo($('#output').empty());
-
-      $('#frame-customizations').show();
-    }
-  }
-
-  /**
-   * Loads an image from a data URI. The callback will be called with the <img> once
-   * it loads.
-   */
-  function loadImageFromUri(uri, callback) {
-    callback = callback || function(){};
-
-    var img = document.createElement('img');
-    img.src = uri;
-    img.onload = function() {
-      callback(img);
-    };
-    img.onerror = function() {
-      callback(null);
-    }
-  }
-
-  /**
-   * Loads a set of images (organized by ID). Once all images are loaded, the callback
-   * is triggered with a dictionary of <img>'s, organized by ID.
-   */
-  function loadImageResources(images, callback) {
-    var imageResources = {};
-
-    var checkForCompletion_ = function() {
-      for (var id in images) {
-        if (!(id in imageResources))
-          return;
-      }
-      (callback || function(){})(imageResources);
-      callback = null;
-    };
-
-    for (var id in images) {
-      var img = document.createElement('img');
-      img.src = images[id];
-      (function(img, id) {
-        img.onload = function() {
-          imageResources[id] = img;
-          checkForCompletion_();
-        };
-        img.onerror = function() {
-          imageResources[id] = null;
-          checkForCompletion_();
-        }
-      })(img, id);
-    }
-  }
-
-  /**
-   * Loads the first valid image from a FileList (e.g. drag + drop source), as a data URI. This
-   * method will throw an alert() in case of errors and call back with null.
-   *
-   * @param {FileList} fileList The FileList to load.
-   * @param {Function} callback The callback to fire once image loading is done (or fails).
-   * @return Returns an object containing 'uri' representing the loaded image. There will also be
-   *      a 'name' field indicating the file name, if one is available.
-   */
-  function loadImageFromFileList(fileList, callback) {
-    fileList = fileList || [];
-
-    var file = null;
-    for (var i = 0; i < fileList.length; i++) {
-      if (fileList[i].type.toLowerCase().match(/^image\/(png|jpeg|jpg)/)) {
-        file = fileList[i];
-        break;
-      }
-    }
-
-    if (!file) {
-      alert('Please use a valid screenshot file (PNG or JPEG format).');
-      callback(null);
-      return;
-    }
-
-    var fileReader = new FileReader();
-
-    // Closure to capture the file information.
-    fileReader.onload = function(e) {
-      callback({
-        uri: e.target.result,
-        name: file.name
-      });
-    };
-    fileReader.onerror = function(e) {
-      switch(e.target.error.code) {
-        case e.target.error.NOT_FOUND_ERR:
-          alert('File not found.');
-          break;
-        case e.target.error.NOT_READABLE_ERR:
-          alert('File is not readable.');
-          break;
-        case e.target.error.ABORT_ERR:
-          break; // noop
-        default:
-          alert('An error occurred reading this file.');
-      }
-      callback(null);
-    };
-    fileReader.onabort = function(e) {
-      alert('File read cancelled.');
-      callback(null);
-    };
-
-    fileReader.readAsDataURL(file);
-  }
-
-  /**
-   * Adds a simple version of Canvas.toBlob if toBlob isn't available.
-   */
-  function polyfillCanvasToBlob() {
-    if (!HTMLCanvasElement.prototype.toBlob && window.Blob) {
-      HTMLCanvasElement.prototype.toBlob = function(callback, mimeType, quality) {
-        if (typeof callback != 'function') {
-          throw new TypeError('Function expected');
-        }
-        var dataURL = this.toDataURL(mimeType, quality);
-        mimeType = dataURL.split(';')[0].split(':')[1];
-        var bs = window.atob(dataURL.split(',')[1]);
-        if (dataURL == 'data:,' || !bs.length) {
-          callback(null);
-          return;
-        }
-        for (var ui8arr = new Uint8Array(bs.length), i = 0; i < bs.length; ++i) {
-          ui8arr[i] = bs.charCodeAt(i);
-        }
-        callback(new Blob([ui8arr.buffer /* req'd for Safari */ || ui8arr], {type: mimeType}));
-      };
-    }
-  }
-</script>
diff --git a/docs/html/distribute/stories/games.jd b/docs/html/distribute/stories/games.jd
new file mode 100644
index 0000000..1a482b1
--- /dev/null
+++ b/docs/html/distribute/stories/games.jd
@@ -0,0 +1,246 @@
+page.title=Developer Stories: Google Play Game Services
+meta.tags="google play, developer story, games, global"
+page.image=/images/distribute/glu-ew-gpgames.jpg
+page.metaDescription=How gaming studios are using Google Play game services to deliver new gaming experiences for their users.
+
+@jd:body
+
+<p>One of the goals of <a href="https://developers.google.com/games/">Google
+Play game services</a> is to allow developers to focus on what they’re good at
+as game developers &mdash; creating great gaming experiences for their users, by
+building on top of what Google is good at: mobile and cloud services. Integral
+to that is an easy integration process, one that provides a whole host of
+features with little engineering work required.</p>
+
+<p>The gaming studios below understood the opportunity that Google Play game
+services unlocked, and are starting to see real results following their
+successful integrations. </p>
+
+<div style="margin-bottom:2em;"><!-- START STORY -->
+
+<h3>Concrete Software &mdash;  Straightforward, easy to implement</h3>
+
+<img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+  -moz-border-radius: 5px;
+  border-radius: 5px height:78px;
+  width: 78px;
+  float: left;
+  margin: 12px 20px 9px 20px;"
+  src="http://lh6.ggpht.com/_UOay5HBxf077suKYzmikU2IbnYOJub3X0inz-LoUsVh4TX758BEyArjoR7owXijkAA=w124">
+
+<div style="list-style: none;height:100%;
+  float: right;
+  border-top: 1px solid #9C0;
+  width: 220px;
+  margin: 4px 20px;padding: .5em;">
+  
+  <h5>About the developer</h5> 
+    <ul>
+      <li><a href="https://play.google.com/store/apps/developer?id=Concrete%20Software%2C%20Inc.">Concrete Software</a>, 
+      makers of <a href="https://play.google.com/store/apps/details?id=com.concretesoftware.pbachallenge_androidmarket&hl=en">PBA
+      Bowling Challenge</a></li>
+      <li>Added support for multiplayer, leaderboards and achievements through Google Play game
+      services</li>
+    </ul>
+
+    <h5>Results</h5> 
+    <ul>
+      <li>Session lengths have increased more than 15%</li>
+    </ul>
+    
+    <div style="padding:.5em 0 0 1em;">
+      <a href="https://play.google.com/store/apps/details?id=com.concretesoftware.pbachallenge_androidmarket&hl=en">
+       <img alt="Android app on Google Play" src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
+      </a>
+    </div>
+</div>
+
+<div style="line-height:1.4em;">
+<p style="margin-top:0;margin-bottom:12px;">Concrete Software added several
+features from Google Play game services into one of their top titles,
+<a href="https://play.google.com/store/apps/details?id=com.concretesoftware.pbachallenge_androidmarket">PBA
+Bowling Challenge</a>, including support for multiplayer, leaderboards, and
+achievements.</p>
+
+<p>So far, their users have loved the new additions: average session length
+is up more than 15%. Keith Pichelman, CEO of Concrete Software, explains: </p>
+
+<p>"The Google Play game services were straightforward and easy to implement. We
+had been researching options for multiplayer services, so when Google Play game
+services came out, it was an easy decision for us. Not only were they easy to
+integrate, but the features have worked flawlessly. </p>
+
+<p>"PBA Bowling Challenge now has real-time multiplayer which our users instantly
+were thrilled with; you can see in the reviews how people immediately raved about
+the new game experience. </p>
+
+<p>"We also included achievements, leaderboards, and most recently cloud
+synchronization from the Google Play game services as well. Using the game
+services in PBA Bowling Challenge was a huge success, enough so that we are now
+going back to our other titles, adding the features to them as well."</p>
+</div>
+
+<div style="clear:both;margin-top:40px;width:auto;">
+  
+  <img src="{@docRoot}images/distribute/concrete-pbc-gpgames.jpg">
+
+  <div style="width:600px;margin-top:0px;padding:0 90px;">
+    <p class="image-caption"><span style="font-weight:500;">Session lengths up:</span>
+    After adding support for multiplayer with Google Play game services, Concrete
+    Software saw an increase in session lengths of more than 15% for PBA Bowling
+    Challenge.</p>
+  </div>
+</div>
+</div> <!-- END STORY -->
+
+<div style="margin:3em auto"><!-- START STORY -->
+
+<h3>Glu: It’s a must-have for all titles</h3>
+
+<img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+  -moz-border-radius: 5px;
+  border-radius: 5px height:78px;
+  width: 78px;
+  float: left;
+  margin: 12px 20px 30px 20px;"
+  src="http://lh4.ggpht.com/Q7mQJsdhulW4_s039R9aaRhQkGnyzLkhF00j5EnyhHOivijnyi7P7b5A8qG0xk1r-jQ=w124">
+          
+<div style="list-style: none;height:100%;
+  float: right;
+  border-top: 1px solid #9C0;
+  width: 220px;
+  margin: 4px 20px;padding: .5em;">
+
+  <h5>About the developer</h5> 
+    <ul>
+      <li><a href="https://play.google.com/store/apps/developer?id=Glu+Mobile">Glu
+      Mobile</a>, creators of <a href="https://play.google.com/store/apps/details?id=com.glu.ewarriors2">Eternity
+      Warriors 2</a></li>
+      <li>Has already integrated 5 titles with Google Play game services</li>
+    </ul>
+
+  <h5>Results</h5> 
+    <ul>
+      <li>In Eternity Warriors 2, 7-day user retention is up 40%</li>
+      <li>20% increase in play sessions per day as well</li>
+    </ul>
+
+    <div style="padding:.5em 0 0 1em;">
+      <a href="https://play.google.com/store/apps/details?id=com.glu.ewarriors2">
+        <img alt="Android app on Google Play" src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
+      </a>
+    </div>
+</div>
+
+<div style="line-height:1.4em;">
+<p style="margin-top:0;margin-bottom:12px;">Glu was one of the first developers
+to integrate Google Play game services, with
+<a href="https://play.google.com/store/apps/details?id=com.glu.ewarriors2">Eternity
+Warriors 2</a>. Based on this first success, Glu has integrated game services
+into several more games, including Samurai vs. Zombies 2, Frontline Commando:
+D-Day, Contract Killer 2, and Zombies Ate My Friends.</p>
+
+<p>Already supported in Eternity Warriors 2, they’ve seen a 40% increase in 7-day
+user retention and a 20% increase in play sessions per day. Sourabh Ahuja, Glu's
+Vice President of Android Development, explains:</p>
+
+<p>“Multiplayer, leaderboards, achievements &mdash; these are all things that we
+had to build individually for our titles. The availability of these features in
+Google Play game services helps us make our games stickier, and it’s awesome that
+it comes directly from Google. </p>
+
+<p>"It’s flexible enough that we were able to make it interoperable with our
+in-house systems. We look forward to utilizing game services extensively across
+our portfolio."</p>
+</div>
+
+<div style="clear:both;margin-top:40px;width:auto;">
+
+  <img src="{@docRoot}images/distribute/glu-ew-gpgames.jpg"></a>
+
+  <div style="width:600px;margin-top:0px;padding:0 90px;">
+    <p class="image-caption"><span style="font-weight:500;">User retention up:</span>
+    Glu saw a 40% increase in 7-day user retention for Eternity Warriors 2 after
+    integrating with Google Play game services.</p>
+  </div>
+</div>
+</div> <!-- END STORY -->
+
+
+<div style="margin-bottom:2em;"><!-- START STORY -->
+
+<h3>Vector-Unit: An awesome multiplayer experience</h3>
+
+<img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+  -moz-border-radius: 5px;
+  border-radius: 5px height:78px;
+  width: 78px;
+  float: left;
+  margin: 12px 20px 9px 20px;" src=
+  "http://lh3.ggpht.com/dTUrKLffqXHJtPuIlp8fjDhROuzrTcpidbNFprugR65hMrPLX7Omd8SGop0xMXXKzcw=w124">
+  
+<div style="list-style: none;height:100%;
+  float: right;
+  border-top: 1px solid #9C0;
+  width: 220px;
+  margin: 4px 20px;padding: .5em;">
+  
+  <h5>About the developer</h5> 
+    <ul>
+      <li><a href="https://play.google.com/store/apps/developer?id=Vector+Unit">Vector
+      Unit</a>, creators of <a href="https://play.google.com/store/apps/details?id=com.vectorunit.red">Riptide
+      GP2</a></li>
+      <li>Added multiplayer to Riptide GP2 through Google Play game services </li>
+    </ul>
+
+  <h5>Results</h5> 
+    <ul>
+      <li>With an easy multiplayer solution, they were able to focus on the
+      gameplay</li>
+      <li>Early reviews of Riptide GP2 called multiplayer “one of the sweetest
+      cherries on top!”</li>
+    </ul>
+
+  <div style="padding:.5em 0 0 1em;">
+    <a href="https://play.google.com/store/apps/details?id=com.vectorunit.red">
+      <img alt="Android app on Google Play" src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
+    </a>
+  </div>
+</div>
+
+<div style="line-height:1.4em;">
+<p style="margin-top:0;margin-bottom:12px;">Vector Unit just launched their
+latest title, <a href="https://play.google.com/store/apps/details?id=com.vectorunit.red">Riptide
+GP2</a>, with Google Play game services integration, and it has one of the strongest
+integrations of multiplayer yet. Early reviews call multiplayer “one of the sweetest
+cherries on top!”.</p>
+
+<p>Ralf Knoesel, CTO of Vector Unit, tells more about how they've used Google Play game
+services:</p>
+    
+<p>“We wanted to provide a really compelling multiplayer experience for our users, and
+Google Play game services allowed us to do just that. With multiplayer, you can show off
+your skills and your custom-tuned hydro jet in 4-way online battles with friends and
+players around the world. </p>
+
+<p>"By providing an easy way to power this multiplayer experience, we were able to focus
+on making the gameplay come alive &mdash; like the stunts, which are more daring and
+slicker than ever (with more of them to master), or the realistic detail of the water
+splashing against the camera lens.”</p>
+
+</div>
+
+<div style="clear:both;margin-top:40px;width:auto;">
+  
+  <img src="{@docRoot}images/distribute/vector-unit-rt-gpgames.jpg"></a>
+
+  <div style="width:600px;margin-top:0px;padding:0 90px;">
+    <p class="image-caption"><span style="font-weight:500;">Multiplayer and more:</span>
+    Google Play game services helped Vector Unit pack an awesome multiplayer experience
+    into Riptide GP 2, so they could focus on building a great gaming experience.</p>
+  </div>
+</div>
+</div> <!-- END STORY -->
+
+
+
diff --git a/docs/html/distribute/stories/index.jd b/docs/html/distribute/stories/index.jd
new file mode 100644
index 0000000..ca7647d
--- /dev/null
+++ b/docs/html/distribute/stories/index.jd
@@ -0,0 +1,13 @@
+page.title=Developer Stories
+section.landing=true
+page.metaDescription=Android developers, their apps, and their successes with Android and Google Play.
+
+@jd:body
+
+<p>Android developers, their apps, and their successes with Android and Google Play.</p>
+
+<div class="resource-widget resource-flow-layout col-13"
+    data-query="type:youtube+tag:developerstory"
+    data-sortOrder="-timestamp"
+    data-cardSizes="18x12"
+    data-maxResults="32"></div>
diff --git a/docs/html/distribute/stories/localization.jd b/docs/html/distribute/stories/localization.jd
new file mode 100644
index 0000000..d6e6ccf
--- /dev/null
+++ b/docs/html/distribute/stories/localization.jd
@@ -0,0 +1,330 @@
+page.title=Developer Stories: Localization in Google Play
+meta.tags="google play, developer story, localization, global"
+page.tags="stories", "video", "case study"
+page.image=/images/distribute/zombie-ragdoll-n5-land.jpg
+page.metaDescription=Hear from Android developers who have successfully used the Google Play App Translation Service.
+
+@jd:body
+
+<p>
+  As you build your app and distribute it across the world through Google Play,
+  localization becomes an increasingly important tool to reach more users.
+  Localization involves a <a href=
+  "{@docRoot}distribute/googleplay/publish/localizing.html">variety of tasks</a>, but
+  most important is creating quality translations of your app's UI strings and
+  marketing materials.
+</p>
+
+<p>
+  Managing the translation process across multiple languages can be a
+  challenge, especially if you need to locate translators on your own. That’s
+  why Google Play offers the App Translation Service right from the Developer
+  Console. It's a single place where you can go to source professional
+  translators, get cost estimates, and then send your strings and other
+  materials for translation.
+</p>
+
+<p>
+  Here are some stories from developers who have used Google Play's App Translation
+  Service to localize their apps and the results they've seen as they've
+  expand their offerings beyond a single language.
+</p>
+
+<!-- START STORY -->
+
+<div style="margin-bottom:2em;padding-top:10px;" id="zombieragdoll">
+
+<h3 style="line-height:1.25em">Zombie Ragdoll: Improved user engagement<br /> with localized versions</h3>
+
+  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+            -moz-border-radius: 5px;
+            border-radius: 5px height:78px;
+            width: 78px;
+            float: left;
+            margin: 12px 20px 9px 20px;" src=
+            "https://lh4.ggpht.com/m-Ew8c8C_nGctbP6PSPGOaVNnGFryReOE2yHXJ9Z6Prk1nsDyx5w5TmWfg-P5N3HypA=w124">
+
+  <div style="list-style: none;height:100%;
+  float: right;
+  border-top: 1px solid #9C0;
+  width: 220px;
+  margin: 4px 20px;padding: .5em;">
+
+    <h5>About the app</h5>
+
+    <ul>
+      <li><a href="https://play.google.com/store/apps/details?id=com.rvappstudios.zombieragdoll">Zombie Ragdoll</a></li>
+      <li>A fun zombie-based physics game</li>
+    </ul>
+
+    <h5>Localization Results</h5>
+
+    <ul>
+      <li>Increased engagement because of appeal of the localized version</li>
+      <li>80% of installs came from users of non-English languages</li>
+      </ul>
+
+    <div style="padding:.5em 0 0 1em;">
+      <a href="https://play.google.com/store/apps/details?id=com.rvappstudios.zombieragdoll">
+        <img alt="Android app on Google Play"
+         src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
+      </a>
+
+    </div>
+  </div>
+
+  <div style="line-height:1.4em;">
+
+<p>
+  The 2013 Google I/O talks about <a href=
+  "https://developers.google.com/events/io/sessions/326345917">Building Android
+  Apps for a Global Audience</a> and <a href=
+  "https://developers.google.com/events/io/sessions/326455375">What’s New for
+  Developers in Google Play</a> inspired developers at RV AppStudios to go global
+  from very beginning for their new game, Zombie Ragdoll. They launched Zombie
+  Ragdoll in August 2013, localized into 20 languages.
+</p>
+
+<p>
+  They quickly saw the impact of their decision to ship simultaneously in
+  multiple languages through increased non-English installs and improved
+  engagement with users worldwide. In addition, they started getting
+  significant usage in countries where their apps had not been as popular
+  before. They are seeing great traction in countries like Vietnam, Russia,
+  Philippines and Thailand.
+</p>
+
+<p>
+  Vivek Dave, founder of RV AppStudios, credits the success of Zombie Ragdoll
+  to localization:
+</p>
+
+<p>
+  "The value of localization is clear, it helps discoverability and helps
+  connect with the users in other countries. So when the localization
+  opportunity arose, we immediately jumped on it. Android is worldwide, and we
+  would be severely limiting ourselves if we focused on English as the only
+  language.
+</p>
+
+<p>
+  "The App Translation Service offered in the Google Play Developer Console is
+  extremely easy to use and the pricing is very attractive. Developers with
+  limited localization experience can easily create, upload, and translate
+  their app."
+</p>
+
+
+<p>
+  RV AppStudios not only localizes the text within the game, but also localizes
+  the game assets to a specific country/culture. Dave says, “Users want a
+  personalized experience, and by offering a localized game with translation of
+  text and graphic assets, we believe users will connect at a much deeper level
+  with the game.”
+</p>
+
+
+  <div style="margin-top:8px;float:left;margin-right:24px;">
+    <img src="{@docRoot}images/distribute/zombie-ragdoll-n5-land.jpg" style="width:470px;">
+  </div>
+
+
+    <div style="margin-top:128px;">
+      <p class="img-caption"><strong>Hindi version of Zombie Ragdoll</strong>:
+      Localized screenshots and videos in the app's Google Play listing go a
+      long way toward increasing the number of installs.</p>
+    </div>
+
+  </div>
+
+</div> <!-- END STORY -->
+
+<!-- START STORY -->
+
+<div style="margin-bottom:2em;padding-top:18px;clear:both;" id="sayhichat">
+
+<h3>SayHi Chat: Install growth and user engagement<br />
+  from professional translations</h3>
+
+  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+            -moz-border-radius: 5px;
+            border-radius: 5px height:78px;
+            width: 78px;
+            float: left;
+            margin: 12px 20px 9px 20px;" src=
+            "https://lh5.ggpht.com/qiL6CF1Hktz618T3mbGrxvm_OoeheQ78FgG7zr90C2MCRiz4IDQsbKuHT4xQGiWEU8o=w124">
+
+  <div style="list-style: none;height:100%;
+  float: right;
+  border-top: 1px solid #9C0;
+  width: 220px;
+  margin: 4px 20px;padding: .5em;">
+
+    <h5>About the app</h5>
+
+    <ul>
+      <li><a href="https://play.google.com/store/apps/details?id=com.unearby.sayhi">SayHi Chat,
+      Love, Meet, Dating</a></li>
+      <li>A social app to help you find people nearby</li>
+    </ul>
+
+    <h5>Localization Results</h5>
+
+    <ul>
+      <li>120% growth in language installs for new languages added</li>
+      <li>~20% increase in revenue and ~50% increase in User Reviews in the new
+        languages</li>
+      </ul>
+
+    <div style="padding:.5em 0 0 1em;">
+      <a href="https://play.google.com/store/apps/details?id=com.unearby.sayhi">
+        <img alt="Android app on Google Play"
+         src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
+      </a>
+
+    </div>
+  </div>
+
+  <div style="line-height:1.4em;">
+
+<p>
+  The SayHi Chat app started out only in Japanese, Chinese and English. It soon
+  became one of the most popular apps in Japan, Hong Kong, and Taiwan. The
+  SayHi team realized it was time to launch in more languages, as the language
+  barrier was restricting how fast SayHi could grow globally. </p>
+
+  <p>Yan Shi, senior
+  developer at SayHi, says: "We checked Google Analytics for our DAU and user
+  growth numbers in each country, we also looked at total Android and iOS users
+  in those markets before finalizing our next set of languages.
+</p>
+
+  <div style="margin-top:8px;float:left;width:270px;">
+    <img src="{@docRoot}images/distribute/hichat-n5-port.jpg" style="width:240px;margin-right:48px;">
+  </div>
+
+<p>
+  SayHi used the App Translation Service to launch in 13 additional languages
+  in August 2013 and immediately saw 120% increase in install rates. In
+  addition, they are seeing their app ranked in Top 10 apps in countries like
+  Poland and Italy.
+</p>
+
+<p>Notably, they saw steady growth in Spain after replacing their previous
+  non-professional Spanish translation with a professional one produced through
+  the App Translation Service.</p>
+
+<p>
+  Yan Shi adds, “The App Translation Service is really easy to use and
+  the completion time for translation requests is very good.”
+</p>
+
+    <div style="width:600px;margin-top:98px;padding:0;">
+      <p class="img-caption"><strong>Arabic version of SayHi Chat</strong>:
+        User engagement increased significantly with
+        the localized version.</p>
+    </div>
+
+  </div>
+</div> <!-- END STORY -->
+
+
+<div style="margin-bottom:2em;clear:both;padding-top:18px;" id="g4a"><!-- START STORY -->
+
+<h3 style="line-spacing:1.25em;">G4A Indian Rummy: Benefitting from ease-of-use and<br /> fast turnaround time</h3>
+
+  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+            -moz-border-radius: 5px;
+            border-radius: 5px height:78px;
+            width: 78px;
+            float: left;
+            margin: 12px 20px 9px 20px;" src=
+            "https://lh4.ggpht.com/IxSyQgO0LWzPRoLfCrER06-0kr6aMAa2azF7eNYB30EBZAGOLYJUZulknPockbTlDYU=w124">
+
+  <div style="list-style: none;height:100%;
+  float: right;
+  border-top: 1px solid #9C0;
+  width: 220px;
+  margin: 4px 20px;padding: .5em;">
+
+    <h5>About the app</h5>
+
+    <ul>
+      <li><a href="https://play.google.com/store/apps/details?id=org.games4all.android.games.indianrummy.prod">G4A Indian Rummy</a></li>
+      <li>A card game in which the players try to form sets and sequences of cards</li>
+    </ul>
+
+    <h5>Localization Results</h5>
+
+    <ul>
+      <li>Double the number of users in French and German languages</li>
+      <li>300% increase in user engagement with localized version</li>
+      </ul>
+
+    <div style="padding:.5em 0 0 1em;">
+      <a href="https://play.google.com/store/apps/details?id=com.rvappstudios.zombieragdoll">
+        <img alt="Android app on Google Play"
+         src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
+      </a>
+    </div>
+  </div>
+
+  <div style="line-height:1.4em;">
+
+<p>
+  Games4All (G4A) is the developer of Indian Rummy and a variety of games that
+  they distribute broadly to users around the world. After noticing that
+  certain apps had become especially popular in specific countries, they
+  decided to localize those apps. Initially they used a local agency to do
+  the translation and got great results &mdash; the number of users in
+  that language increased tremendously when they released the localized
+  version.
+</p>
+
+<p>
+  Building on that success, G4A expanded their localization goals but
+  found that translation quality varied across their vendors and costs limited the
+  language/game combinations they could try. That's when G4A decided to try the
+  App Translation Service.
+</p>
+
+<p>
+  Founder Pieter Olivier says, "When we heard that the App Translation
+  Service was available in the Developer Console, we jumped at the opportunity.
+  We've now been using the App Translation Service for several months and found
+  that the cost per translation is much lower than with local companies and the
+  process is much easier."
+</p>
+
+<p>So far, G4A has translated the game Indian Rummy into five languages through
+   the App Translation Service.</p>
+
+<p>
+  Olivier continues, "The first thing we did was convert all of our texts into
+  the strings.xml format. After that using the service was extremely easy and
+  straightforward. In contrast, our previous experiences with translation
+  agencies were much more difficult: files often required extensive conversion
+  operations to make them usable, and turnaround times varied wildly.
+</p>
+
+<p>
+  "With the App Translation Service, the turnaround time is usually measured in
+  days instead of weeks that we were used to with traditional translation
+  agencies."
+</p>
+
+  <div style="margin-top:14px;float:left;margin-right:24px;">
+    <img src="{@docRoot}images/distribute/indian-rummy-n4-land.jpg" style="width:470px;">
+  </div>
+
+    <div style="margin-top:158px;">
+      <p class="img-caption"><strong>Dutch
+      version of Indian Rummy</strong>: Making slight changes to games rules based on
+      local nuances was key to success of the game.</p>
+    </div>
+
+  </div>
+
+
+
+</div> <!-- END STORY -->
\ No newline at end of file
diff --git a/docs/html/distribute/stories/stories_toc.cs b/docs/html/distribute/stories/stories_toc.cs
new file mode 100644
index 0000000..944dabe
--- /dev/null
+++ b/docs/html/distribute/stories/stories_toc.cs
@@ -0,0 +1,34 @@
+<ul id="nav">
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/stories/index.html">
+            <span class="en">Videos</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/stories/localization.html">
+            <span class="en">Going Global</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/stories/games.html">
+            <span class="en">Games</span>
+          </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/stories/tablets.html">
+          <span class="en">Tablets</span>
+        </a>
+    </div>
+  </li>
+
+</ul>
+
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
+
diff --git a/docs/html/distribute/stories/tablets.jd b/docs/html/distribute/stories/tablets.jd
new file mode 100644
index 0000000..771fa52
--- /dev/null
+++ b/docs/html/distribute/stories/tablets.jd
@@ -0,0 +1,368 @@
+page.title=Developer Stories: The Opportunity of Android Tablets
+meta.tags="google play, developer story, journal, tablets, pure"
+pdage.metaDescription=Developers are investing in a full tablet experience for their apps and seeing those investments pay off big.
+page.image=/images/distribute/rememberthemilk.png
+
+@jd:body
+
+
+<p>"More" and more, developers are investing in a full tablet experience
+for their apps and are seeing those investments pay off big. The increased
+screen area on tablets opens up a world of possibilities, allowing for more
+engagement with the user &mdash; which can mean an increase in usage as well as
+more monetization opportunities. And with the growing wave of Android tablets that
+continue to hit the market, it’s an important piece of any developer’s mobile
+offering. </p>
+
+<p>Here are some stories from developers who are seeing real results as they
+expand their offering to include Android tablets.</p>
+
+
+<div style="margin-bottom:2em;" id="rememberthemilk"><!-- START STORY -->
+
+<h3>Remember The Milk: Lifting installs with tablet design</h3>
+
+  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+            -moz-border-radius: 5px;
+            border-radius: 5px height:78px;
+            width: 78px;
+            float: left;
+            margin: 12px 20px 9px 20px;" src=
+            "http://lh3.ggpht.com/xmnal18taauP2mjQFEhr1PhcItQ_W32IRuaD86IoL2U_4E-mfeKiliKtkISgOuA6Ln9n=w124">
+          
+  <div style="list-style: none;height:100%;
+  float: right;
+  border-top: 1px solid #9C0;
+  width: 220px;
+  margin: 4px 20px;padding: .5em;">
+  
+
+    <h5>About the app</h5> 
+    
+    
+    <ul>
+      <li><a href="http://play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">Remember The Milk</a></li>
+      <li>A feature-packed to-do list app; never forget the milk (or anything else) again</li>
+    </ul>
+
+    <h5>Tablet Results</h5> 
+
+    <ul>
+      <li>83% jump in tablet installs following update </li>
+      <li>Nexus 7 is most popular Android device for app </li>
+      <li>Single APK for phones and tablets</li>
+      </ul>
+    
+    <div style="padding:.5em 0 0 1em;">
+      <a href="http://play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">
+        <img alt="Android app on Google Play"
+         src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
+      </a>
+      
+    </div>
+  </div>
+
+  <div style="line-height:1.4em;">
+    <p style="margin-top:0;margin-bottom:12px;">When the Android tablet guidelines
+      came out in 2012, the team at Remember The Milk had already been thinking about
+      a redesign for their <a href="http://play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">feature-packed
+      to-do list app</a>. Omar Kilani, Co-founder of Remember The Milk, explains how
+      <a href="http://blog.rememberthemilk.com/2013/04/the-all-new-remember-the-milk-for-android-and-tablets-too/">updating</a>
+      their app to meet the tablet guidelines lead to an 83% jump in tablet installs: </p>
+
+    <p>“We took this as an opportunity to think about how we were going to approach
+      Android tablets differently from a user experience perspective. The guidelines
+      were a helpful resource, and with the extra screen real estate tablets afford,
+      users have the opportunity to see all of their data in context and drill down
+      on more items. All of this is accomplished using a single APK on Play, even though
+      the phone and tablet versions each capture completely different use cases for us.”</p>
+
+    <p>“In the month after updating, we saw our tablet installs on Google Play jump 83%,
+      and the Nexus 7 is now the most popular Android device amongst our users. For us,
+      designing for tablets was an investment that has really paid off.”</p>
+
+    <p>The team also came out with a number of other goodies &mdash; including a new set of
+      widgets and richer notifications, and more ways to provide an immersive experience
+      for their users.</p>
+  </div>
+
+  <div style="clear:both;margin-top:30px;width:auto;">
+  
+    <img src="{@docRoot}images/distribute/rememberthemilk.png">
+
+    <div style="width:600px;margin-top:0px;padding:0 90px;">
+      <p class="image-caption"><span style="font-weight:500;">Tablet redesign led to lift
+      in installs</span>: Following the redesign of the Android app, in part to meet the tablet
+      design criteria, Remember The Milk saw an 83% increase in tablet installs.</p>
+    </div>
+
+  </div>
+
+</div> <!-- END STORY -->
+
+
+<div style="margin-bottom:2em;" id="mint"><!-- START STORY -->
+
+<h3>Mint: More screen real estate = more engagement</h3>
+
+  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+            -moz-border-radius: 5px;
+            border-radius: 5px height:78px;
+            width: 78px;
+            float: left;
+            margin: 12px 20px 9px 20px;" src=
+            "https://lh5.ggpht.com/0xAIZJ1uE05b4RHNHgBBTIH6nRdPTY660T104xY7O2GbHXwab6YVmpU5yYg8yacfBg=w124">
+          
+  <div style="list-style: none;height:100%;
+  float: right;
+  border-top: 1px solid #9C0;
+  width: 220px;
+  margin: 4px 20px;padding: .5em;">
+  
+
+    <h5>About the app</h5> 
+    
+    
+    <ul>
+ <li><a href="http://play.google.com/store/apps/details?id=com.mint">Mint.com Personal Finance</a> by Intuit Inc.</li>
+      <li>Financial management app targeting 7- to 10-inch tablets and phones</li>
+    </ul>
+
+    <h5>Tablet Results</h5> 
+
+    <ul>
+      <li>Able to offer richer UI features</li>
+      <li>Much higher user engagement</li>
+      <li>Longer sessions &mdash; more Android tablet users have sessions longer than 5 minutes</li>
+      </ul>
+    
+    <div style="padding:.5em 0 0 1em;">
+<a href="http://play.google.com/store/apps/details?id=com.mint">
+  <img alt="Android app on Google Play"
+       src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
+</a>
+      
+    </div>
+  </div>
+
+  <div style="line-height:1.4em;">
+    <p style="margin-top:0;margin-bottom:12px;">When Intuit was thinking about
+expanding their Mint mobile offering to include a version optimized for Android
+tablets, they knew that taking the layout that worked for phones and simply
+showing an enlarged version wouldn’t take full advantage of the opportunities
+that tablets afford.</p>
+    
+    <p>“We knew we had a lot more real estate, and we wanted to provide a more
+immersive experience for our users” said Ken Sun, Intuit Group Product Manager
+at Mint.</p>
+
+<p>Intuit’s Mint app, which has a 4-star rating on Google Play, brings a number
+of features to Android tablets that aren’t available for phones, including a
+more visual presentation of personal financial data.</p>
+
+<p>“Whereas our app for phones is used throughout the day for quick sessions,
+we’ve seen a larger percentage of our tablet usage happen in the evening, for
+much longer sessions,” said Sun. “People are doing a lot more than just checking
+their spending. They’re looking at historical trends, re-categorizing
+transactions, analyzing the data and setting financial goals for the future
+&mdash; digging much deeper and being more thoughtful. One example is how much
+users are interacting with their own budgets in the tablet app.  Customer budget
+operations (view, edit, drill-down, etc.) are 7x higher on Android tablets than
+they are on phones.”</p>
+
+<p>Fifty percent more Android tablet users have Mint sessions of 5 minutes or
+longer than they do on phones.  “We’ve found that phone usage is indicative of a
+customer’s regular financial check-in, while tablet usage points towards more
+analysis and interaction with that customer’s personal financial data.  This is
+the sort of immersive engagement experience we were looking for; the tablet and
+phone apps serve as great complements to each other."</p>
+  </div>
+
+  <div style="clear:both;margin-top:40px;width:auto;">
+  
+    <img src="{@docRoot}images/distribute/mint.png">
+
+    <div style="width:600px;margin-top:0px;padding:0 90px;">
+      <p class="image-caption"><span style="font-weight:500;">Making the most of tablet screens</span>: Mint used the extra screen area on tablets to offer quick access to additional tools and information.</p>
+    </div>
+
+  </div>
+
+</div> <!-- END STORY -->
+
+
+<div style="margin:3em auto"><!-- START STORY -->
+
+
+<h3>TinyCo: Monetization opportunities abound on tablets</h3>
+
+  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+            -moz-border-radius: 5px;
+            border-radius: 5px height:78px;
+            width: 78px;
+            float: left;
+            margin: 12px 20px 30px 20px;" src=
+            "https://lh6.ggpht.com/QTy7lOGRTS58NW4XEeym2sxpWKDmRNod_n3kBrHlqTRIyzIv2gkw8DfwiR4GIAdxiHw=w124">
+
+          
+  <div style="list-style: none;height:100%;
+  float: right;
+  border-top: 1px solid #9C0;
+  width: 220px;
+  margin: 4px 20px;padding: .5em;">
+
+    <h5>About the app</h5> 
+
+    <ul>
+                <li><a href="http://play.google.com/store/apps/details?id=com.tinyco.village">Tiny Village</a> by TinyCo</li>
+            <li>Game targeting 7- to 10-inch tablets and phones</li>
+    </ul>
+
+    <h5>Tablet Results</h5> 
+
+    <ul>
+      <li>35% higher average revenue per paying user (ARPPU)</li>
+      <li>Consistent increase in user retention</li>
+      <li>3x increase in downloads to Android tablets in the last 6 months</li>
+    </ul>
+    
+    <div style="padding:.5em 0 0 1em;">
+<a href="http://play.google.com/store/apps/details?id=com.tinyco.village">
+  <img alt="Android app on Google Play"
+       src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
+</a>
+      
+    </div>
+  </div>
+
+  <div style="line-height:1.4em;">
+    <p style="margin-top:0;margin-bottom:12px;">
+    
+<p>Over a year ago, app developer TinyCo, makers of a suite of games such as
+Tiny Monsters, decided to prioritize launching across multiple platforms
+effectively. They chose Android as one of their primary launch platforms because
+of its large installed base and global reach. They also knew that the growing
+base of Android tablet users represented a huge opportunity.</p>
+    
+    <p>Tiny Village was their first title to take advantage of the strategy, and
+it proved to be a winning one &mdash; especially in terms of Android
+tablets.</p>
+    
+    <p> “With continued optimization of the gameplay experience and a genuine
+commitment to our Android offering through our Griffin engine, all of our
+metrics started to rise,” said Rajeev Nagpal, Head of Product at TinyCo. In
+fact, they’ve seen Android tablet downloads more than triple in the last six
+months.</p>
+
+    <p>One of the first things they noticed about usage of Tiny Village on
+tablets was an increase in average revenue per paying user (ARPPU)&mdash;about 35%
+higher than on smaller-screen devices such as phones. Additionally, average
+revenue per user ARPU is now about 35% higher as well. “The game is just much
+more immersive on tablet.”</p>
+
+    <p>In addition to an increase in monetization metrics, they’ve also seen a
+consistent increase in retention over other platforms. “These are really
+important metrics for games &mdash; if you can get users to both stay around
+longer and spend more while they’re there, you have a recipe for success.”</p>
+  </div>
+
+  <div style="clear:both;margin-top:40px;width:auto;">
+  
+    <img src="{@docRoot}images/distribute/tinyvillage.png">
+
+    <div style="width:600px;margin-top:0px;padding:0 90px;">
+      <p class="image-caption"><span style="font-weight:500;">More monetization
+on tablets</span>: On Android tablets TinyCo has seen higher ARPPU and user
+retention than on phones.</p>
+    </div>
+
+  </div>
+
+</div> <!-- END STORY -->
+
+
+<div style="margin-bottom:2em;"><!-- START STORY -->
+
+<h3>Instapaper: Riding the growing wave of Android tablets</h3>
+
+
+  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+            -moz-border-radius: 5px;
+            border-radius: 5px height:78px;
+            width: 78px;
+            float: left;
+            margin: 12px 20px 9px 20px;" src=
+            "https://lh3.ggpht.com/30KKcrIFO8V_wRfhnHaI9l0CLH_orIVFE7Xywtr9TBxAf0hi2BaZkKyBOs63Yfavpg=w124">
+
+          
+  <div style="list-style: none;height:100%;
+  float: right;
+  border-top: 1px solid #9C0;
+  width: 220px;
+  margin: 4px 20px;padding: .5em;">
+  
+  
+  
+
+    <h5>About the app</h5> 
+    <ul>
+                <li><a href="http://play.google.com/store/apps/details?id=com.instapaper.android">Instapaper</a> by Mobelux</li>
+      <li>Content-browsing utility that targets 7- to 10-inch tablets and phones</li>
+    </ul>
+
+    <h5>Tablet Results</h5> 
+
+    <ul>
+      <li>Tablets are now 50% of the app's installed base.</li>
+    </ul>
+    
+    <div style="padding:.5em 0 0 1em;">
+<a href="http://play.google.com/store/apps/details?id=com.instapaper.android">
+  <img alt="Android app on Google Play"
+       src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
+</a>
+      
+    </div>
+  </div>
+
+  <div style="line-height:1.4em;">
+    <p style="margin-top:0;margin-bottom:12px;">Instapaper for Android is an app
+for saving web content to read later. Developer Mobelux decided that creating a
+great UI for Android tablet users would be an essential part of their initial launch
+plan.</p>
+    
+    <p>The app launched at the beginning of the summer of 2012, just in time to
+take advantage of a new tide of Android tablets, including the <span
+style="white-space:nowrap;">Nexus 7</span> tablet. The app has since seen huge
+popularity among tablet users, in particular, on Nexus 7. On the day that
+pre-orders of Nexus 7 began arriving, Mobelux saw a 600% jump in downloads of
+its app on Google Play.</p>
+
+    <p>“We saw a promising new set of Android tablets about to hit the market
+and wanted to position ourselves to be ready for them” said Jeff Rock of
+Mobelux. “It was a market that others were hesitant to explore, but the decision
+to prioritize tablets has paid off very well for us.”</p>
+
+    <p>Since that initial 600% jump in downloads, Instapaper for Android has
+continued to see a successful run on Android tablets. In fact, Android tablets
+now represent about 50% of their installed base. “With more and more Android
+tablets coming online, we’re excited to see how our investment in Android
+tablets continues to pay off.”</p>
+  </div>
+
+  <div style="clear:both;margin-top:40px;width:auto;">
+  
+    <img src="{@docRoot}images/distribute/instapaper.png">
+
+    <div style="width:600px;margin-top:0px;padding:0 90px;">
+      <p class="image-caption"><span style="font-weight:500;">Popular with
+tablet users</span>: A great tablet UI and browsing convenience make Instapaper
+popular with Android tablet users.</p>
+    </div>
+
+  </div>
+
+</div> <!-- END STORY -->
+
+
+
diff --git a/docs/html/distribute/tools/disttools_toc.cs b/docs/html/distribute/tools/disttools_toc.cs
new file mode 100644
index 0000000..f4f39f0
--- /dev/null
+++ b/docs/html/distribute/tools/disttools_toc.cs
@@ -0,0 +1,46 @@
+<ul id="nav">
+
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/launch-checklist.html">
+            <span class="en">Launch Checklist</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/localization-checklist.html">
+            <span class="en">Localization Checklist</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/promote/device-art.html">
+            <span class="en">Device Art Generator</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/promote/badges.html">
+            <span class="en">Google Play Badges</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/promote/linking.html">
+            <span class="en">Linking to Your Products</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/promote/brand.html">
+            <span class="en">Brand Guidelines</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/open-distribution.html">
+            <span class="en">Alternative Distribution</span></a>
+    </div>
+  </li>
+</ul>
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
+
diff --git a/docs/html/distribute/tools/index.jd b/docs/html/distribute/tools/index.jd
new file mode 100644
index 0000000..c8f0212
--- /dev/null
+++ b/docs/html/distribute/tools/index.jd
@@ -0,0 +1,57 @@
+page.title=Tools &amp; Reference
+section.landing=true
+nonavpage=true
+
+@jd:body
+
+<p>
+  Here you’ll find resources to help you publish your apps and games, acquire
+  users, and monetize your investment.
+</p>
+
+<div class="dynamic-grid">
+
+  <h3>Publishing and Launch</h3>
+  <div class="resource-widget resource-flow-layout landing col-16"
+    data-query="collection:distribute/tools/checklists"
+    data-cardSizes="9x6"
+    data-maxResults="2">
+  </div>
+
+<h3>Marketing Tools</h3>
+  <div class="resource-widget resource-flow-layout landing col-16"
+    data-query="collection:distribute/tools/promote"
+    data-cardSizes="6x6"
+    data-maxResults="3">
+  </div>
+
+  <h3>Developer Support</h3>
+  <div class="resource-widget resource-flow-layout landing col-16"
+    data-query="collection:distribute/tools/support"
+    data-cardSizes="6x6"
+    data-maxResults="3">
+  </div>
+
+  <h3>Developer News</h3>
+  <div class="resource-widget resource-flow-layout landing col-16"
+    data-query="collection:distribute/tools/news"
+    data-cardSizes="9x6"
+    data-maxResults="2">
+  </div>
+
+  <h3>More</h3>
+  <div class="resource-widget resource-flow-layout landing col-16"
+    data-query="collection:distribute/tools/more"
+    data-cardSizes="6x6"
+    data-maxResults="3">
+  </div>
+
+<!--  <h3>Related Resources</h3>
+  <div class="resource-widget resource-stack-layout col-16"
+    data-query="tag:developersupport"
+    data-sortOrder="-timestamp"
+    data-numStacks="3"
+    data-maxResults="6">
+  </div> -->
+
+</div>
diff --git a/docs/html/distribute/tools/launch-checklist.jd b/docs/html/distribute/tools/launch-checklist.jd
new file mode 100644
index 0000000..3b0dd55
--- /dev/null
+++ b/docs/html/distribute/tools/launch-checklist.jd
@@ -0,0 +1,1072 @@
+page.title=Launch Checklist
+page.metaDescription=Essential overview of the complete process of delivering your app to users. Read this checklist early in development to help you plan for a successful launch on Google Play.
+meta.tags="localizing, publishing, disttools"
+page.tags="launch, publishing, Google Play"
+page.image=/distribute/images/launch-checklist.jpg
+
+@jd:body
+
+<div id="qv-wrapper">
+  <div id="qv" style="width:280px">
+    <h2>Checklist</h2>
+    <ol>
+      <li><a href="#understand-publishing">1. Understand the Publishing Process</a></li>
+      <li><a href="#understand-policies">2. Understand Google Play Policies</a></li>
+      <li><a href="#test-quality">3. Test for Core App Quality</a></li>
+      <li><a href="#determine-rating">4. Determine Content Rating</a></li>
+      <li><a href="#determine-country">5. Determine Country Distribution</a></li>
+      <li><a href="#confirm-size">6. Confirm Overall Size</a></li>
+      <li><a href="#confirm-platform">7. Confirm Platform and Screen Ranges</a></li>
+      <li><a href="#decide-price">8. Decide Free or Priced</a></li>
+      <li><a href="#consider-billing">9. Use In-app Billing</a></li>
+      <li><a href="#set-prices">10. Set Prices for your Products</a></li>
+      <li><a href="#start-localization">11. Start Localization</a></li>
+      <li><a href="#prepare-graphics">12. Prepare Promotional Graphics, Screenshots, and Videos</a></li>
+      <li><a href="#build-upload">13. Build the Release-ready APK</a></li>
+      <li><a href="#plan-beta">14. Plan a Beta Release</a></li>
+      <li><a href="#complete-details">15. Complete the Store Listing</a></li>
+      <li><a href="#use-badges">16. Use Google Play Badges and Links</a></li>
+      <li><a href="#final-checks">17. Final Checks and Publishing</a></li>
+      <li><a href="#support-users">18. Support Users after Launch  </a></li>
+    </ol>
+  </div>
+</div>
+
+<div class="top-right-float" style="width:194px"><img
+src="{@docRoot}distribute/images/launch-checklist.jpg"></div>
+
+<p>
+  Before you publish your apps on Google Play and distribute them to users, you
+  need to get the apps ready, test them, and prepare your promotional
+  materials.
+</p>
+
+<p>
+  This page helps you understand the publishing process and get ready for a
+  successful product launch on Google Play. It summarizes some of the tasks
+  you'll need to complete before publishing your app on Google Play, such as
+  creating a signed, release-ready application package (APK), understanding the
+  requirements of the app, and creating the product page and graphic assets for
+  each of your apps.
+</p>
+
+<p>
+  The preparation and publishing tasks are numbered to give you a rough idea of
+  sequence. However, you can handle the tasks in any sequence that works for
+  you or you can skip steps as appropriate.
+</p>
+
+<p>
+  As you move toward publishing, a variety of support resources are available
+  to you. Relevant links are provided in each step.
+</p>
+
+<div class="headerLine">
+  <h1 id="understand-publishing">
+    1. Understand the Publishing Process
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Before you begin the steps in this checklist, you should take a moment to
+  read and understand the overall publishing workflow and become familiar with
+  how the process works. In particular, you or your development team will need
+  to prepare your apps for release using a process common to all Android apps.
+  The <a href="{@docRoot}tools/publishing/publishing_overview.html">Publishing
+  workflow documents</a> provide the details on how publishing works and how to
+  get an APK ready for release.
+</p>
+
+<p>
+  Once you are familiar with publishing in general, continue reading to
+  understand the issues that you should consider when publishing apps on Google
+  Play.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/understanding"
+data-sortorder="-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="understand-policies">
+    2. Understand Google Play Policies and Agreements
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Make sure that you understand and follow the Google Play program policies
+  that you accepted when registering. Google Play actively enforces the
+  policies and any violations can lead to suspension of your apps or, for
+  repeated violations, termination of your developer account.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/policies" data-sortorder=
+"-timestamp" data-cardsizes="6x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="test-quality">
+    3. Test for Quality
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Before you publish apps on Google Play, it's important to make sure that they
+  meet the basic quality expectations for all Android apps, on all of the
+  devices that you are targeting. You can check your app's quality by setting
+  up a test environment and testing the app against a short set of
+  <strong>quality criteria that applies to all apps</strong>. For complete
+  information, see the <a href=
+  "{@docRoot}distribute/essentials/quality/core.html">Core App Quality</a>
+  guidelines.
+</p>
+
+<p>
+  If your app is targeting tablet devices, make sure that it delivers a rich,
+  compelling experience to your tablet customers. See the <a href=
+  "{@docRoot}distribute/essentials/quality/tablets.html">Tablet App Quality</a>
+  guidelines for recommendations on ways to optimize your app for tablets.
+</p>
+
+<p>
+  If you plan to make your apps available to Google Play for Education, then
+  you need to make sure they are suitable for a K-12 classroom and offer
+  outstanding educational value. See the <a href=
+  "{@docRoot}distribute/essentials/gpfe-guidelines.html">Education
+  Guidelines</a> for information on the characteristics your education apps
+  should exhibit.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/quality" data-sortorder=
+"-timestamp" data-cardsizes="6x3,6x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="determine-rating">
+    4. Determine your App’s Content Rating
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Google Play requires you to set a content rating for your app, which informs
+  Google Play users of its maturity level. Before you publish, you should
+  confirm what rating level you want to use. The available content rating
+  levels are:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Everyone
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Low maturity
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Medium maturity
+    </p>
+  </li>
+
+  <li>
+    <p>
+      High maturity
+    </p>
+  </li>
+</ul>
+
+<p>
+  On their Android devices, Android users can set the desired maturity level
+  for browsing. Google Play then filters apps based on the setting, so the
+  content rating you select can affect the app's distribution to users. You can
+  assign (or change) the content rating for your apps in the Developer Console,
+  no changes are required in your app binary.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/rating" data-sortorder=
+"-timestamp" data-cardsizes="9x3,6x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="determine-country">
+    5. Determine Country Distribution
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Google Play lets you control what countries and territories your apps are
+  distributed to. For the widest reach and the largest potential customer base,
+  you’d normally want to distribute to all available countries and territories.
+  However, because of business needs, app requirements, or launch dependencies,
+  you might want to exclude one or more countries from your distribution.
+</p>
+
+<p>
+  It's important to determine the exact country distribution early, because it
+  can affect:
+</p>
+
+<ul>
+  <li>
+    <p>
+      The need for localized resources in the app.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      The need for a localized app description in the Developer Console.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Legal requirements for the app that may be specific to certain countries.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Time zone support, local pricing, and so on.
+    </p>
+  </li>
+</ul>
+
+<p>
+  With your target countries in mind, you should assess your localization
+  needs, both in your apps and in their Google Play listings details, and start
+  the work of localization well in advance of your target launch date.
+</p>
+
+<p>
+  See <a href=
+  "{@docRoot}distribute/tools/localization-checklist.html">Localization
+  Checklist</a> for key steps and considerations in the localization process.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/country" data-sortorder=
+"-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="confirm-size">
+    6. Confirm the App's Overall Size
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  The overall size of your app can affect its design and how you publish it on
+  Google Play. Currently, the maximum size for an APK published on Google Play
+  is <strong>50 MB</strong>. If your app exceeds that size, or if you want to
+  offer a secondary download, you can use <a href=
+  "{@docRoot}google/play/expansion-files.html">APK Expansion Files</a>, which
+  Google Play will host for free on its server infrastructure and automatically
+  handle the download to devices.
+</p>
+
+<ul>
+  <li>
+    <p>
+      The maximum size for an APK published on Google Play is 50 MB.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      You can use up to two (2) APK Expansion Files, each up to 2GB in size,
+      for each APK.
+    </p>
+  </li>
+</ul>
+
+<p>
+  Using APK Expansion files is a convenient, cost-effective method of
+  distributing large apps. However, the use of APK Expansion Files requires
+  some changes in your app binary, so you will need to make those changes
+  before creating your release-ready APK.
+</p>
+
+<p>
+  To minimize the size of your app binary, make sure that you run the <a href=
+  "{@docRoot}tools/help/proguard.html">Proguard</a> tool or similar obfuscator
+  on your code when building your release-ready APK.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/size" data-sortorder=
+"-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="confirm-platform">
+    7. Confirm the App's Platform and Screen Compatibility Ranges
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Before publishing, it's important to make sure that your apps are designed to
+  run properly on the Android platform versions and device screen sizes that
+  you want to target.
+</p>
+
+<p>
+  From an app-compatibility perspective, Android platform versions are defined
+  by <a href=
+  "{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API
+  level</a>. You should confirm the minimum version that your app is compatible
+  with <a href=
+  "{@docRoot}guide/topics/manifest/uses-sdk-element.html">&lt;minSdkVersion&gt;</a>,
+  as that will affect its distribution to Android devices once it is published.
+</p>
+
+<p>
+  For screen sizes, you should confirm that the app runs properly and looks
+  good on the range of screen sizes and pixel densities that you want to
+  support. You should follow the advice provided in <a href=
+  "{@docRoot}guide/practices/screens_support.html">Supporting Multiple
+  Screens</a> to provide scalable support for multiple screen sizes. However,
+  if you have been unable to do so, declare the minimum screen-size supported
+  by your apps using <a href=
+  "{@docRoot}guide/topics/manifest/supports-screens-element.html">&lt;supports-screens&gt;</a>.
+  Google Play will then restrict the availability of your apps accordingly,
+  making them available to devices with the declared screen size or large.
+</p>
+
+<p>
+  To get a better understanding of the current device penetration of Android
+  platform versions and screen sizes across all Android devices, see the
+  <a href="{@docRoot}about/dashboards/index.html">Device Dashboard</a> charts.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/platform" data-sortorder=
+"-timestamp" data-cardsizes="6x3,6x3,6x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="decide-price">
+    8. Decide Whether your App will be Free or Priced
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-launch-checklist-1.png">
+</div>
+
+<p>
+  On Google Play, you can publish apps as free to download or priced. Free apps
+  can be downloaded by any Android user in Google Play. Paid apps can be
+  downloaded only by users who are in a country that supports paid downloads
+  and have registered a form of payment in Google Play, such as a credit card
+  or Direct Carrier Billing.
+</p>
+
+<p>
+  Deciding whether you apps will be free or paid is important because, on
+  Google Play, <strong>free apps must remain free</strong>.
+</p>
+
+<ul>
+  <li>
+    <p>
+      Once you publish an app as a free app, you cannot change it to being a
+      priced app. However, you can still sell <a href=
+      "{@docRoot}google/play/billing/billing_overview.html#products">in-app
+      products</a> and <a href=
+      "{@docRoot}google/play/billing/billing_subscriptions.html">subscriptions</a>
+      through Google Play's <a href=
+      "{@docRoot}google/play/billing/index.html">In-app Billing</a> service.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      If you publish your app as a priced app, you <em>can</em> change it at
+      any time to be a free app (<strong>but cannot then change it back to
+      priced</strong>). You can also sell in-app products and subscriptions.
+    </p>
+  </li>
+</ul>
+
+<p>
+  If your app is be priced, or if you'll be selling in-app products, you need
+  <a href=
+  "https://developers.google.com/wallet/digital/training/getting-started/merchant-setup">
+  set up a Google Wallet Merchant Account</a> before you can publish.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/price" data-sortorder=
+"-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="consider-billing">
+    9. Consider using In-app Billing
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Google Play <a href="{@docRoot}google/play/billing/index.html">In-app
+  Billing</a> lets you sell digital content in your applications. You can use
+  the service to sell a wide range of content, including downloadable content
+  such as media files or photos, and virtual content such as game levels or
+  potions. In-app Billing service lets you sell one-time purchases and
+  subscriptions from inside your app. This can help you to monetize the app
+  over its installed lifetime.
+</p>
+
+<p>
+  If your are looking for more ways to monetize your app and build engagement,
+  you should consider In-app Billing or Instant Buy. These services have become
+  very popular with both users and developers. To use In-app Billing or Instant
+  Buy, you need to make changes to your app binary, so you will need to
+  complete and test your implementation before creating your release-ready APK.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/purchasemethod"
+data-sortorder="-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="set-prices">
+    10. Set Prices for your Products
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  If your apps is priced or you’ll sell in-app or physical products, Google
+  Play lets you set prices for your products in a variety of currencies, for
+  users in markets around the world. You can set prices individually in
+  different currencies, so you have the flexibility to adjust your price
+  according to market conditions and exchange rates.
+</p>
+
+<p>
+  Before you publish, consider how you’ll price your products and what your
+  prices will be in various currencies. Later, you can set prices in all
+  available currencies through the Developer Console.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/setprice" data-sortorder=
+"-timestamp" data-cardsizes="9x3,9x3,9x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="start-localization">
+    11. Start Localization
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  With your country targeting in mind, it's a good idea to assess your
+  localization needs, ensure your apps are internationalized, and start the
+  work of localizing well in advance of your target launch date.
+</p>
+
+<p>
+  In addition to your application design, there are at least three aspects of
+  localization to consider:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Localizing the strings, images, and other resources in your apps.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Localizing your apps’ store listing details on Google Play.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Localizing the apps’ graphic assets, screenshots, and videos that
+      accompany your store listing.
+    </p>
+  </li>
+</ul>
+
+<p>
+  See <a href=
+  "{@docRoot}distribute/tools/localization-checklist.html">Localization
+  Checklist</a> for key steps and considerations in the localization process.
+</p>
+
+<p>
+  To localize your store listing, first create and finalize your app title,
+  description, and promotional text. Collect and send all of these for
+  localization. You can optionally translate the "Recent Changes" text for app
+  updates as well. Later you can add your localized listing details in the
+  Developer Console, or you can choose to let Google Play auto-translate your
+  listing details into the languages you support.
+</p>
+
+<p>
+  A key part of making your app listing attractive to a global customer base is
+  creating localized versions of your promotional graphics, screenshots and
+  videos. For example, your app's feature graphic might include text that
+  should be translated, for maximum effectiveness. You can create different
+  versions of your promotional graphics for each language and upload them to
+  the Developer Console. If you offer a promotional video, you can create
+  localized versions of it and then add a link to the correct localized video
+  for each language you support.
+</p>
+
+<p>
+  When your translations are complete, move them into your app resources as
+  needed and test that they are loaded properly. Save your app's translated
+  listing details for later, when you upload assets and configure the store
+  listing.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/localization"
+data-sortorder="-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="prepare-graphics">
+    12. Prepare Promotional Graphics, Screenshots, and Videos
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  When you publish on Google Play, you can supply a variety of high-quality
+  graphic assets to showcase your app or brand. After you publish, these appear
+  on your store listing page, search results, and elsewhere. These graphic
+  assets are key parts of a successful store listing page that attracts and
+  engages users, so you should consider having a professional produce them for
+  you. Screenshots and videos are also very important, because they show how
+  your apps look, how they’re used or played, and what makes them different.
+</p>
+
+<p>
+  All of your graphic assets should be designed so that they are easy to see
+  and highlight your apps or brand in a colorful, interesting way. The assets
+  should reference the same logo and icon as users will find in the All Apps
+  launcher once they have downloaded the app. Your graphic assets should also
+  fit in well with the graphic assets of all the apps you publish, which will
+  be also be displayed to users on your store listing page.
+</p>
+
+<p>
+  To help you market your apps more effectively to a global audience, Google
+  Play lets you create localized versions of your promotional graphics,
+  screenshots, and videos and upload them to the Developer Console. When a user
+  visits your app's store listing, Google Play displays the promotional
+  graphic, screenshots, and video that you've provided for the user's language.
+</p>
+
+<p>
+  To localize your promotional graphics, you can translate any embedded text,
+  use different imagery or presentation, or change your marketing approach to
+  best address the needs of users in specific languages. For example, if your
+  feature or promotional graphic includes an embedded product name or tag line,
+  you can translate that text and add it to a localized version of the
+  promotional graphic.
+</p>
+
+<p>
+  Because your localized graphic assets and videos are so important, you should
+  get started on creating and localizing them well in advance of your target
+  publishing date.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/graphics" data-sortorder=
+"-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="build-upload">
+    13. Build and Upload the Release-ready APK
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  When you are satisfied that your apps meet your UI, compatibility, and
+  quality requirements, you can build the release-ready versions of the apps.
+  You upload the release-ready APKs to your Developer Console and distribute to
+  users.
+</p>
+
+<p>
+  The process for preparing a release-ready APK is the same for all apps,
+  regardless of how they are distributed. Generally the process includes basic
+  code cleanup and optimization, building and signing with your release key,
+  and final testing.
+</p>
+
+<p>
+  For complete details on how to create a release-ready version of your app,
+  read <a href="{@docRoot}tools/publishing/preparing.html">Preparing for
+  Release</a>.
+</p>
+
+<p>
+  Once you have the release-ready APKs in hand, you can upload them to the
+  Developer Console. If necessary, you can replace an APK with a more recent
+  version before publishing.
+</p>
+<!--<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/toolsreference/launchchecklist/build"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3,9x3,6x3,9x3,9x3,9x3"
+  data-maxResults="6"></div>-->
+
+<div class="headerLine clearfloat">
+  <h1 id="plan-beta">
+    14. Plan a Beta Release
+  </h1>
+
+  <hr>
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <h2>
+      Easy beta testing
+    </h2>
+
+    <p>
+      Google Play lets you set up groups of alpha and beta testers, anywhere
+      around the world. Check out this powerful feature next time you sign in
+      to the Developer Console.
+    </p>
+  </div>
+</div>
+
+<p>
+  Before launching your apps, it's always valuable to get real-world feedback
+  from users &mdash; even more so when you are launching new apps. It's highly
+  recommended that you distribute a pre-release version of your app to users
+  across your key markets and provide an easy means for them to provide
+  feedback and report bugs.
+</p>
+
+<p>
+  Google Play can help you set up a beta program for your app. After you sign
+  in to your Developer Console and have upload your APKs, you can set up groups
+  of users for alpha and beta testing the apps. You can start with a small
+  group of alpha testers, then move to a larger group of beta testers. Once
+  users are added, they access your app's store listing and install the app.
+  <strong>Users on alpha or beta versions cannot leave reviews or
+  ratings</strong>, so there is <strong>no risk to your rating</strong> on
+  Google Play. You need to arrange a mechanism for any testing feedback to be
+  delivered - such as a Google Forum or Google+.
+</p>
+
+<p>
+  The feedback you receive will help you adjust your UI, translations, and
+  store listing to ensure a great experience for users.
+</p>
+<!-- Related resources
+
+<table>
+  <tr>
+    <td>Beta-testing and Staged Rollouts
+See how you can facilitate testing with Google Play.</td>
+  </tr>
+</table> -->
+
+<div class="headerLine">
+  <h1 id="complete-details">
+    15. Complete the Apps’ Store Listing
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  On Google Play, your apps’ product information is shown to users on their
+  store listing pages, the pages that users visit to learn more about your apps
+  and the pages from which they will decide to purchase or download your apps,
+  on their Android devices or on the web.
+</p>
+
+<p>
+  Google Play gives you a variety of ways to promote your apps and engage with
+  users on your store listing pages, from colorful graphics, screenshots, and
+  videos to localized descriptions, release details, and links to your other
+  apps. As you prepare to publish your apps, make sure that you take advantage
+  of all that your product detail pages can offer, making your apps as
+  compelling as possible to users.
+</p>
+
+<p>
+  You should begin planning your product pages in advance of your target launch
+  date, arranging for localized description, high-quality graphic assets,
+  screenshots and video, and so on.
+</p>
+
+<p>
+  As you get near your target publishing date, you should become familiar with
+  all the fields, options, and assets associated with the store listing
+  configuration page in the Developer Console. As you collect the information
+  and assets for the page, make sure that you can enter or upload it to the
+  Developer Console, until the page is complete and ready for publishing.
+</p>
+
+<p>
+  After you've set your apps’ geographic targeting in the Developer Console,
+  remember to add your localized store listing, promotional graphics, and so
+  on, for all of the languages that you support.
+</p>
+
+<p>
+  If your app is targeting tablet devices, make sure to include at least one
+  screenshot of the app running on a tablet, and highlight your apps’ support
+  for tablets in the app description, release notes, promotional campaigns, and
+  elsewhere.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/productdetails"
+data-sortorder="-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="use-badges">
+    16. Use Google Play Badges and Links in your Promotional Campaigns
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Google Play badges give you an officially branded way of promoting your apps
+  to Android users. Use the <a href=
+  "{@docRoot}distribute/tools/promote/badges.html">Google Play Badge
+  generator</a> to quickly create badges to link users to your products from
+  web pages, ads, reviews, and more. You can also use special <a href=
+  "{@docRoot}distribute/tools/promote/linking.html">link formats</a> to link
+  directly to your store listing page, to a list of your products, or to search
+  results.
+</p>
+
+<p>
+  To help your apps get traction after launch, it's strongly recommended that
+  you support launch with a promotional campaign that announces your product
+  through many channels as possible, in as many countries as possible. For
+  example, you can promote a launch using ad placements, social network or blog
+  posts, video and other media, interviews and reviews, or any other channels
+  available.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/badges" data-sortorder=
+"-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="final-checks">
+    17. Final Checks and Publishing
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  When you think you’re ready to publish, sign in to the Developer Console and
+  take a few moments for a few final checks.
+</p>
+
+<p>
+  Make sure that:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Your developer profile has the correct information and is linked to the
+      proper Google Wallet merchant account (if you’re selling products).
+    </p>
+  </li>
+
+  <li>
+    <p>
+      You have the right version of the apps uploaded.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      All parts of your store listing are ready, including all graphic assets,
+      screenshots, video, localized descriptions, and so on.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      You have set your app's pricing to free or priced.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      You have set country (and carrier) targeting and priced your products (if
+      appropriate) in buyer currencies
+    </p>
+  </li>
+
+  <li>
+    <p>
+      "Compatible devices" shows that your apps are reaching the devices that
+      you’re targeting. If not, you should check with your development team on
+      the apps’ requirements and filtering rules.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      You’ve provided the correct link to your website and the correct support
+      email address.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Your apps don’t violate content policy guidelines.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      You’ve acknowledged that your apps meets the guidelines for Android
+      content on Google Play and also US export laws.
+    </p>
+  </li>
+</ul>
+
+<p>
+  Your apps are now ready to publish!
+</p>
+
+<p>
+  If you’re releasing an update, make sure to read the <a href=
+  "http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&amp;answer=113476&amp;topic=2365760&amp;ctx=topic">
+  requirements for publishing updates</a>.
+</p>
+
+<p>
+  When you’re ready, click the <strong>Publish</strong> button in the Developer
+  Console. Within a few hours, your apps will become available to users and
+  your product page will appear in Google Play for browsing, searching, or
+  linking from your promotional campaigns.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/finalchecks"
+data-sortorder="-timestamp" data-cardsizes="6x3,6x3,6x3,9x3,9x3,9x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="support-users">
+    18. Support Users after Launch
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  After you publish apps or app updates, it's crucial for you to support your
+  customers. Prompt and courteous support can provide a better experience for
+  users that results in better ratings and more positive reviews for your
+  products. Users are likely to be more engaged with your app and recommend it
+  if you’re responsive to their needs and feedback. This is especially true
+  after publishing if you’re using a coordinated promotional campaign.
+</p>
+
+<p>
+  There are a number of ways that you can keep in touch with users and offer
+  them support. The most fundamental is to provide your <em>support email
+  address</em> on your store listing pages. Beyond that, you can provide
+  support in any way you choose, such as a forum, mailing list, or a Google+
+  page. The Google Play team provides user support for downloading, installing.
+  and payments issues, but issues that fall outside of these topics will be in
+  your domain. Examples of issues you can support include: feature requests,
+  questions about using the apps, and questions about compatibility settings.
+</p>
+
+<p>
+  After publishing, plan to:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Check your ratings and reviews frequently on your apps’ store listing
+      pages. Watch for recurring themes that could signal bugs or other issues.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Be mindful of new Android platform version launches, as compatibility
+      settings for your apps might need to be updated.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Put a link to your support resources on your website and set up any other
+      support such as forums.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Provide an appropriate support email address on your store listing pages
+      and respond to users when they take the time to email you.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Beyond the automatic refund window offered by Google Play, be generous
+      with your own refund policy, as satisfied users will be more likely to
+      purchase in the future.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Acknowledge and fix issues in your apps. It helps to be transparent and
+      list known issues on your store listing pages proactively.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Publish updates as frequently as you’re able, without sacrificing quality
+      or annoying users with too-frequent updates.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      With each update, make sure to provide a summary of what's changed. You
+      can enter this information in the Developer Console. Users will read it
+      and appreciate that you are serious about improving the quality of your
+      apps.
+    </p>
+  </li>
+</ul>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/toolsreference/launchchecklist/afterlaunch"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3,9x3,9x3,9x3,9x3,9x3"
+  data-maxResults="6"></div>
diff --git a/docs/html/distribute/tools/localization-checklist.jd b/docs/html/distribute/tools/localization-checklist.jd
new file mode 100644
index 0000000..7a638ed
--- /dev/null
+++ b/docs/html/distribute/tools/localization-checklist.jd
@@ -0,0 +1,978 @@
+page.title=Localization Checklist
+page.metaDescription=Take advantage of the worldwide audience offered by Android and Google Play. Read this checklist to get an overview of how to deliver your product to markets around the world.
+meta.tags="localizing, publishing, disttools"
+page.tags="local, l10n, translation, language"
+page.image=/distribute/images/localization-checklist.jpg
+
+@jd:body
+
+<div id="qv-wrapper">
+  <div id="qv" style="width:280px">
+    <h2>Checklist</h2>
+    <ol>
+      <li><a href="#identify-languages">1. Identify target languages and locales</a></li>
+      <li><a href="#design">2. Design for localization</a></li>
+      <li><a href="#manage-strings">3. Manage strings for localization</a></li>
+      <li><a href="#translate-strings">4. Translate UI strings and other resources</a></li>
+      <li><a href="#test">5. Test your localized app</a></li>
+      <li><a href="#prepare-launch">6. Prepare for international launch</a></li>
+      <li><a href="#support-users">7. Support international users after launch</a></li>
+    </ol>
+  </div>
+</div>
+
+<div class="top-right-float" style="width:194px">
+  <img src="{@docRoot}distribute/images/localization-checklist.jpg">
+</div>
+
+<p>
+  Android and Google Play offer you a worldwide audience for your apps, with an
+  addressable user base that's growing very rapidly in countries such as Japan,
+  Korea, India, Brazil, and Russia. We strongly encourage you to localize as it
+  can maximize your apps’ distribution potential resulting in ratings from
+  users around the world.
+</p>
+
+<p>
+  Localization involves a variety of tasks throughout your app development
+  cycle, and advance planning is essential. This document helps you identify
+  key aspects of localization to get your app ready for a successful worldwide
+  launch on Google Play.
+</p>
+
+<div class="headerLine">
+  <h1 id="identify-languages">
+    1. Identify target languages and locales
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  A basic but important step in preparing for localization is identifying the
+  countries where you’ll distribute your apps and the languages spoken there.
+  Localizing your apps is particularly important in countries where there is a
+  large market opportunity and English or another international language is not
+  widely used.
+</p>
+
+<p>
+  For international users, you can manage your apps in three main dimensions:
+  country, locale, and language. Of those, language is the key consideration
+  for localization (locale can also significant because of differences in
+  formats for dates, times, currencies, and similar information). Users control
+  both the language and locale used on their Android devices and in turn those
+  affect how your app is displayed.
+</p>
+
+<p>
+  Typically, you would decide which countries to target first, based on overall
+  market size and opportunity, app category, competitive landscape, local
+  pricing and financial factors, and so on. Then, based on your country
+  targeting, you would determine the languages you need to support in your
+  apps.
+</p>
+
+<p>
+  You may then decide to localize into some or all languages of the targeted
+  country. It might make sense to start with a major regional language and add
+  more languages as user base grows.
+</p>
+
+<p>
+  Once you have identified your target languages, you can focus your
+  development, translation, testing, and marketing efforts to these markets.
+</p>
+
+<h3 id="related-resources">
+  Related Resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/localizationchecklist/identifylocales"
+data-sortorder="-timestamp" data-cardsizes="9x3," data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="design">
+    2. Design for localization
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  After you've determined your target languages for localization, assess what
+  you'll need to do to support them in your apps and plan the work early.
+  Consider the vocabulary expansion, script requirements, character spacing and
+  wrapping constraints, left-to-right and right-to-left support, and other
+  potential factors in each language.
+</p>
+
+<h4>
+  <strong>Design a single set of flexible layouts</strong>
+</h4>
+
+<p>
+  As you create your layouts, make sure that any UI elements that hold text are
+  designed generously. It’s good to allow more space than necessary for your
+  language (up to 30% more is normal) to accommodate other languages.
+</p>
+
+<p>
+  Also, elements should be able to expand horizontally or vertically to
+  accommodate variations in the width and height of UI strings or input text.
+  Your text strings shouldn’t overlap borders or the screen edge in any of your
+  target languages.
+</p>
+
+<p>
+  If you design your UI carefully, you can typically use a single set of
+  layouts for all of the languages you support. See <a href=
+  "{@docRoot}training/basics/fragments/fragment-ui.html">Building a Flexible
+  UI</a> for more information.
+</p>
+
+<h4>
+  <strong>Use alternative layouts where needed</strong>
+</h4>
+
+<p>
+  In cases where your UI can't accommodate text in one of your target
+  languages, you can create an <a href=
+  "{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">
+  alternative layout</a> for that language only. Android makes it easy to
+  declare sets of layouts and other resources to load for specific languages,
+  locales, screen sizes, and so on, simply by tagging them with the appropriate
+  resource qualifiers. While the flexibility of alternative layouts exists it
+  can also make your apps harder to maintain over time. In general, using a
+  single, more flexible layout is preferred.
+</p>
+
+<h4>
+  <strong>Support RTL layouts and text</strong>
+</h4>
+
+<p>
+  If you’re distributing to countries where right-to-left (RTL) scripts are
+  used, you should consider implementing support for RTL layouts and text
+  display and editing, to the extent possible.
+</p>
+
+<p>
+  Android 4.1 introduced limited support for bidirectional text, allowing apps
+  to display and edit text in both left-to-right (LTR) and right-to-left (RTL)
+  scripts. Android 4.2 added <a href=
+  "http://android-developers.blogspot.fr/2013/03/native-rtl-support-in-android-42.html">
+  full native support for RTL layouts</a>, including layout mirroring, so that
+  you can deliver the same great app experiences to all of your users.
+</p>
+
+<p>
+  At a minimum, for Android 4.2 users, it's simple to add basic RTL layout
+  mirroring, which goes a long way toward meeting the needs of RTL users.
+</p>
+
+<h4>
+  <strong>Use system-provided formats for dates, times, numbers, and
+  currencies</strong>
+</h4>
+
+<p>
+  Where your apps specify dates, times, numbers, currencies, and other entities
+  that can vary by locale, make sure to use the system-provided formats, rather
+  than app-specific formats. Keep in mind that not every locale uses the same
+  thousands separator, decimal separator, or percent sign.
+</p>
+
+<p>
+  Android provides a variety of utilities for formatting and converting
+  patterns across locales, such as <a href=
+  "{@docRoot}reference/android/text/format/DateUtils.html">DateUtils</a> and
+  <a href="{@docRoot}reference/java/text/DateFormat.html">DateFormat</a> for
+  dates; <a href=
+  "{@docRoot}reference/java/lang/String.html#format(java.lang.String,%20java.lang.Object...)">
+  String.format()</a> or <a href=
+  "{@docRoot}reference/java/text/DecimalFormat.html">DecimalFormat</a> for
+  numbers and currency; <a href=
+  "{@docRoot}reference/android/telephony/PhoneNumberUtils.html">PhoneNumberUtils</a>
+  for phone numbers; and others.
+</p>
+
+<p>
+  Hardcoding your formats based on assumptions about the user's locale can
+  result in problems when the user changes to another locale. Using
+  system-provided formats and utilities is strongly encouraged.
+</p>
+
+<h4>
+  <strong>Include a full set of default resources</strong>
+</h4>
+
+<p>
+  Make sure that your apps can run properly regardless of language or locale by
+  providing a complete set of default resources. The app's default resources
+  are those that are <em>not marked</em> with any language or locale
+  qualifiers, for example those stored in res/drawable/ and res/values/. If
+  your apps attempt to load a resource that isn't available in the current
+  language or in the default set, they will crash.
+</p>
+
+<p>
+  Whatever the default language you’re using in your apps, make sure that you
+  store the associated layouts, drawables, and strings in default resource
+  directories, without language or locale qualifiers.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/tools/loc/designforloc" data-sortorder="-timestamp"
+data-cardsizes="9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="manage-strings">
+    3. Manage strings for localization
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  It's important to manage your apps’ UI strings properly, so that you deliver
+  a great experience for users and make localization straightforward.
+</p>
+
+<h4>
+  <strong>Move all strings into strings.xml</strong>
+</h4>
+
+<p>
+  As you build your apps, remember not to hard code any string. Instead declare
+  <em>all</em> of your strings as resources in a default strings.xml file which
+  makes it easy to update and localize. Strings in strings.xml file can be
+  extracted, translated and integrated back into your app (with appropriate
+  qualifiers) without any changes to compiled code.
+</p>
+
+<p>
+  If you generate images with text, put those strings in strings.xml as well,
+  and regenerate the images after translation.
+</p>
+
+<h4>
+  <strong>Follow Android guidelines for UI strings</strong>
+</h4>
+
+<p>
+  As you design and develop your UIs, make sure that you pay close attention to
+  <em>how</em> you talk to your user. In general, use a <a href=
+  "{@docRoot}design/style/writing.html">succinct and compressed style</a> that
+  is friendly but brief, and use a consistent style throughout your UIs.
+</p>
+
+<p>
+  Make sure that you read and follow the Android Design recommendations for
+  <a href="{@docRoot}design/style/writing.html">writing style and word
+  choice</a>. Doing so will make your apps appear more polished to the user and
+  will help users understand your UI more quickly.
+</p>
+
+<p>
+  Also, always use Android standard terminology wherever possible&mdash;such as
+  for UI elements such as "Action Bar," "Options Menu," "System Bar,"
+  "Notifications," and so on. Using Android terms correctly and consistently
+  makes translation easier and results in a better end-product for users.
+</p>
+
+<h4>
+  <strong>Provide sufficient context for declared strings</strong>
+</h4>
+
+<p>
+  As you declare strings in your strings.xml file, make sure to describe the
+  context in which the string is used. This information will be invaluable to
+  translators and result in better quality translation and will also help you
+  manage your strings more effectively over time.
+</p>
+
+<p>
+  Here's an example:
+</p>
+
+<pre class="prettyprint">
+&lt;!-- The action for submitting a form. This text is on a button that can fit 30 chars --&gt;
+&lt;string name="login_submit_button"&gt;Sign in&lt;/string&gt;
+</pre>
+<p>
+  Consider providing context information that may include:
+</p>
+
+<ul>
+  <li>
+    <p>
+      What is this string for? When/where is it presented to the user?
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Where is this in the layout? For example, if it’s a button, translations
+      are less flexible than if it were a text box.
+    </p>
+  </li>
+</ul>
+
+<h4>
+  <strong>Mark message parts that should not be translated</strong>
+</h4>
+
+<p>
+  Often strings contain contain text that shouldn’t be translated to other
+  languages. Common examples might be a piece of code, a placeholder for a
+  value, a special symbol, or a name. As you prepare you strings for
+  translation, look for and mark text that should remain as-is, without
+  translation, so that translators don’t change it.
+</p>
+
+<p>
+  To mark text that should not be translated, use an
+  <code>&lt;xliff:g&gt;</code> placeholder tag. Here's an example tag that
+  ensures the text "%1$s" will not be changed during translation (otherwise it
+  could break the message):
+</p>
+
+<pre class="prettyprint">
+&lt;string name="countdown"&gt;
+    &lt;xliff:g id="time" example="5 days&gt;%1$s&lt;/xliff:g&gt;until holiday
+&lt;/string&gt;
+</pre>
+<p>
+  When you declare a placeholder tag, always add an id attribute that explains
+  what the placeholder is for. If your apps will later replace the placeholder
+  value, be sure to provide an example attribute to clarify the expected use.
+</p>
+
+<p>
+  Here are some more examples of placeholder tags:
+</p>
+
+<pre>
+&lt;resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"&gt;
+
+&lt;!-- Example placeholder for a special unicode symbol --&gt;
+
+&lt;string name="star_rating"&gt;Check out our 5
+
+    &lt;xliff:g id="star"&gt;\u2605&lt;/xliff:g&gt;
+
+&lt;/string&gt;
+
+&lt;!-- Example placeholder for a for a URL --&gt;
+
+&lt;string name="app_homeurl"&gt;
+
+    Visit us at &lt;xliff:g id="application_homepage"&gt;http://my/app/home.html&lt;/xliff:g&gt;
+
+&lt;/string&gt;
+
+&lt;!-- Example placeholder for a name --&gt;
+
+&lt;string name="prod_name"&gt;
+
+    Learn more at &lt;xliff:g id="prod_gamegroup"&gt;Game Group&lt;/xliff:g&gt;
+
+&lt;/string&gt;
+
+&lt;!-- Example placeholder for a literal --&gt;
+
+&lt;string name="promo_message"&gt;
+
+    Please use the "&lt;xliff:g id="promotion_code"&gt;ABCDEFG&lt;/xliff:g&gt;” to get a discount.
+
+&lt;/string&gt;
+
+...
+
+&lt;/resources&gt;
+</pre>
+<h3 class="clearfloat">
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/localizationchecklist/managestrings"
+data-sortorder="-timestamp" data-cardsizes="9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="translate-strings">
+    4. Translate UI strings and other resources
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Translating your apps’ UI strings and resources to your target languages is
+  the key phase of localization, and it's the one that requires the most care
+  and planning.
+</p>
+
+<p>
+  It is recommended to work with a professional translator (see <a href=
+  "#gp-trans">Purchase professional translations</a>) to ensure high quality
+  translations that enhance the value of your app. Machine translations,
+  although an option may not produce as good an experience for your users.
+</p>
+
+<h4>
+  <strong>Prepare for translation</strong>
+</h4>
+
+<p>
+  Translation output quality will depend in part on your input therefore make
+  sure that your strings.xml file is well organized, well commented, and
+  accurate.
+</p>
+
+<p>
+  Here are some ways to prepare your strings for translation:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Make sure your strings are formatted correctly and consistently.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Follow the strings recommendations listed in <a href=
+      "#manage-strings">Manage strings for localization</a>, above.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Clean up the strings.xml file and remove unused strings.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Place comments in the file to identify the owner, origin, and the version
+      of the file, as well as any special instructions for translators.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Identify existing translations, if any, and include those in an outgoing
+      zip file or other package that you send to translators.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Identify drawables or other resources that require translation and
+      include them in the translators’ package.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Additionally, consider translating your apps’ store listing details
+      &mdash; app title and description, release notes, and so on &mdash; as
+      well as other international marketing materials.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Create a terminology list that explains the meaning and use of key terms
+      found in your product, your market, or the underlying technology. Add the
+      list to the translators’ package.
+    </p>
+  </li>
+</ul>
+
+<h4>
+  <strong>Send your strings for translation</strong>
+</h4>
+
+<p>
+  Early in the development cycle, contact professional translation vendors to
+  get an idea of cost and turnaround time. Make sure to include multiple
+  iterations in the cost. You can find translation vendors online or use
+  translation services available directly from Google Play Developer console
+  (see <a href="#gp-trans">Purchase professional translations</a>).
+</p>
+
+<p>
+  When your translations are complete, take a preliminary look at the
+  translations. Check that all files were translated, check for potential
+  encoding issues, and make sure that declaration formats are intact.
+</p>
+
+<p>
+  If everything looks good, carefully move the localized directories and files
+  back into your apps’ resources. Make sure to tag the directories with the
+  appropriate language and locale qualifiers so that they'll later be loaded
+  properly.
+</p>
+
+<p>
+  After the translations are merged back into your app, start <a href=
+  "#test">testing the localized app</a>.
+</p>
+
+<h4 id="gp-trans">
+  <strong>Purchase professional translations through Google Play</strong>
+</h4>
+
+<div class="sidebox-wrapper">
+  <div class="sidebox">
+    <h2>
+      App Translations Service
+    </h2>
+
+    <p>
+      To make it easy to export your app's strings and import the finished
+      translations into your project, try the <a href=
+      "{@docRoot}sdk/installing/installing-adt.html#tmgr">ADT Translation
+      Manager Plugin</a>.
+    </p>
+  </div>
+</div>
+
+<p>
+  Google Play App Translation Service can help you quickly find and purchase
+  translations of your app. In the Developer Console, you can browse a list of
+  third-party vendors who are pre-qualified by Google to offer high-quality
+  translation at competitive prices. You can upload the strings you want
+  translated, select the languages you want to translate into, and select your
+  translation vendor based on time and price.
+</p>
+
+<p>
+  Once you've purchased translations, you'll receive an email from your vendor.
+  Your translations are a direct business agreement between you and your
+  vendor; you'll need to work directly with the vendor to manage the
+  translation process and deliverables and resolve any support issues.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-localization-trans-0.png" class="border-img">
+</div>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/localizationchecklist/translatestrings"
+data-sortorder="-timestamp" data-cardsizes="9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="test">
+    5. Test your localized app
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Once you've received your translated strings and resources and moved them
+  back into your apps, you need to test the apps to make sure that they’re
+  ready for distribution to your international users.
+</p>
+
+<p>
+  Manual testing can help you discover localization issues in your layouts and
+  strings that can affect user satisfaction and, ultimately, your apps' user
+  rating.
+</p>
+
+<h4>
+  <strong>Set up a test environment</strong>
+</h4>
+
+<p>
+  To test your localized app, you'll need to set up an environment consisting
+  of multiple devices (or virtual devices) and screen sizes, based on the
+  markets and form factors you’re targeting. Note that the range of devices in
+  specific regions might be different. If possible, match your test devices to
+  the actual devices likely to be available to users.
+</p>
+
+<h4>
+  <strong>Look for common localization issues</strong>
+</h4>
+
+<p>
+  On each test device, set the language or locale in Settings. Install and
+  launch the app and then navigate through all of the UI flows, dialogs, and
+  user interactions. Enter text in inputs. Some things to look for include:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Clipped text, or text that overlaps the edge of UI elements or the screen
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Poor line wrapping
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Incorrect word breaks or punctuation
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Incorrect alphabetical sorting
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Incorrect layout direction or text direction
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Untranslated text &mdash; if your default strings are displayed instead
+      of translated strings, then you may have overlooked those strings for
+      translation or marked the resources directory with an incorrect language
+      qualifier.
+    </p>
+  </li>
+</ul>
+
+<p>
+  For cases where your strings have expanded in translation and no longer fit
+  your layouts, it's suggested you try to simplify your default text, simplify
+  your translated text, or adjust your default layouts. If none of those
+  resolves the issue, you can create a custom layout for the language.
+</p>
+
+<h4>
+  <strong>Test for default resources</strong>
+</h4>
+
+<p>
+  After you've tested your apps in all of your supported languages and locales,
+  make sure to test it again in an <em>unsupported language</em> and locale.
+  This’ll help you make sure that your apps includes a full set of default
+  strings and resources, so that your apps are usable to all users, regardless
+  of their preferred language.
+</p>
+
+<h4>
+  <strong>Review with native-language speakers</strong>
+</h4>
+
+<p>
+  During or after testing, it's recommended that you let native speakers review
+  your localized apps. One way to do that is through beta testing with regional
+  users &mdash; Google Play can help you do this. <!-- </p>
+
+<h3 class="clearfloat">Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/toolsreference/localizationchecklist/test"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3,9x3,6x3,9x3,9x3,9x3"
+  data-maxResults="6"></div> -->
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="prepare-launch">
+    6. Prepare for international launch
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Getting your apps translated is a key part of localization, but to help your
+  product attract users and gain visibility, you should prepare for launch in
+  your target countries and create a broader launch and marketing plan for
+  international users.
+</p>
+
+<h4>
+  <strong>Localize your Google Play listing</strong>
+</h4>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <h2>
+      Localize your Google Play listing
+    </h2>
+
+    <p>
+      Google Play Store listing is the first impression international users
+      will have of your app. You should highlight what's great about your apps
+      to all of your users! Localize your listing in the Developer Console,
+      including:
+    </p>
+
+    <ul>
+      <li>App title and description
+      </li>
+
+      <li>App screenshots on phones and tablets
+      </li>
+
+      <li>Promotional graphics and videos.
+      </li>
+    </ul>
+  </div>
+</div>
+
+<p>
+  If you want your apps to be successful in international markets, it's
+  essential to localize your Google Play store listing. You can manage your
+  localized listing in the Developer Console.
+</p>
+
+<p>
+  Well before launch, decide on your app title, description, promotional text,
+  marketing names and programs, and other text and images. Send your listing
+  text and images for translation early, so that you’ve them ready when beta
+  testing begins. When your translated text is available, you can add it
+  through the Developer Console.
+</p>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <h2>
+      Store listing translation in Google Play
+    </h2>
+
+    <p>
+      You can use the App Translation service on Google Play to translate your
+      store listing. Prepare an XML file with your store listing information
+      and upload just as you would upload the strings.xml file (see <a href=
+      "#gp-trans">Purchase professional translations</a>)
+    </p>
+  </div>
+</div>
+
+<p>
+  Also, since you've made the effort to create a great localized app, let users
+  know about it! Take screenshots of your UI in each language, for phones and
+  7- and 10- inch tablets. You can upload screenshots to the Developer Console
+  for each language you support. These will be of great value to users browsing
+  your app listings in other languages.
+</p>
+
+<p>
+  It's also essential to create localized versions of your promotional graphics
+  and videos. For example, your apps’ feature graphics might include text that
+  should be translated, for maximum effectiveness, or you might want to take a
+  different visual approach in one country than you do in another. You can
+  create different versions of your promotional graphics for each language and
+  upload them to the Developer Console. If you offer a promotional video, you
+  can create localized versions of it and then add a link to the correct
+  localized video for each language you support.
+</p>
+
+<h4>
+  <strong>Plan a beta release in key countries</strong>
+</h4>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <h2>
+      Easy beta testing
+    </h2>
+
+    <p>
+      Google Play now lets you set up groups of alpha and beta testers,
+      anywhere around the world. Check out this powerful feature next time you
+      sign in to the Developer Console.
+    </p>
+  </div>
+</div>
+
+<p>
+  Before launching your apps, it's always valuable to get real-world feedback
+  from users &mdash; even more so when you are launching an app in a new
+  language, country, or region. In those cases, it's highly recommended that
+  you distribute a pre-release version of your apps to users across your key
+  markets and provide an easy means for them to provide feedback and report
+  bugs.
+</p>
+
+<p>
+  Google Play can help you set up a beta program for your apps. After you sign
+  in to the Developer Console and upload your APK, you can set up groups of
+  users for alpha testing and beta testing the app. You can start with a small
+  group of alpha testers, then move to a larger group of beta testers.
+</p>
+
+<p>
+  Once users are added, they access your app's store listing and install the
+  app. <strong>Users on alpha or beta versions cannot leave reviews or
+  ratings</strong>, so there is <strong>no risk to your rating</strong> on
+  Google Play, however it does mean you need to setup a mechanism for your
+  testers to provide you with feedback: consider creating a <a href=
+  "http://www.google.com/+/business/">Google+</a> page or <a href=
+  "https://groups.google.com/forum/#!overview">Google Groups</a>.
+</p>
+
+<p>
+  The feedback you receive will help you adjust your UI, translations, and
+  store listing to ensure a great experience for users.
+</p>
+
+<h4>
+  <strong>Plan for international marketing</strong>
+</h4>
+
+<p>
+  For highest visibility across countries, consider an international marketing
+  or advertising campaign. The scope of the campaign will vary based on the
+  budget you can support, but in general it's cost-effective and productive to
+  do regional or country-specific marketing at launch and after.
+</p>
+
+<h4>
+  <strong>Create localized Google Play badges</strong>
+</h4>
+
+<p>
+  If you’re preparing international marketing, make sure to include a <a href=
+  "{@docRoot}distribute/tools/promote/badges.html">localized Google Play
+  badge</a> to tell users you're on Google Play. You can use the badge
+  generator to quickly build localized badges that you can use on websites or
+  marketing materials. High-resolution assets are also available.
+</p>
+
+<h4>
+  <strong>Create Localized Device Art</strong>
+</h4>
+
+<p>
+  If you feature product shots of your apps running on Android devices, make
+  sure that those shots look great and reflect the latest in Android devices.
+  To help you create high-quality marketing materials, use the drag-and-drop
+  <a href="{@docRoot}distribute/tools/promote/device-art.html">Device Art
+  Generator</a> to quickly frame your screenshot on a Nexus device.
+</p>
+
+<h4>
+  <strong>Check your Optimization Tips</strong>
+</h4>
+
+<p>
+  As you prepare for launch, make sure to sign into the Developer Console and
+  check your apps’ Optimization Tips. The Optimization Tips let you know when
+  you’re missing parts of your localized store listing and provide other
+  helpful reminders for a successful localized launch.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/localizationchecklist/preplaunch"
+data-sortorder="-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="support-users">
+    7. Support international users after launch
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  After you launch your apps internationally, you should be prepared to support
+  users in a variety of languages and time zones. The extent of your
+  international user support depends on your budget, but at a minimum you
+  should watch your ratings, reviews, and download stats carefully after
+  launch.
+</p>
+
+<p>
+  Here are some suggestions:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Use the app stats in the Developer Console to compare your downloads,
+      installs, and uninstalls, and ratings across languages and
+      countries&mdash;If your downloads or ratings aren’t keeping up in
+      specific languages or countries, consider options for improving your
+      product or changing your marketing approach.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Check reviews regularly&mdash;Google Play translates all user reviews for
+      you, so you can stay in touch with how international users feel about
+      your apps, what features they like and what issues are affecting them. By
+      watching reviews, you can spot technical issues that may affect users in
+      a particular country, then fix and update your apps.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Respond to reviews if possible&mdash;It's good to engage with
+      international users in their language or a common language if possible.
+      If not, you can try using translation tools, although results may not be
+      predictable. If your apps gets very popular in a language, consider
+      getting support help from native-language speakers.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Make sure there's a link to any support resources on your website.
+      Consider setting up language-specific user groups, Google+ communities,
+      or other support forums.
+    </p>
+  </li>
+</ul>
+
+<p>
+  By following these practices for localizing your apps, promoting and
+  marketing to international users, and providing ongoing support, you can
+  attract many new users to your apps and maintain their loyalty.
+</p>
+
+<p>
+  Make sure to read the <a href=
+  "{@docRoot}distribute/tools/launch-checklist.html">Launch Checklist</a> to
+  learn more about how to plan, build, and launch your app on Google Play.
+</p>
+<h3 class="clearfloat">Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/toolsreference/localizationchecklist/supportlaunch"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3,9x3,6x3,9x3,9x3,9x3"
+  data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/tools/open-distribution.jd b/docs/html/distribute/tools/open-distribution.jd
new file mode 100644
index 0000000..f804af2
--- /dev/null
+++ b/docs/html/distribute/tools/open-distribution.jd
@@ -0,0 +1,150 @@
+page.title=Alternative Distribution Options
+page.metaDescription=With Android you can distribute apps to users in any way you want, using any store or distribution approach.
+page.image=/distribute/images/alt-distribution.jpg
+
+@jd:body
+
+<p>
+  As an open platform, Android offers choice. You can distribute your Android
+  apps to users in any way you want, using any distribution approach or
+  combination of approaches that meets your needs. From publishing in an app
+  marketplace to serving your apps from a web site or emailing them directly
+  users, you’re never locked into any particular distribution platform.
+</p>
+
+<p>
+  The process for building and packaging your apps for distribution is the
+  same, regardless of how you distribute them. This saves you time and lets you
+  automate parts of the process as needed. You can read <a href=
+  "{@docRoot}tools/publishing/preparing.html">Preparing for Release</a> for
+  more information.
+</p>
+
+<p>
+  The sections below highlight some of the alternatives for distributing your
+  apps.
+</p>
+
+<div class="headerLine">
+  <h1>
+  Distributing Through an App Marketplace
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Usually, to reach the broadest possible audience, you’d distribute your apps
+  through a marketplace, such as Google Play.
+</p>
+
+<p>
+  Google Play is the premier marketplace for Android apps and is particularly
+  useful if you want to distribute your apps to a large global audience.
+  However, you can distribute your apps through any app marketplace you want or
+  use multiple marketplaces.
+</p>
+
+<p>
+  Unlike other forms of distribution, Google Play allows you to use the In-app
+  Billing service and Licensing service. The <a href=
+  "{@docRoot}google/play/billing/index.html">In-app Billing service</a> makes
+  it easy to sell in-app products like game jewels or app feature upgrades. The
+  <a href="{@docRoot}google/play/licensing/index.html">Licensing service</a>
+  helps prevent unauthorized installation and use of your apps.
+</p>
+
+<div class="headerLine">
+  <h1>
+  Distributing Your Apps by Email
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure" style="width:300px;">
+  <img src="{@docRoot}images/publishing/publishing_via_email.png">
+  <p class="img-caption">
+  <b>Figure 1.</b> Users can simply click <b>Install</b> when you send them
+  an application via email.
+  </p>
+</div>
+
+<p>
+  An easy and quick way to release your apps is to send them to users by email.
+  To do this, you prepare the app for release, attach it to an email, and send
+  it to a user. When the user open your email on their Android-powered device,
+  the Android system recognizes the APK and displays an <strong>Install
+  Now</strong> button in the email message (see Figure 1). Users can install
+  your app by touching the button.
+</p>
+
+<p>
+  <strong>Note:</strong> The <strong>Install Now</strong> button, shown in
+  Figure 1, appears only if the user has configured their device to allow
+  installation from <a href=
+  "{@docRoot}distribute/open.html#unknown-sources">unknown sources</a> and
+  opened your email in the native Gmail app.
+</p>
+
+<p>
+  Distributing apps through email is convenient if you’re sending them to a few
+  trusted users, as it provides few protections from piracy and unauthorized
+  distribution; that is, anyone you send your apps to can simply forward them
+  to others.
+</p>
+
+<div class="headerLine">
+  <h1>
+  Distributing Through a Website
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  If you don’t want to release your apps on a marketplace such as Google Play,
+  you can make them available for download on your own website or server,
+  including on a private or enterprise server. To do this, you first prepare
+  your apps for release in the normal way. Then all you need to do is host the
+  release-ready APK file on your website and provide a download link to users.
+</p>
+
+<p>
+  When users browse to the download link from their Android-powered devices,
+  the file is downloaded and Android system automatically starts installing it
+  on the device. However, the installation process will start automatically
+  only if users have configured their Settings to allow the installation of
+  apps from <a href="{@docRoot}distribute/open.html#unknown-sources">unknown
+  sources</a>.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1>
+  User Opt-In for Apps from Unknown Sources
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure" style="width:325px;">
+  <img src="{@docRoot}images/publishing/publishing_unknown_sources_sm.png">
+  <p class="img-caption">
+  <b>Figure 2.</b> Users must enable the <b>Unknown sources</b> setting
+  before they can install apps not downloaded from Google Play.
+  </p>
+</div>
+
+<p>
+  Android protects users from inadvertent download and install of apps from
+  locations other than Google Play (which is trusted). It blocks such installs
+  until the user opts-in <strong>Unknown sources</strong> in Settings
+  <strong>&gt;</strong> Security, shown in Figure 2. Users need to make this
+  configuration change <em>before</em> they download your apps to their
+  devices.
+</p>
+
+<p>
+  Note that some network providers don’t allow users to install applications
+  from unknown sources.
+</p>
diff --git a/docs/html/distribute/tools/promote/badge-files.jd b/docs/html/distribute/tools/promote/badge-files.jd
new file mode 100644
index 0000000..cce3632
--- /dev/null
+++ b/docs/html/distribute/tools/promote/badge-files.jd
@@ -0,0 +1,291 @@
+page.title=Google Play Badge Files
+page.image=/images/gp-badges-set.png
+page.metaDescription=Download hi-res assets for localized Google Play badges.
+page.tags="badge, google play"
+
+@jd:body
+
+<style>
+table tr td {border:0}
+</style>
+
+<p>The following links provide the Adobe&reg; Illustrator&reg; (.ai) file for the
+two Google Play badges.</p>
+
+<hr>
+<img src="{@docRoot}images/brand/en_generic_rgb_wo_60.png" alt="Get It On Google Play">
+
+<div style="clear:left">&nbsp;</div>
+
+<div class="col-4" style="margin-left:0">
+
+       <a href="{@docRoot}downloads/brand/v2/english_get.ai">English (English)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/amharic_get.ai">ኣማርኛ (Amharic)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/af_generic_rgb_wo.ai">Afrikaans (Afrikaans)</a><br/>
+<!--
+       <a href="{@docRoot}downloads/brand/ar_generic_rgb_wo.ai">العربية (Arabic)</a><br/>
+-->
+       <a href="{@docRoot}downloads/brand/v2/belarusian_get.ai">Беларуская (Belarusian)</a><br/>
+       
+       <a href="{@docRoot}downloads/brand/v2/bulgarian_get.ai">български (Bulgarian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/catalan_get.ai">Català (Catalan)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/traditional_chinese_get.ai">中文 (中国) (Chinese)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/hongkong_chinese_get.ai">中文(香港) (Chinese Hong Kong)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/taiwan_chinese_get.ai">中文 (台灣) (Chinese Taiwan)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/croatian_get.ai">Hrvatski (Croatian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/czech_get.ai">Česky (Czech)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/danish_get.ai">Dansk (Danish)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/dutch_get.ai">Nederlands (Dutch)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/estonian_get.ai">Eesti keel (Estonian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/farsi_get.ai">فارسی (Farsi Persian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/filipino_get.ai">Tagalog (Filipino)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/finnish_get.ai">Suomi (Finnish)</a><br/>
+
+</div>
+
+<div class="col-4">
+
+       <a href="{@docRoot}downloads/brand/v2/french_get.ai">Français (French)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/german_get.ai">Deutsch (German)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/greek_get.ai">Ελληνικά (Greek)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/hebrew_get.ai">עברית (Hebrew)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/hindi_get.ai">हिन्दी (Hindi)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/hungarian_get.ai">Magyar (Hungarian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/indonesian_get.ai">Bahasa Indonesia (Indonesian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/italian_get.ai">Italiano (Italian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/japanese_get.ai">日本語 (Japanese)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/kazakh_get.ai">Қазақ тілі (Kazakh)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/korean_get.ai">한국어 (Korean)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/latvian_get.ai">Latviski (Latvian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/lithuanian_get.ai">Lietuviškai (Lithuanian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/malay_get.ai">Bahasa Melayu (Malay)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/norwegian_get.ai">Norsk (Norwegian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/polish_get.ai">Polski (Polish)</a><br/>
+
+</div>
+
+<div class="col-4" style="margin-right:0">
+
+       <a href="{@docRoot}downloads/brand/v2/portugal_portuguese_get.ai">Português (Portuguese)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/brazilian_portuguese_get.ai">Português Brasil (Portuguese Brazil)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/romanian_get.ai">Românã (Romanian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/russian_get.ai">Pусский (Russian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/serbian_get.ai">Српски / srpski (Serbian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/slovak_get.ai">Slovenčina (Slovak)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/slovenian_get.ai">Slovenščina (Slovenian)</a><br/>
+       
+       <a href="{@docRoot}downloads/brand/v2/spanish_get.ai">Español (Spanish)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/spanish_latam_get.ai">Español Latinoamérica (Spanish Latin America)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/swahili_get.ai">Kiswahili (Swahili)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/swedish_get.ai">Svenska (Swedish)</a><br/>
+       
+       <a href="{@docRoot}downloads/brand/v2/thai_get.ai">ภาษาไทย (Thai)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/turkish_get.ai">Türkçe (Turkish)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/uk_generic_rgb_wo.ai">Українська (Ukrainian)</a><br/>
+       <a href="{@docRoot}downloads/brand/vi_generic_rgb_wo.ai">Tiếng Việt (Vietnamese)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/zulu_get.ai">isiZulu (Zulu)</a><br/>
+
+</div>
+<div style="clear:left">&nbsp;</div>
+
+
+
+
+
+
+
+
+
+<hr>
+<img src="{@docRoot}images/brand/en_app_rgb_wo_60.png" alt="Android App On Google Play">
+
+<div style="clear:left">&nbsp;</div>
+
+<div class="col-4" style="margin-left:0">
+
+       <a href="{@docRoot}downloads/brand/v2/english_app.ai">English (English)</a><br/>
+      
+       <a href="{@docRoot}downloads/brand/v2/afrikaans_app.ai">Afrikaans (Afrikaans)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/amharic_app.ai">ኣማርኛ (Amharic)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/arabic_app.ai">العربية (Arabic)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/belarusian_app.ai">Беларуская (Belarusian)</a><br/>
+       
+       <a href="{@docRoot}downloads/brand/v2/bulgarian_app.ai">български (Bulgarian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/catalan_app.ai">Català (Catalan)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/traditional_chinese_app.ai">中文 (中国) (Chinese)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/hongkong_chinese_app.ai">中文(香港) (Chinese Hong Kong)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/taiwan_chinese_app.ai">中文 (台灣) (Chinese Taiwan)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/croatian_app.ai">Hrvatski (Croatian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/czech_app.ai">Česky (Czech)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/danish_app.ai">Dansk (Danish)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/dutch_app.ai">Nederlands (Dutch)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/estonian_app.ai">Eesti keel (Estonian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/farsi_app.ai">فارسی (Farsi Persian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/filipino_app.ai">Tagalog (Filipino)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/finnish_app.ai">Suomi (Finnish)</a><br/>
+
+</div>
+
+<div class="col-4">
+
+       <a href="{@docRoot}downloads/brand/v2/french_app.ai">Français (French)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/german_app.ai">Deutsch (German)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/greek_app.ai">Ελληνικά (Greek)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/hebrew_app.ai">עברית (Hebrew)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/hindi_app.ai">हिन्दी (Hindi)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/hungarian_app.ai">Magyar (Hungarian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/indonesian_app.ai">Bahasa Indonesia (Indonesian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/italian_app.ai">Italiano (Italian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/japanese_app.ai">日本語 (Japanese)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/korean_app.ai">한국어 (Korean)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/latvian_app.ai">Latviski (Latvian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/lithuanian_app.ai">Lietuviškai (Lithuanian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/malay_app.ai">Bahasa Melayu (Malay)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/norwegian_app.ai">Norsk (Norwegian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/polish_app.ai">Polski (Polish)</a><br/>
+
+
+</div>
+
+<div class="col-4" style="margin-right:0">
+
+       <a href="{@docRoot}downloads/brand/v2/portugal_portuguese_app.ai">Português (Portuguese)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/brazilian_portuguese_app.ai">Português Brasil (Portuguese Brazil)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/romanian_app.ai">Românã (Romanian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/russian_app.ai">Pусский (Russian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/serbian_app.ai">Српски / srpski (Serbian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/slovak_app.ai">Slovenčina (Slovak)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/slovenian_app.ai">Slovenščina (Slovenian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/spanish_app.ai">Español (Spanish)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/spanish_latam_app.ai">Español Latinoamérica (Spanish Latin America)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/swahili_app.ai">Kiswahili (Swahili)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/swedish_app.ai">Svenska (Swedish)</a><br/>
+       
+       <a href="{@docRoot}downloads/brand/v2/thai_app.ai">ภาษาไทย (Thai)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/turkish_app.ai">Türkçe (Turkish)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/ukranian_app.ai">Українська (Ukrainian)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/vietnamese_app.ai">Tiếng Việt (Vietnamese)</a><br/>
+
+       <a href="{@docRoot}downloads/brand/v2/zulu_app.ai">isiZulu (Zulu)</a><br/>
+
+</div>
+<div style="clear:left">&nbsp;</div>
+
+
+
+
+
+  
+<h2>Guidelines</h2>
+
+  <ul>
+    <li>Do not modify the color, proportions, spacing or any other aspect of the badge image.
+    </li>
+    <li>When used alongside logos for other application marketplaces, the Google Play logo
+    should be of equal or greater size.</li>
+    <li>When used online, the badge should link to either:
+      <ul>
+        <li>A list of products published by you, for example:<br />
+        <span style="margin-left:1em;">http://play.google.com/store/search?q=<em>publisherName</em></span>
+        </li>
+        <li>A specific app product details page within Google Play, for example:<br />
+        <span style="margin-left:1em;">http://play.google.com/store/apps/details?id=<em>packageName</em></span>
+        </li>
+      </ul>
+    </li>
+  </ul>
+  
+<p>For more information, see the
+<a href="{@docRoot}distribute/tools/promote/brand.html#brand-google_play">Brand
+Guidelines</a>.
+
+
+<p>To quickly create a badge that links to your apps on Google Play,
+use the <a
+href="{@docRoot}distribute/tools/promote/badges.html">Googe Play badge generator</a>.</p>
+    
+    
+    
\ No newline at end of file
diff --git a/docs/html/distribute/tools/promote/badges.jd b/docs/html/distribute/tools/promote/badges.jd
new file mode 100644
index 0000000..e91a804
--- /dev/null
+++ b/docs/html/distribute/tools/promote/badges.jd
@@ -0,0 +1,362 @@
+page.title=Google Play Badge Generator
+page.image=/images/gp-badges-set.png
+page.metaDescription=Build badges for your app in just a few clicks, or download hi-res badge assets localized for a variety of languages.
+meta.tags="disttools, promoting, deviceart, marketing, googleplay"
+page.tags="badge, google play"
+
+@jd:body
+
+<p itemprop="description">Google Play badges enable you to promote your apps with
+official branding in your online ads, promotional materials, or anywhere you want
+a link to your apps</p>
+
+<p>In the form below,
+input your app's package name or publisher name, choose the badge style,
+click <em>Build my badge</em>, then paste the HTML into your web content.</p>
+
+<p>If you're creating a promotional web page for your app, you should also use the
+<a href="{@docRoot}distribute/tools/promote/device-art.html">Device Art Generator</a>, which quickly
+wraps your screenshots in real device artwork.</p>
+
+<p>For guidelines when using the Google Play badge and other brand assets,
+see the <a href="{@docRoot}distribute/tools/promote/brand.html#brand-google_play">Brand
+Guidelines</a>.</p>
+
+<style type="text/css">
+
+form.button-form {
+  margin-top:2em;
+}
+
+/* the label and input elements are blocks that float left in order to
+   keep the left edgets of the input aligned, and IE 6/7 do not fully support "inline-block" */
+label.block {
+  display: block;
+  float: left;
+  width: 100px;
+  padding-right: 10px;
+}
+
+input.text {
+  display: block;
+  float: left;
+  width: 250px;
+}
+
+div.button-row {
+  white-space:nowrap;
+  min-height:80px;
+}
+
+div.button-row input {
+  vertical-align:middle;
+  margin:0 5px 0 0;
+}
+
+#jd-content div.button-row img {
+  margin: 0;
+  vertical-align:middle;
+}
+
+</style>
+
+<script type="text/javascript">
+
+// locales for which we have the 'app' badge
+var APP_LANGS = ['it','pt-br','pt-pt','nl','ko','ja','fr','es','es-419','en','de'];
+
+// variables for creating 'try it out' demo button
+var imagePath = "{@docRoot}images/brand/"
+var linkStart = "<a href=\"https://play.google.com/store/";
+var imageStart = "\">\n"
+        + "  <img alt=\"";
+  // leaves opening for the alt text value
+var imageSrc = "\"\n       src=\"" + imagePath;
+  // leaves opening for the image file name
+var imageEnd = ".png\" />\n</a>";
+
+// variables for creating code snippet
+var linkStartCode = "&lt;a href=\"https://play.google.com/store/";
+var imageStartCode = "\"&gt;\n"
+        + "  &lt;img alt=\"";
+  // leaves opening for the alt text value
+var imageSrcCode = "\"\n       src=\"" + imagePath;
+  // leaves opening for the image file name
+var imageEndCode = ".png\" />\n&lt;/a>";
+
+/** Generate the HTML snippet and demo based on form values */
+function buildButton(form) {
+  var lang = $('#locale option:selected').val();
+  var selectedValue = lang + $('form input[type=radio]:checked').val();
+  var altText = selectedValue.indexOf("generic") != -1 ? "Get it on Google Play" : "Android app on Google Play";
+
+  if (form["package"].value != "com.example.android") {
+    $("#preview").show();
+    var packageName = escapeHTML(form["package"].value);
+    $("#snippet").show().html(linkStartCode + "apps/details?id=" + packageName
+            + imageStartCode + altText + imageSrcCode
+            + selectedValue + imageEndCode);
+    $("#button-preview").html(linkStart + "apps/details?id=" + packageName
+            + imageStart + altText + imageSrc
+            + selectedValue + imageEnd);
+            
+    // Send the event to Analytics
+    _gaq.push(['_trackEvent', 'Distribute', 'Create Google Play Badge', 'Package ' + selectedValue]);
+  } else if (form["publisher"].value != "Example, Inc.") {
+    $("#preview").show();
+    var publisherName = escapeHTML(form["publisher"].value);
+    $("#snippet").show().html(linkStartCode + "search?q=pub:" + publisherName
+            + imageStartCode + altText + imageSrcCode
+            + selectedValue + imageEndCode);
+    $("#button-preview").html(linkStart + "search?q=pub:" + publisherName
+            + imageStart + altText + imageSrc
+            + selectedValue + imageEnd);
+   
+    // Send the event to Analytics
+    _gaq.push(['_trackEvent', 'Distribute', 'Create Google Play Badge', 'Publisher ' + selectedValue]);
+  } else {
+    alert("Please enter your package name or publisher name");
+  }
+  return false;
+}
+
+/** Listen for Enter key */
+function onTextEntered(event, form, me) {
+  // 13 = enter
+  if (event.keyCode == 13) {
+    buildButton(form);
+  }
+}
+
+/** When input is focused, remove example text and disable other input */
+function onInputFocus(object, example) {
+  if (object.value == example) {
+    $(object).val('').css({'color' : '#000'});
+  }
+  $('input[type="text"]:not(input[name='+object.name+'])',
+          object.parentNode).attr('disabled','true');
+  $('#'+object.name+'-clear').show();
+}
+
+/** When input is blured, restore example text if appropriate and enable other input */
+function onInputBlur(object, example) {
+  if (object.value.length < 1) {
+    $(object).attr('value',example).css({'color':'#ccc'});
+    $('input[type="text"]', object.parentNode).removeAttr('disabled');
+    $('#'+object.name+'-clear').hide();
+  }
+}
+
+/** Clear the form to start over */
+function clearLabel(id, example) {
+  $("#preview").hide();
+  $('#'+id+'').html('').attr('value',example).css({'color':'#ccc'});
+  $('input[type="text"]', $('#'+id+'').parent()).removeAttr('disabled');
+  $('#'+id+'-clear').hide();
+  return false;
+}
+
+/** Switch the badge urls for selected language */
+function changeBadgeLang() {
+  var lang = $('#locale option:selected').val();
+  
+  // check if we have the 'app' badge for this lang and show notice if not
+  $("div.button-row.error").remove();  // remove any existing instance of error message
+  if ($.inArray(lang,APP_LANGS) == -1) {
+    $("div.button-row.app").hide();
+    $("div.button-row.app").after('<div class="button-row error"><p class="note" style="margin:1em 0 -1em">'
+        + 'Sorry, we currently don\'t have the '
+        + '<em>Android app on Google Play</em> badge translated for '
+        + $("select#locale option[value="+lang+"]").attr("title")
+        + '.<br>Please check back later or instead use the <em>Get it on Google Play</em> badge below.'
+        + '</p></div>');
+  } else {
+    $("div.button-row.app").show(); // show the 'app' badge row
+  }
+  
+  $('.button-row img').each(function() {
+    var id = $(this).parent().attr('for');
+    var imgName = lang + $('input#'+id).attr('value') + '.png';
+    var lastSlash = $(this).attr('src').lastIndexOf('/');
+    var imgPath = $(this).attr('src').substring(0, lastSlash+1);
+    $(this).attr('src', imgPath + imgName);
+  });
+}
+
+/** When the doc is ready, find the inputs and color the input grey if the value is the example
+    text. This is necessary to handle back-navigation, which can auto-fill the form with previous
+    values (and text should not be grey) */
+$(document).ready(function() {
+  $(".button-form input.text").each(function(index) {
+    if ($(this).val() == $(this).attr("default")) {
+      $(this).css("color","#ccc");
+    } else {
+      /* This is necessary to handle back-navigation to the page after form was filled */
+      $('input[type="text"]:not(input[name='+this.name+'])',
+              this.parentNode).attr('disabled','true');
+      $('#'+this.name+'-clear').show();
+    }
+  });
+});
+
+</script>
+
+<form class="button-form">
+  <label class="block" for="locale">Language:</label>
+  <select id="locale" style="display:block;float:left;margin:0"
+          onchange="changeBadgeLang()">
+    <option title="Afrikaans"
+            value="af">Afrikaans</option>
+    <option title="Arabic"
+            value="ar">العربية</option>
+    <option title="Belarusian"
+            value="be">Беларуская</option>
+    <option title="Bulgarian"
+            value="bg">Български</option>
+    <option title="Catalan"
+            value="ca">Català</option>
+    <option title="Chinese (China)"
+            value="zh-cn">中文 (中国)</option>
+    <option title="Chinese (Hong Kong)"
+            value="zh-hk">中文(香港)</option>
+    <option title="Chinese (Taiwan)"
+            value="zh-tw">中文 (台灣)</option>
+    <option title="Croatian"
+            value="hr">Hrvatski</option>
+    <option title="Czech"
+            value="cs">Česky</option>
+    <option title="Danish"
+            value="da">Dansk</option>
+    <option title="Dutch"
+            value="nl">Nederlands</option>
+    <option title="Estonian"
+            value="et">Eesti</option>
+    <option title="Farsi - Persian"
+            value="fa">فارسی</option>
+    <option title="Filipino"
+            value="fil">Tagalog</option>
+    <option title="Finnish"
+            value="fi">Suomi</option>
+    <option title="French"
+            value="fr">Français</option>
+    <option title="German"
+            value="de">Deutsch</option>
+    <option title="Greek"
+            value="el">Ελληνικά</option>
+    <option title="English"
+            value="en" selected="true">English</option>
+<!--
+    <option title="Hebrew"
+            value="iw-he">עברית</option>
+-->
+    <option title="Hungarian"
+            value="hu">Magyar</option>
+    <option title="Indonesian"
+            value="id-in">Bahasa Indonesia</option>
+    <option title="Italian"
+            value="it">Italiano</option>
+    <option title="Japanese"
+            value="ja">日本語</option>
+    <option title="Korean"
+            value="ko">한국어</option>
+    <option title="Latvian"
+            value="lv">Latviešu</option>
+    <option title="Lithuanian"
+            value="lt">Lietuviškai</option>
+    <option title="Malay"
+            value="ms">Bahasa Melayu</option>
+    <option title="Norwegian"
+            value="no">Norsk (bokmål)‎</option>
+    <option title="Polish"
+            value="pl">Polski</option>
+    <option title="Portuguese (Brazil)"
+            value="pt-br">Português (Brasil)</option>
+    <option title="Portuguese (Portugal)"
+            value="pt-pt">Português (Portugal)</option>
+    <option title="Romanian"
+            value="ro">Română</option>
+    <option title="Russian"
+            value="ru">Русский</option>
+    <option title="Serbian"
+            value="sr">Српски / srpski</option>
+    <option title="Slovak"
+            value="sk">Slovenčina</option>
+    <option title="Slovenian"
+            value="sl">Slovenščina</option>
+    <option title="Spanish (Spain)"
+            value="es">Español (España)</option>
+    <option title="Spanish (Latin America)"
+            value="es-419">Español (Latinoamérica)</option>
+    <option title="Swedish"
+            value="sv">Svenska</option>
+    <option title="Swahili"
+            value="sw">Kiswahili</option>
+    <option title="Thai"
+            value="th">ไทย</option>
+    <option title="Turkish"
+            value="tr">Türkçe</option>
+    <option title="Ukrainian"
+            value="uk">Українська</option>
+    <option title="Vietnamese"
+            value="vi">Tiếng Việt</option>
+    <option title="Zulu"
+            value="zu">isiZulu</option>
+  </select>
+  <p style="clear:both;margin:0">&nbsp;</p>
+  <label class="block" for="package" style="clear:left">Package name:</label>
+  <input class="text" type="text" id="package" name="package"
+         value="com.example.android"
+         default="com.example.android"
+         onfocus="onInputFocus(this, 'com.example.android')"
+         onblur="onInputBlur(this, 'com.example.android')"
+         onkeyup="return onTextEntered(event, this.parentNode, this)"/>&nbsp;
+         <a id="package-clear" style="display:none" href="#"
+            onclick="return clearLabel('package','com.example.android');">clear</a>
+  <p style="clear:both;margin:0">&nbsp;<em>or</em></p>
+  <label class="block" style="margin-top:5px" for="publisher">Publisher&nbsp;name:</label>
+  <input class="text" type="text" id="publisher" name="publisher"
+         value="Example, Inc."
+         default="Example, Inc."
+         onfocus="onInputFocus(this, 'Example, Inc.')"
+         onblur="onInputBlur(this, 'Example, Inc.')"
+         onkeyup="return onTextEntered(event, this.parentNode, this)"/>&nbsp;
+         <a id="publisher-clear" style="display:none" href="#"
+            onclick="return clearLabel('publisher','Example, Inc.');">clear</a>
+         <br/><br/>
+
+
+<div class="button-row app">
+  <input type="radio" name="buttonStyle" value="_app_rgb_wo_45" id="ws" />
+    <label for="ws"><img src="{@docRoot}images/brand/en_app_rgb_wo_45.png"
+alt="Android app on Google Play (small)" /></label>
+    &nbsp;&nbsp;&nbsp;&nbsp;
+  <input type="radio" name="buttonStyle" value="_app_rgb_wo_60" id="wm" />
+    <label for="wm"><img src="{@docRoot}images/brand/en_app_rgb_wo_60.png"
+alt="Android app on Google Play (large)" /></label>
+</div>
+
+<div class="button-row">
+  <input type="radio" name="buttonStyle" value="_generic_rgb_wo_45" id="ns" checked="checked" />
+    <label for="ns"><img src="{@docRoot}images/brand/en_generic_rgb_wo_45.png"
+alt="Get it on Google Play (small)" /></label>
+    &nbsp;&nbsp;&nbsp;&nbsp;
+  <input type="radio" name="buttonStyle" value="_generic_rgb_wo_60" id="nm" />
+    <label for="nm"><img src="{@docRoot}images/brand/en_generic_rgb_wo_60.png"
+alt="Get it on Google Play (large)" /></label>
+</div>
+
+  <input class="button" onclick="return buildButton(this.parentNode);"
+    type="button" value="Build my badge" style="padding:10px" />
+  <br/>
+</form>
+
+<div id="preview" style="display:none">
+  <p>Copy and paste this HTML into your web site:</p>
+  <textarea id="snippet" cols="100" rows="5" onclick="this.select()"
+style="font-family:monospace;background-color:#efefef;padding:5px;display:none;margin-bottom:1em">
+  </textarea >
+
+<p>Try it out:</p>
+<div id="button-preview" style="margin-top:1em"></div>
+</div>
+
diff --git a/docs/html/distribute/tools/promote/brand.jd b/docs/html/distribute/tools/promote/brand.jd
new file mode 100644
index 0000000..2116c0f
--- /dev/null
+++ b/docs/html/distribute/tools/promote/brand.jd
@@ -0,0 +1,195 @@
+page.title=Brand Guidelines
+page.image=/assets/images/resource-card-default-android.jpg
+page.metaDescription=Guidelines and downloads for the Android and Google Play brands.
+page.tags="brand, bugdroid, assets"
+
+@jd:body
+
+<p>We encourage you to use the Android and Google Play brands with your Android app
+promotional materials. You can use the icons and other assets on this page
+provided that you follow the guidelines.</p>
+
+<h2 id="brand-android">Android</h2>
+
+ <p>The following are guidelines for the Android brand
+ and related assets.</p>
+ 
+
+  <h4 style="clear:right">Android in text</h4>
+    
+  <div style="float:right;clear:right;width:200px;margin:0 0 20px 30px">
+    <img alt="" src="{@docRoot}images/brand/mediaplayer.png">
+  </div>
+    <ul>
+    <li>Android&trade; should have a trademark symbol the first time it appears in a creative.</li>
+    <li>Android should always be capitalized and is never plural or possessive.</li>
+    <li>"Android" cannot be used in names of applications or accessory products,
+    including phones, tablets, TVs, speakers, headphones, watches, and other devices. Instead use "for Android".
+      <ul>
+        <li><span style="color:red">Incorrect</span>: "Android MediaPlayer"</li>
+        <li><span style="color:green">Correct</span>: "MediaPlayer for Android"</li>
+      </ul>
+      <p>If used with your logo, "for Android" needs to be smaller in size than your logo.
+      First instance of this use should be followed by a TM symbol, "for Android&trade;".</p>
+    </li>
+    <li>Android may be used as a descriptor, as long as it is followed by a proper generic term.
+      <ul>
+        <li><span style="color:red">Incorrect</span>: "Android MediaPlayer" or "Android XYZ app"</li>
+        <li><span style="color:green">Correct</span>: "Android features" or "Android applications"</li>
+      </ul>
+    </li>
+    </ul>
+  
+    <p>Any use of the Android name needs to include this
+    attribution in your communication:</p>
+    <blockquote><em>Android is a trademark of Google Inc.</em></blockquote></p>
+
+
+ <h4>Android robot</h4>
+
+  <div style="float:right;width:200px;margin-left:30px">
+    <img alt="" src="{@docRoot}images/brand/Android_Robot_100.png"
+      style="margin-left:50px">
+    <p style="text-align:center">
+       <a href="{@docRoot}images/brand/Android_Robot_100.png">100x118</a> |
+       <a href="{@docRoot}images/brand/Android_Robot_200.png">200x237</a><br>
+       <a href="{@docRoot}downloads/brand/Android_Robot_outlined.ai">Illustrator (.ai)</a></p>
+  </div>
+
+    <p>The Android robot can be used, reproduced, and modified freely in marketing
+    communications. The color value for print is PMS 376C and the online hex
+    color is <span style="color:#A4C639">#A4C639</span>.</p>
+
+    <p>When using the Android Robot or any modification of it, proper attribution is
+    required under the terms of the <a href="http://creativecommons.org/licenses/by/3.0/">Creative
+Commons Attribution</a> license:</p>
+   
+    <blockquote><em>The Android robot is reproduced or modified from work created and shared by Google and
+used according to terms described in the Creative Commons 3.0 Attribution License.</em></blockquote>
+    
+    <p>You may not file trademark applications incorporating the Android robot logo or
+derivatives thereof. We want to ensure that the Android robot remains available
+for all to use.</p>
+
+
+<h4 style="clear:right">Android logo</h4>
+
+<div style="float:right;width:210px;margin-left:30px;margin-top:-10px">
+  <img alt="" src="{@docRoot}images/brand/android_logo_no.png">
+</div>
+
+<p>The Android logo may not be used. Nor can this be used with the Android robot.</p>
+<p>The custom typeface may not be used.</p>
+
+
+
+
+<h2 id="brand-google_play">Google Play</h2>
+
+
+ <p>The following are guidelines for the Google Play brand
+ and related assets.</p>
+
+<h4>Google Play in text</h4>
+
+<p>Always include a TM symbol on the first or most prominent instance of Google Play&trade;
+in text.</p>
+
+<p>When referring to the mobile experience, use "Google Play" unless the text is clearly
+instructional for the user. For example, a marketing headline might read "Download our
+games on Google Play&trade;," but instructional text would read "Download our games using the Google
+Play&trade; Store app."
+
+ <p>Any use of the Google Play name or icon needs to include this
+    attribution in your communication:</p>
+
+<blockquote><em>Google Play is a trademark of Google Inc.</em></blockquote>
+
+
+  <div style="float:right;width:96px;margin-left:30px;margin-top:-20px">
+     <img src="{@docRoot}images/brand/Google_Play_Store_96.png" alt="">
+    <p style="text-align:center">
+       <a href="{@docRoot}images/brand/Google_Play_Store_48.png">48x48</a> |
+       <a href="{@docRoot}images/brand/Google_Play_Store_96.png">96x96</a><br>
+       <a href="{@docRoot}downloads/brand/Google_Play_Store.ai">Illustrator (.ai)</a>
+       </p>
+  </div>
+  
+<h4>Google Play Store icon</h4>
+
+<p>You may use the Google Play Store icon, but you may not modify it.</p>
+
+<p>As mentioned above, when referring to the Google Play Store app in copy, use the full name:
+"Google Play Store." However, when labeling the Google Play Store icon directly, it's OK to use
+"Play Store" alone to accurately reflect the icon label as it appears on a device.</p>
+
+        
+<h4>Google Play badge</h4>
+      
+  <div style="float:right;clear:right;width:172px;margin-left:30px">
+    <img src="{@docRoot}images/brand/en_app_rgb_wo_60.png" alt="">
+    <p style="text-align:center">
+       <a href="{@docRoot}images/brand/en_app_rgb_wo_45.png">129x45</a> |
+       <a href="{@docRoot}images/brand/en_app_rgb_wo_60.png">172x60</a></p>
+  </div>
+      
+  <div style="float:right;clear:right;width:172px;margin-left:30px">
+    <img src="{@docRoot}images/brand/en_generic_rgb_wo_60.png" alt="">
+    <p style="text-align:center">
+       <a href="{@docRoot}images/brand/en_generic_rgb_wo_45.png">129x45</a> |
+       <a href="{@docRoot}images/brand/en_generic_rgb_wo_60.png">172x60</a></p>
+  </div>
+         
+  <p>The "Get it on Google Play" and "Android App on Google Play" logos are badges that you
+    can use on your website and promotional materials, to point to your products on Google
+    Play.</p>
+
+  <ul>
+    <li>Don't modify the color, proportions, spacing, or any other aspect of the badge image.
+    </li>
+    <li>When used alongside logos for other application marketplaces, the Google Play logo
+    should be of equal or greater size.</li>
+    <li>When used online, the badge should link to either:
+      <ul>
+        <li>A list of products published by you, for example:<br />
+        <span style="margin-left:1em;">http://play.google.com/store/search?q=<em>publisherName</em></span>
+        </li>
+        <li>A specific app product details page within Google Play, for example:<br />
+        <span style="margin-left:1em;">http://play.google.com/store/apps/details?id=<em>packageName</em></span>
+        </li>
+      </ul>
+    </li>
+  </ul>
+  
+  <p>To quickly create a badge that links to your apps on Google Play,
+  use the <a
+  href="{@docRoot}distribute/tools/promote/badges.html">Googe Play badge generator</a>
+  (provides the badge in over 40 languages).</p>
+  
+  <p>To create your own size, download an Adobe&reg; Illustrator&reg; (.ai) file for the
+  <a href="{@docRoot}distribute/tools/promote/badge-files.html">Google Play
+  badge in over 40 languages</a>.</p>
+    
+  <p>For details on all the ways that you can link to your product details page in Google Play, 
+    see <a href="{@docRoot}distribute/tools/promote/linking.html">Linking to your products</a></p>
+
+
+
+<h2 id="Questions">Questions</h2>
+
+<p>To view our full guidelines or for any further brand usage questions, please contact our
+Android Partner Marketing team:</p>
+<ul>
+  <li>For North and South America, please contact <a
+  href="mailto:android-brand-approvals@google.com?Subject=Brand%20Approval%20Questions"
+  >android-brand-approvals@google.com</a></li>
+
+  <li>For Europe and Emerging Markets, please contact <a
+  href="mailto:emea-android-brand@google.com?Subject=Brand%20Approval%20Questions"
+  >emea-android-brand@google.com</a></li>
+
+  <li>For Asia and Pacific-America, please contact <a
+  href="mailto:apac-android-brand-approvals@google.com?Subject=Brand%20Approval%20Questions"
+  >apac-android-brand-approvals@google.com</a></li>
+</ul>
+
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/thumb.png
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art.jd b/docs/html/distribute/tools/promote/device-art.jd
new file mode 100644
index 0000000..b0b5f84
--- /dev/null
+++ b/docs/html/distribute/tools/promote/device-art.jd
@@ -0,0 +1,697 @@
+page.title=Device Art Generator
+page.image=/images/device-art-ex-crop.jpg
+page.metaDescription=Drag and drop screenshots of your app into real device artwork, for better looking promotional images and improved visual context.
+meta.tags="disttools, promoting, deviceart, marketing"
+page.tags="device, deviceart, nexus, assets"
+Xnonavpage=true
+
+@jd:body
+
+<p>The device art generator enables you to quickly wrap app screenshots in real device artwork. This provides better visual context for your app screenshots on your website or in other promotional materials</p>
+
+<p class="note"><strong>Note</strong>: Do <em>not</em> use graphics created here in your 1024x500
+feature image or screenshots for your Google Play app listing.</p>
+
+<hr>
+
+<div class="supported-browser">
+
+<div class="layout-content-row">
+  <div class="layout-content-col span-3">
+    <h4>Step 1</h4>
+    <p>Drag a screenshot from your desktop onto a device to the right.</p>
+  </div>
+  <div class="layout-content-col span-10">
+    <ul class="device-list primary"></ul>
+    <a href="#" id="archive-expando">Older devices</a>
+    <ul class="device-list archive"></ul>
+  </div>
+</div>
+
+<hr>
+
+<div class="layout-content-row">
+  <div class="layout-content-col span-3">
+    <h4>Step 2</h4>
+    <p>Customize the generated image and drag it to your desktop to save.</p>
+    <p id="frame-customizations">
+      <input type="checkbox" id="output-shadow" checked="checked" class="form-field-checkbutton">
+      <label for="output-shadow">Shadow</label><br>
+      <input type="checkbox" id="output-glare" checked="checked" class="form-field-checkbutton">
+      <label for="output-glare">Screen Glare</label><br><br>
+      <a class="button" id="rotate-button">Rotate</a>
+    </p>
+  </div>
+  <div class="layout-content-col span-10">
+    <!-- position:relative fixes an issue where dragging an image out of a inline-block container
+         produced no drag feedback image in Chrome 28. -->
+    <div id="output" style="position:relative">No input image.</div>
+  </div>
+</div>
+
+</div>
+
+<div class="unsupported-browser" style="display: none">
+  <p class="warning"><strong>Error:</strong> This page requires 
+    <span id="unsupported-browser-reason">certain features</span>, which your web browser
+    doesn't support. To continue, navigate to this page on a supported web browser, such as
+    <strong>Google Chrome</strong>.</p>
+  <a href="https://www.google.com/chrome/" class="button">Get Google Chrome</a>
+  <br><br>
+</div>
+
+<style>
+  h4 {
+    text-transform: uppercase;
+  }
+
+  .device-list {
+    padding: 0;
+    margin: 0;
+  }
+
+  .device-list li {
+    display: inline-block;
+    vertical-align: bottom;
+    margin: 0;
+    margin-right: 20px;
+    text-align: center;
+  }
+
+  .device-list li .thumb-container {
+    display: inline-block;
+  }
+
+  .device-list li .thumb-container img {
+    margin-bottom: 8px;
+    opacity: 0.6;
+
+    -webkit-transition: -webkit-transform 0.2s, opacity 0.2s;
+       -moz-transition:    -moz-transform 0.2s, opacity 0.2s;
+            transition:         transform 0.2s, opacity 0.2s;
+  }
+
+  .device-list li.drag-hover .thumb-container img {
+    opacity: 1;
+
+    -webkit-transform: scale(1.1);
+       -moz-transform: scale(1.1);
+            transform: scale(1.1);
+  }
+
+  .device-list li .device-details {
+    font-size: 13px;
+    line-height: 16px;
+    color: #888;
+  }
+
+  .device-list li .device-url {
+    font-weight: bold;
+  }
+
+  #archive-expando {
+    display: block;
+    font-size: 13px;
+    font-weight: bold;
+    color: #333;
+    text-transform: uppercase;
+    margin-top: 16px;
+    padding-top: 16px;
+    padding-left: 28px;
+    border-top: 1px solid transparent;
+    background: transparent url({@docRoot}assets/images/styles/disclosure_down.png)
+                no-repeat scroll 0 8px;
+    -webkit-transition: border 0.2s;
+       -moz-transition: border 0.2s;
+            transition: border 0.2s;
+  }
+
+  #archive-expando.expanded {
+    background-image: url({@docRoot}assets/images/styles/disclosure_up.png);
+    border-top: 1px solid #ccc;
+  }
+
+  .device-list.archive {
+    max-height: 0;
+    overflow: hidden;
+    opacity: 0;
+
+    -webkit-transition: max-height 0.2s, opacity 0.2s;
+       -moz-transition: max-height 0.2s, opacity 0.2s;
+            transition: max-height 0.2s, opacity 0.2s;
+  }
+
+  .device-list.archive.expanded {
+    opacity: 1;
+    max-height: 300px;
+  }
+
+  #output {
+    color: #f44;
+    font-style: italic;
+  }
+
+  #output img {
+    max-height: 500px;
+  }
+</style>
+<script>
+  // Global variables
+  var g_currentImage;
+  var g_currentDevice;
+  var g_currentObjectURL;
+  var g_currentBlob;
+
+  // Global constants
+  var MSG_INVALID_INPUT_IMAGE = 'Invalid screenshot provided. Screenshots must be PNG files '
+      + 'matching the target device\'s screen aspect ratio in either portrait or landscape.';
+  var MSG_NO_INPUT_IMAGE = 'Drag a screenshot (in PNG format) from your desktop onto a '
+      + 'target device above.'
+  var MSG_GENERATING_IMAGE = 'Generating device art&hellip;';
+
+  var MAX_DISPLAY_HEIGHT = 126; // XOOM, to fit into 200px wide
+
+  // Device manifest.
+  var DEVICES = [
+    {
+      id: 'nexus_5',
+      title: 'Nexus 5',
+      url: 'http://www.google.com/nexus/5/',
+      physicalSize: 5,
+      physicalHeight: 5.43,
+      density: 'XXHDPI',
+      landRes: ['shadow', 'back', 'fore'],
+      landOffset: [436,306],
+      portRes: ['shadow', 'back', 'fore'],
+      portOffset: [304,436],
+      portSize: [1080,1920],
+    },
+    {
+      id: 'nexus_7',
+      title: 'Nexus 7',
+      url: 'http://www.google.com/nexus/7/',
+      physicalSize: 7,
+      physicalHeight: 8,
+      actualResolution: [1200,1920],
+      density: 'XHDPI',
+      landRes: ['shadow', 'back', 'fore'],
+      landOffset: [326,245],
+      portRes: ['shadow', 'back', 'fore'],
+      portOffset: [244,326],
+      portSize: [800,1280]
+    },
+    {
+      id: 'nexus_10',
+      title: 'Nexus 10',
+      url: 'http://www.google.com/nexus/10/',
+      physicalSize: 10,
+      physicalHeight: 7,
+      actualResolution: [1600,2560],
+      density: 'XHDPI',
+      landRes: ['shadow', 'back', 'fore'],
+      landOffset: [227,217],
+      portRes: ['shadow', 'back', 'fore'],
+      portOffset: [217,223],
+      portSize: [800,1280]
+    },
+    {
+      id: 'xoom',
+      title: 'Motorola XOOM',
+      url: 'http://www.google.com/phone/detail/motorola-xoom',
+      physicalSize: 10,
+      physicalHeight: 6.61,
+      density: 'MDPI',
+      landRes: ['shadow', 'back', 'fore'],
+      landOffset: [218,191],
+      portRes: ['shadow', 'back', 'fore'],
+      portOffset: [199,200],
+      portSize: [800,1280],
+      archived: true
+    },
+    {
+      id: 'nexus_7_2012',
+      title: 'Nexus 7 (2012)',
+      url: 'http://www.google.com/nexus/7/',
+      physicalSize: 7,
+      physicalHeight: 7.81,
+      density: '213dpi',
+      landRes: ['shadow', 'back', 'fore'],
+      landOffset: [315,270],
+      portRes: ['shadow', 'back', 'fore'],
+      portOffset: [264,311],
+      portSize: [800,1280],
+      archived: true
+    },
+    {
+      id: 'nexus_4',
+      title: 'Nexus 4',
+      url: 'http://www.google.com/nexus/4/',
+      physicalSize: 4.7,
+      physicalHeight: 5.27,
+      density: 'XHDPI',
+      landRes: ['shadow', 'back', 'fore'],
+      landOffset: [349,214],
+      portRes: ['shadow', 'back', 'fore'],
+      portOffset: [213,350],
+      portSize: [768,1280],
+      archived: true
+    },
+    {
+      id: 'galaxy_nexus',
+      title: 'Galaxy Nexus',
+      url: 'http://www.android.com/devices/detail/galaxy-nexus',
+      physicalSize: 4.65,
+      physicalHeight: 5.33,
+      density: 'XHDPI',
+      landRes: ['shadow', 'back', 'fore'],
+      landOffset: [371,199],
+      portRes: ['shadow', 'back', 'fore'],
+      portOffset: [216,353],
+      portSize: [720,1280],
+      archived: true
+    },
+    {
+      id: 'nexus_s',
+      title: 'Nexus S',
+      url: 'http://www.google.com/phone/detail/nexus-s',
+      physicalSize: 4.0,
+      physicalHeight: 4.88,
+      density: 'HDPI',
+      landRes: ['shadow', 'back', 'fore'],
+      landOffset: [247,135],
+      portRes: ['shadow', 'back', 'fore'],
+      portOffset: [134,247],
+      portSize: [480,800],
+      archived: true
+    }
+  ];
+
+  DEVICES = DEVICES.sort(function(x, y) { return x.physicalSize - y.physicalSize; });
+
+  var MAX_HEIGHT = 0;
+  for (var i = 0; i < DEVICES.length; i++) {
+    MAX_HEIGHT = Math.max(MAX_HEIGHT, DEVICES[i].physicalHeight);
+  }
+
+  // Setup performed once the DOM is ready.
+  $(document).ready(function() {
+    if (!checkBrowser()) {
+      return;
+    }
+
+    polyfillCanvasToBlob();
+    setupUI();
+
+    // Set up Chrome drag-out
+    $.event.props.push("dataTransfer");
+    document.body.addEventListener('dragstart', function(e) {
+      var target = e.target;
+      if (target.classList.contains('dragout')) {
+        e.dataTransfer.setData('DownloadURL', target.dataset.downloadurl);
+      }
+    }, false);
+  });
+
+  /**
+   * Returns the device from DEVICES with the given id.
+   */
+  function getDeviceById(id) {
+    for (var i = 0; i < DEVICES.length; i++) {
+      if (DEVICES[i].id == id)
+        return DEVICES[i];
+    }
+    return;
+  }
+
+  /**
+   * Checks to make sure the browser supports this page. If not,
+   * updates the UI accordingly and returns false.
+   */
+  function checkBrowser() {
+    // Check for browser support
+    var browserSupportError = null;
+
+    // Must have <canvas>
+    var elem = document.createElement('canvas');
+    if (!elem.getContext || !elem.getContext('2d')) {
+      browserSupportError = 'HTML5 canvas.';
+    }
+
+    // Must have FileReader
+    if (!window.FileReader) {
+      browserSupportError = 'desktop file access';
+    }
+
+    if (browserSupportError) {
+      $('.supported-browser').hide();
+
+      $('#unsupported-browser-reason').html(browserSupportError);
+      $('.unsupported-browser').show();
+      return false;
+    }
+
+    return true;
+  }
+
+  function setupUI() {
+    $('#output').html(MSG_NO_INPUT_IMAGE);
+
+    $('#frame-customizations').hide();
+
+    $('#output-shadow, #output-glare').click(function() {
+      createFrame();
+    });
+
+    // Build device list.
+    $.each(DEVICES, function() {
+      var resolution = this.actualResolution || this.portSize;
+      var scaleFactorText = '';
+      if (resolution[0] != this.portSize[0]) {
+        scaleFactorText = '<br>' + (100 * (this.portSize[0] / resolution[0])).toFixed(0) +
+            '% size output';
+      } else {
+        scaleFactorText = '<br>&nbsp;';
+      }
+
+      $('<li>')
+          .append($('<div>')
+              .addClass('thumb-container')
+              .append($('<img>')
+                  .attr('src', 'device-art-resources/' + this.id + '/thumb.png')
+                  .attr('height',
+                      Math.floor(MAX_DISPLAY_HEIGHT * this.physicalHeight / MAX_HEIGHT))))
+          .append($('<div>')
+              .addClass('device-details')
+              .html((this.url
+                  ? ('<a class="device-url" href="' + this.url + '">' + this.title + '</a>')
+                  : this.title) +
+                  '<br>' +  this.physicalSize + '" @ ' + this.density +
+                  '<br>' + (resolution[0] + 'x' + resolution[1]) + scaleFactorText))
+          .data('deviceId', this.id)
+          .appendTo(this.archived ? '.device-list.archive' : '.device-list.primary');
+    });
+
+    // Set up "older devices" expando.
+    $('#archive-expando').click(function() {
+      if ($(this).hasClass('expanded')) {
+        $(this).removeClass('expanded');
+        $('.device-list.archive').removeClass('expanded');
+      } else {
+        $(this).addClass('expanded');
+        $('.device-list.archive').addClass('expanded');
+      }
+      return false;
+    });
+
+    // Set up drag and drop.
+    $('.device-list li')
+        .live('dragover', function(evt) {
+          $(this).addClass('drag-hover');
+          evt.dataTransfer.dropEffect = 'link';
+          evt.preventDefault();
+        })
+        .live('dragleave', function(evt) {
+          $(this).removeClass('drag-hover');
+        })
+        .live('drop', function(evt) {
+          $('#output').empty().html(MSG_GENERATING_IMAGE);
+          $(this).removeClass('drag-hover');
+          g_currentDevice = getDeviceById($(this).closest('li').data('deviceId'));
+          evt.preventDefault();
+          loadImageFromFileList(evt.dataTransfer.files, function(data) {
+            if (data == null) {
+              $('#output').html(MSG_INVALID_INPUT_IMAGE);
+              return;
+            }
+            loadImageFromUri(data.uri, function(img) {
+              g_currentFilename = data.name;
+              g_currentImage = img;
+              createFrame();
+              // Send the event to Analytics
+              _gaq.push(['_trackEvent', 'Distribute', 'Create Device Art', g_currentDevice.title]);
+            });
+          });
+        });
+
+    // Set up rotate button.
+    $('#rotate-button').click(function() {
+      if (!g_currentImage) {
+        return;
+      }
+
+      var w = g_currentImage.naturalHeight;
+      var h = g_currentImage.naturalWidth;
+      var canvas = $('<canvas>')
+          .attr('width', w)
+          .attr('height', h)
+          .get(0);
+
+      var ctx = canvas.getContext('2d');
+      ctx.rotate(-Math.PI / 2);
+      ctx.translate(-h, 0);
+      ctx.drawImage(g_currentImage, 0, 0);
+
+      loadImageFromUri(canvas.toDataURL('image/png'), function(img) {
+        g_currentImage = img;
+        createFrame();
+      });
+    });
+  }
+
+  /**
+   * Generates the frame from the current selections (g_currentImage and g_currentDevice).
+   */
+  function createFrame() {
+    var port;
+
+    var aspect1 = g_currentImage.naturalWidth / g_currentImage.naturalHeight;
+    var aspect2 = g_currentDevice.portSize[0] / g_currentDevice.portSize[1];
+
+    if (aspect1 == aspect2) {
+      port = true;
+    } else if (aspect1 == 1 / aspect2) {
+      port = false;
+    } else {
+      alert('The screenshot must have an aspect ratio of ' +
+          aspect2.toFixed(3) + ' or ' + (1 / aspect2).toFixed(3) +
+          ' (ideally ' + g_currentDevice.portSize[0] + 'x' + g_currentDevice.portSize[1] +
+          ' or ' + g_currentDevice.portSize[1] + 'x' + g_currentDevice.portSize[0] + ').');
+      $('#output').html(MSG_INVALID_INPUT_IMAGE);
+      return;
+    }
+
+    // Load image resources
+    var res = port ? g_currentDevice.portRes : g_currentDevice.landRes;
+    var resList = {};
+    for (var i = 0; i < res.length; i++) {
+      resList[res[i]] = 'device-art-resources/' + g_currentDevice.id + '/' +
+          (port ? 'port_' : 'land_') + res[i] + '.png'
+    }
+
+    var resourceImages = {};
+    loadImageResources(resList, function(r) {
+      resourceImages = r;
+      continueWithResources_();
+    });
+
+    function continueWithResources_() {
+      var width = resourceImages['back'].naturalWidth;
+      var height = resourceImages['back'].naturalHeight;
+      var offset = port ? g_currentDevice.portOffset : g_currentDevice.landOffset;
+      var size = port
+          ? g_currentDevice.portSize
+          : [g_currentDevice.portSize[1], g_currentDevice.portSize[0]];
+
+      var canvas = document.createElement('canvas');
+      canvas.width = width;
+      canvas.height = height;
+
+      var ctx = canvas.getContext('2d');
+      if (resourceImages['shadow'] && $('#output-shadow').is(':checked')) {
+        ctx.drawImage(resourceImages['shadow'], 0, 0);
+      }
+      ctx.drawImage(resourceImages['back'], 0, 0);
+      ctx.fillStyle = '#000';
+      ctx.fillRect(offset[0], offset[1], size[0], size[1]);
+      ctx.drawImage(g_currentImage, offset[0], offset[1], size[0], size[1]);
+      if (resourceImages['fore'] && $('#output-glare').is(':checked')) {
+        ctx.drawImage(resourceImages['fore'], 0, 0);
+      }
+
+      window.URL = window.URL || window.webkitURL;
+      if (canvas.toBlob && window.URL.createObjectURL) {
+        if (g_currentObjectURL) {
+          window.URL.revokeObjectURL(g_currentObjectURL);
+          g_currentObjectURL = null;
+        }
+        if (g_currentBlob) {
+          if (g_currentBlob.close) {
+            g_currentBlob.close();
+          }
+          g_currentBlob = null;
+        }
+
+        canvas.toBlob(function(blob) {
+          if (!blob) {
+            continueWithFinalUrl_(canvas.toDataURL('image/png'));
+            return;
+          }
+          g_currentBlob = blob;
+          g_currentObjectURL = window.URL.createObjectURL(blob);
+          continueWithFinalUrl_(g_currentObjectURL);
+        }, 'image/png');
+      } else {
+        continueWithFinalUrl_(canvas.toDataURL('image/png'));
+      }
+    }
+
+    function continueWithFinalUrl_(imageUrl) {
+      var filename = g_currentFilename
+          ? g_currentFilename.replace(/^(.+?)(\.\w+)?$/, '$1_framed.png')
+          : 'framed_screenshot.png';
+
+      var $link = $('<a>')
+          .attr('download', filename)
+          .attr('href', imageUrl)
+          .append($('<img>')
+              .addClass('dragout')
+              .attr('src', imageUrl)
+              .attr('draggable', true)
+              .attr('data-downloadurl', ['image/png', filename, imageUrl].join(':')))
+          .appendTo($('#output').empty());
+
+      $('#frame-customizations').show();
+    }
+  }
+
+  /**
+   * Loads an image from a data URI. The callback will be called with the <img> once
+   * it loads.
+   */
+  function loadImageFromUri(uri, callback) {
+    callback = callback || function(){};
+
+    var img = document.createElement('img');
+    img.src = uri;
+    img.onload = function() {
+      callback(img);
+    };
+    img.onerror = function() {
+      callback(null);
+    }
+  }
+
+  /**
+   * Loads a set of images (organized by ID). Once all images are loaded, the callback
+   * is triggered with a dictionary of <img>'s, organized by ID.
+   */
+  function loadImageResources(images, callback) {
+    var imageResources = {};
+
+    var checkForCompletion_ = function() {
+      for (var id in images) {
+        if (!(id in imageResources))
+          return;
+      }
+      (callback || function(){})(imageResources);
+      callback = null;
+    };
+
+    for (var id in images) {
+      var img = document.createElement('img');
+      img.src = images[id];
+      (function(img, id) {
+        img.onload = function() {
+          imageResources[id] = img;
+          checkForCompletion_();
+        };
+        img.onerror = function() {
+          imageResources[id] = null;
+          checkForCompletion_();
+        }
+      })(img, id);
+    }
+  }
+
+  /**
+   * Loads the first valid image from a FileList (e.g. drag + drop source), as a data URI. This
+   * method will throw an alert() in case of errors and call back with null.
+   *
+   * @param {FileList} fileList The FileList to load.
+   * @param {Function} callback The callback to fire once image loading is done (or fails).
+   * @return Returns an object containing 'uri' representing the loaded image. There will also be
+   *      a 'name' field indicating the file name, if one is available.
+   */
+  function loadImageFromFileList(fileList, callback) {
+    fileList = fileList || [];
+
+    var file = null;
+    for (var i = 0; i < fileList.length; i++) {
+      if (fileList[i].type.toLowerCase().match(/^image\/(png|jpeg|jpg)/)) {
+        file = fileList[i];
+        break;
+      }
+    }
+
+    if (!file) {
+      alert('Please use a valid screenshot file (PNG or JPEG format).');
+      callback(null);
+      return;
+    }
+
+    var fileReader = new FileReader();
+
+    // Closure to capture the file information.
+    fileReader.onload = function(e) {
+      callback({
+        uri: e.target.result,
+        name: file.name
+      });
+    };
+    fileReader.onerror = function(e) {
+      switch(e.target.error.code) {
+        case e.target.error.NOT_FOUND_ERR:
+          alert('File not found.');
+          break;
+        case e.target.error.NOT_READABLE_ERR:
+          alert('File is not readable.');
+          break;
+        case e.target.error.ABORT_ERR:
+          break; // noop
+        default:
+          alert('An error occurred reading this file.');
+      }
+      callback(null);
+    };
+    fileReader.onabort = function(e) {
+      alert('File read cancelled.');
+      callback(null);
+    };
+
+    fileReader.readAsDataURL(file);
+  }
+
+  /**
+   * Adds a simple version of Canvas.toBlob if toBlob isn't available.
+   */
+  function polyfillCanvasToBlob() {
+    if (!HTMLCanvasElement.prototype.toBlob && window.Blob) {
+      HTMLCanvasElement.prototype.toBlob = function(callback, mimeType, quality) {
+        if (typeof callback != 'function') {
+          throw new TypeError('Function expected');
+        }
+        var dataURL = this.toDataURL(mimeType, quality);
+        mimeType = dataURL.split(';')[0].split(':')[1];
+        var bs = window.atob(dataURL.split(',')[1]);
+        if (dataURL == 'data:,' || !bs.length) {
+          callback(null);
+          return;
+        }
+        for (var ui8arr = new Uint8Array(bs.length), i = 0; i < bs.length; ++i) {
+          ui8arr[i] = bs.charCodeAt(i);
+        }
+        callback(new Blob([ui8arr.buffer /* req'd for Safari */ || ui8arr], {type: mimeType}));
+      };
+    }
+  }
+</script>
diff --git a/docs/html/distribute/tools/promote/linking.jd b/docs/html/distribute/tools/promote/linking.jd
new file mode 100644
index 0000000..025480b
--- /dev/null
+++ b/docs/html/distribute/tools/promote/linking.jd
@@ -0,0 +1,218 @@
+page.title=Linking to Your Products
+page.image=/images/gp-linking-ex-crop.png
+meta.tags="promoting"
+page.tags="linking"
+page.metaDescription=Learn how to build links that take users to your published apps in Google Play from browse or search.
+
+@jd:body
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<a href="badges.html">
+  <img alt="Get it on Google Play"
+       src="{@docRoot}images/brand/en_app_rgb_wo_45.png" />
+</a>
+<p>For a link that includes the Google Play brand icon, check out the <a href="badges.html">Badges</a> page. </p>
+</div>
+</div>
+
+<p>Google Play provides several link formats that let you bring users to your
+products in the way you want, from Android apps, web pages, ads, reviews,
+articles, social media posts, and more.</p> 
+
+<p>The link formats let you:</p>
+<ul>
+<li>Link to a specific app's <a href="#OpeningDetails">product details page</a></li>
+<li>Link to a <a href="#OpeningPublisher">list of all of your apps</a>, or</li>
+<li>Link to a <a href="#PerformingSearch">search result</a> of your choice</li>
+<li>Link to a <a href="#OpeningCollection">collection</a> on Google Play</li>
+</ul>
+
+<p>If you are linking from an Android app, you can also control whether the link
+launches the Play Store application or the browser, which takes the user
+to the Google Play website.</p>
+
+<h2 id="OpeningDetails">Linking to a Product Details Page</h2>
+
+<p>Use the format below to deep-link users directly to a specific app's product
+details page. At the product details page, users can see the app description,
+screenshots, reviews and more, and then install it.</p>
+
+<p>To create the link, you need to know the app's fully qualified <em>package
+name</em>, which is declared in the app's <a
+href="{@docRoot}guide/topics/manifest/manifest-element.html#package">manifest
+file</a>. The package name is also visible in the Developer Console. </p>
+
+<dl>
+<dt><strong>From a web site:</strong></dt>
+<dd>
+<pre>http://play.google.com/store/apps/details?id=&lt;package_name&gt;</pre>
+</dd>
+<dt><strong>From an Android app:</strong></dt>
+<dd>
+<pre>market://details?id=&lt;package_name&gt;</pre>
+</dd>
+</dl>
+
+<p>Here's an example:</p>
+
+<p style="margin-left:1em;"><code><a href="http://play.google.com/store/apps/details?id=com.google.android.apps.maps">http://play.google.com/store/apps/details?id=com.google.android.apps.maps</a></code></p>
+
+<p>For details on how to send the link in an Android app, see <a href="#android-app">Linking from an Android App</a>.</p>
+
+
+
+<h2 id="OpeningPublisher">Linking to a Product List</h2>
+
+<p>Use the format below to link users to a list of apps published by you. The
+product list lets users see all of the apps from a specific publisher, with
+ratings, editorial badges, and an Install button for each. </p>
+
+<p>To create the link, you need to know your <em>publisher name</em>, which is
+available from the Developer Console. </p>
+
+<dl>
+<dt><strong>From a web site:</strong></dt>
+<dd>
+<pre>http://play.google.com/store/search?q=pub:&lt;publisher_name&gt;</pre>
+</dd>
+<dt><strong>From an Android app:</strong></dt>
+<dd>
+<pre>market://search?q=pub:&lt;publisher_name&gt;</pre>
+</dd>
+</dl>
+
+<p>Here's an example:</p>
+
+<p style="margin-left:1em;"><code><a href="http://play.google.com/store/search?q=pub:Google Inc.">http://play.google.com/store/search?q=pub:Google Inc.</a></code></p>
+
+<p>For details on how to send the link in an Android app, see <a href="#android-app">Linking from an Android App</a>.</p>
+
+
+<h2 id="PerformingSearch">Linking to a Search Result</h2>
+
+<p>Use the format below to link users to a search query result on Google Play.
+The search result page shows a list of apps (and optionally other content) that
+match the query, with ratings, badges, and an Install button for each. </p>
+
+<p>To create the link, you just need a search query string. If you want the
+query to search outside of the Google Play Apps listings, you can remove the
+<code>&c=apps</code> part of the link URL.</p>
+
+<dl>
+<dt><strong>From a web site:</strong></dt>
+<dd>
+<pre>http://play.google.com/store/search?q=&lt;search_query&gt;&c=apps</pre>
+</dd>
+<dt><strong>From an Android app:</strong></dt>
+<dd>
+<pre>market://search?q=&lt;seach_query&gt;&c=apps</pre>
+</dd>
+</dl>
+
+<p>Here's an example:</p>
+
+<p style="margin-left:1em;"><code><a href="http://play.google.com/store/search?q=maps&c=apps">http://play.google.com/store/search?q=maps&c=apps</a></code></p>
+
+<p>For details on how to send the link in an Android app, see <a href="#android-app">Linking from an Android App</a>.</p>
+
+
+
+<h2 id="OpeningCollection">Linking to a Collection</h2>
+
+<p>If your app is featured or appears in one of the Google Play Top charts or
+collections, you can use the format below to link users directly to the
+collection. The collection shows a ranked list of apps in the collection, with
+ratings, short descriptions, and an Install button.</p>
+
+<dl>
+<dt><strong>From a web site:</strong></dt>
+<dd>
+<pre>http://play.google.com/store/apps/collection/&lt;collection_name&gt;</pre>
+</dd>
+<dt><strong>From an Android app:</strong></dt>
+<dd>
+<pre>market://apps/collection/&lt;collection_name&gt;</pre>
+</dd>
+</dl>
+
+<p>Here's an example:</p>
+
+<p style="margin-left:1em;"><code><a href="http://play.google.com/store/apps/collection/editors_choice">http://play.google.com/store/apps/collection/editors_choice</a></code></p>
+
+<p>For details on how to send the link in an Android app, see <a href="#android-app">Linking from an Android App</a>.</p>
+
+<p class="table-caption"><strong>Table 1.</strong> Collections on Google Play</a>.</p>
+
+<table>
+<tr>
+<th>Collection</th><th>collection_name</th>
+</tr>
+<tr><td>Staff Picks (Featured)</td><td>featured</td></tr>
+<tr><td>Editor's Choice</td><td>editors_choice</td></tr>
+<tr><td>Top Paid</td><td>topselling_paid</td></tr>
+<tr><td>Top Free</td><td>topselling_free</td></tr>
+<tr><td>Top New Free</td><td>topselling_new_free</td></tr>
+<tr><td>Top New Paid</td><td>topselling_new_paid</td></tr>
+<tr><td>Top Grossing</td><td>topgrossing</td></tr>
+<tr><td>Trending</td><td>movers_shakers</td></tr>
+<tr><td>Best Selling in Games</td><td>topselling_paid_game</td></tr>
+</table>
+
+
+<h2 id="android-app">Linking from an Android App</h2>
+
+<p>There are two general formats for links that are accessible to users on
+Android devices, The two formats trigger slightly different behaviors on the
+device:</p>
+
+<ul>
+<li><code>market://</code> &nbsp;&nbsp; Launches the Play Store app to load the
+target page.</li>
+<li><code>http://</code> &nbsp;&nbsp; Lets the user choose whether to launch the
+Play Store app or the browser to handle the request. If the browser handles the
+request, it loads the target page on the Google Play web site.</li>
+</ul>
+
+<p>In general, you should use <code>http://</code> format for links on web pages
+and <code>market://</code> for links in Android apps.</p>
+
+<p>If you want to link to your products from an Android app, create an {@link
+android.content.Intent} that opens a Google Play URL, as shown in the example
+below.</p>
+
+<pre>
+Intent intent = new Intent(Intent.ACTION_VIEW);
+intent.setData(Uri.parse("market://details?id=com.example.android"));
+startActivity(intent);
+</pre>
+
+
+<h2 id="UriSummary">Summary of URL formats</h2>
+
+<p>The table below provides a summary of the URIs currently supported by the Google Play (both on
+the web and in an Android application), as discussed in the previous sections.</p>
+
+<table>
+<tr>
+<th>For&nbsp;this&nbsp;result</th>
+<th>Web page link</th>
+<th>Android app link</th>
+</tr>
+<tr>
+<td style="width:72px;">Show the product details page for a specific app</td>
+<td><code>http://play.google.com/store/apps/details?id=&lt;package_name&gt;</code>
+<td><code>market://details?id=&lt;package_name&gt;</code></td>
+</tr>
+<tr>
+<td>Show apps by a specific publisher</td>
+<td><nobr><code>http://play.google.com/store/search?q=pub:&lt;publisher_name&gt;</code></nobr></td>
+<td><nobr><code>market://search?q=pub:&lt;publisher_name&gt;</code></nobr></td>
+</tr>
+<tr>
+<td>Search for apps using a general string query.</td>
+<td><code>http://play.google.com/store/search?q=&lt;query&gt;</code></td>
+<td><code>market://search?q=&lt;query&gt;</code></td>
+</tr>
+</table>
+
diff --git a/docs/html/distribute/users/build-buzz.jd b/docs/html/distribute/users/build-buzz.jd
new file mode 100644
index 0000000..b76498e
--- /dev/null
+++ b/docs/html/distribute/users/build-buzz.jd
@@ -0,0 +1,301 @@
+page.title=Build Buzz
+page.image=/distribute/images/build-buzz.jpg
+page.metaDescription=Generate interest and demand for your app. Here are some ways to help users find, download, and install your apps.
+page.tags="users, growth, promotion"
+
+@jd:body
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>
+      Contents
+    </h2>
+
+    <ol>
+      <li>
+        <a href="#link-to-your-apps">Link to Your Apps</a>
+      </li>
+      <li>
+        <a href="#use-the-google-play-badge">Use the Badge</a>
+      </li>
+      <li>
+        <a href="#cross-promote-from-your-other-apps">Cross-Promote Your Apps</a>
+      </li>
+      <li>
+        <a href="#hold-a-contest">Hold a Contest</a>
+      </li>
+      <li>
+        <a href="#leverage-pr">Leverage PR</a>
+      </li>
+      <li>
+        <a href="#use-social-media">Use Social Media</a>
+      </li>
+      <li>
+        <a href="#publish-youtube-videos">Publish YouTube Videos</a>
+      </li>
+      <li>
+        <a href="#advertise">Advertise</a>
+      </li>
+      <li>
+        <a href="#maximize-your-marketing-spend">Maximize Your Marketing
+        spend</a>
+      </li>
+      <li><a href="#related-resources">Related Resources</a></li>
+    </ol>
+  </div>
+</div>
+
+<div style="float:right;border 2px solid #ddd;">
+  <img src="{@docRoot}distribute/images/build-buzz.jpg" style=
+  "width:240px;margin:0 0 1.5em 1em;">
+</div>
+
+<p>
+  With more apps published each week in Google Play, building  buzz
+  around your own apps helps them get noticed and makes it easier for
+  users to find and download them.
+</p>
+
+<p>
+  Building buzz doesn’t have a single formula. The tools and techniques
+  described here have worked for other developers, but finding the right mix
+  will depend on your apps, your audience, and your competition. And don’t be
+  afraid to try something different or quirky, taking a risk could pay big
+  dividends.
+</p>
+
+<div class="headerLine">
+  <h1 id="link-to-your-apps">
+    Link to Your Apps in Google Play
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  After publishing your apps, you can take Android users directly to your
+  app/games detail page on Google Play by <a href=
+  "{@docRoot}distribute/tools/promote/linking.html">providing links</a> in your
+  social network posts, ad campaigns, app reviews and articles, your website,
+  and more.
+</p>
+
+<p>
+  You can also link to:
+</p>
+
+<ul>
+  <li>A <a href=
+  "{@docRoot}distribute/tools/promote/linking.html#OpeningPublisher">list</a>
+  of all of your apps
+  </li>
+
+  <li>A Google Play <a href=
+  "{@docRoot}distribute/tools/promote/linking.html#PerformingSearch">search
+  result</a>
+  </li>
+
+  <li>A <a href=
+  "{@docRoot}distribute/tools/promote/linking.html#OpeningCollection">collection</a>
+  on Google Play
+  </li>
+</ul>
+
+<div class="headerLine clearfloat">
+  <h1 id="use-the-google-play-badge">
+    Use the Google Play Badge
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure" style="margin:0 3em;">
+  <img src="{@docRoot}images/gp-build-buzz-uplift-1.png">
+</div>
+
+<p>
+  <a href="{@docRoot}distribute/tools/promote/badges.html">Google Play
+  badges</a> are an especially great way let Android users know that your apps
+  are available and link them directly to your Google Play page. Users are more
+  likely to download and trust your apps and games when the Google Play badge
+  is used.
+</p>
+
+<p>Badge your
+  websites, collateral, and ad campaigns. With the badge generator, they're
+  also easy to make and available in multiple languages.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="cross-promote-from-your-other-apps">
+    Cross-Promote from Your Other Apps
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure-right">
+  <img src="{@docRoot}images/gp-buzz-1.jpg">
+  <p class="img-caption">
+    Cross-promoting related apps.
+  </p>
+</div>
+
+<p>
+  Cross promoting, or house ads, is a great cost effective way to get users to
+  try out new titles. Be sure that your house ad is unobtrusive and presented
+  at a time convenient for users to leave your apps and try out your new title.
+  Also, be sure to include logic that allows users to dismiss the ad and
+  control if they will be asked again later.
+</p>
+
+<p>
+  Consider using free AdMob <a href=
+  "https://support.google.com/admob/v2/answer/3210452?hl=en#subid=us-en-et-dac">
+  house ads</a> within your apps to create awareness and promote your entire
+  portfolio of apps. When launching new apps, an easy way to quickly attract
+  users is to promote directly to your existing customers.
+</p>
+
+<div class="headerLine">
+  <h1 id="hold-a-contest">
+    Hold a Contest
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Contests can be a great way to engage your users. If you have a game, hold a
+  tournament and promote it through your marketing channels. Use Google Play
+  Games APIs for leaderboards and achievements to stimulate competition. Some
+  app developers have provided prizes for creative uses of an app or social
+  engagement. For example, a photo app developer can hold a photo contest.
+</p>
+
+<p>
+  But be sure you’re complying with the appropriate legal requirements in your
+  country and provide a clear set of terms and conditions, accessible online.
+  Don’t let a lack of attention to detail spoil a great marketing opportunity.
+</p>
+
+<div class="headerLine">
+  <h1 id="leverage-pr">
+    Leverage PR
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Public Relations outreach can be a valuable marketing initiative. Many
+  developers use PR to announce new features in their apps or games, which, in
+  turn, builds demand for the updated release when it comes out. You can also
+  provide early copies of your app or game for the press to review, and publish
+  their reviews when the app or game launches.
+</p>
+
+<div class="headerLine">
+  <h1 id="use-social-media">
+    Use Social Media
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Social media is your opportunity to build promotion for your apps. Start with
+  your own channels: update users on your plans before launch, announce your
+  launch, and talk about progress after launch (downloads, new features, and
+  alike.) Then expand by encouraging your users to forward and share your
+  posts.
+</p>
+
+<p>
+  Take advantage of bloggers. Look for bloggers that cover Android and learn
+  what interest them. Remember to look locally as well as globally, gaining a
+  local following can be a great springboard to global success. When you’ve
+  selected a target group of bloggers focus on them by sending details of your
+  apps and free versions if the apps are priced. Follow up and ask them to
+  review your apps. A review on the right blog is a great promotion.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="publish-youtube-videos">
+    Publish YouTube Videos
+  </h1>
+
+  <hr>
+</div>
+
+<div class="center-img" style="padding-top:1em;">
+  <img src="{@docRoot}images/gp-build-buzz-yt.png">
+</div>
+
+<p>
+  YouTube videos are now an essential part of building buzz. Use them to
+  showcase your apps’ feature. Remember to do this before, at, and after
+  launch. Taking users on a journey through the development of your apps can be
+  a great way to drive downloads at launch.
+</p>
+
+<div class="headerLine">
+  <h1 id="advertise">
+    Advertise
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/google/gps-ads.png" style="width:340px">
+</div>
+
+<p>
+  Advertise your app in other apps to increase downloads. There are many tools
+  to help you target the right users for your apps and games. You can use
+  <a href=
+  "http://www.google.com/ads/admob/promote.html#subid=us-en-et-dac">AdMob</a>
+  to drive installs of your app at a target cost-per-acquisition (CPA). You
+  also get free house ads for your own app. <a href=
+  "https://apps.admob.com/admob/signup?subid=us-en-et-dac&amp;_adc=ww-ww-et-admob2&amp;hl=en">
+  Sign up for an AdMob account</a> to get started.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="maximize-your-marketing-spend">
+    Maximize your Marketing Spend
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure" style="margin: 0 3em;">
+  <img src="{@docRoot}images/gp-build-buzz-uplift-2.png" style="">
+</div>
+
+<p>
+  Maximize buzz and leverage the halo effect of cross-platform, multimedia,
+  simultaneous launches.
+</p>
+
+<p><strong>Developers who launch on multiple platforms at
+  the same time have received a 10-20% uplift.</strong>If you’re spending money
+  to advertise your launch or spending effort on press, shipping on multiple
+  platforms simultaneously helps you maximize your return on investment.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="related-resources">
+    Related Resources
+  </h1>
+
+  <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/users/buildbuzz"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/users/build-community.jd b/docs/html/distribute/users/build-community.jd
new file mode 100644
index 0000000..1623939
--- /dev/null
+++ b/docs/html/distribute/users/build-community.jd
@@ -0,0 +1,202 @@
+page.title=Build Community
+page.metaDescription=Build a loyal following with great support and communication.
+page.tags="users, growth, community"
+
+@jd:body
+
+<div id="qv-wrapper">
+  <div id="qv">
+  <h2>
+    Contents
+  </h2>
+
+  <ol>
+    <li>
+    <a href="#starting-your-community">Starting Your Community</a>
+    </li>
+
+    <li>
+    <a href="#tools-to-build-your-community">Tools to Build Your Community</a>
+    </li>
+
+    <li>
+    <a href="#managing-your-community">Managing Your Community</a>
+    </li>
+    <li>
+    <a href="#related-resources">Related Resources</a>
+    </li>
+  </ol>
+  </div>
+</div>
+
+<p>
+  Fans of your apps love to help others, turn newer users into fans, and bring
+  you more users as they talk about your app. Building a community can help you
+  tap into those influencers to help you improve your app and provide support
+  to others.
+</p>
+
+<p>
+  Building your own community can help you bring content that will delight
+  users and get them talking about your apps to friends, family and others in
+  their social network.
+</p>
+
+<div class="headerLine">
+  <h1 id="starting-your-community">
+  Starting Your Community
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  In conjunction with your apps’ design and development, you should start
+  defining and building your community infrastructure. There’s no one approach
+  that fits all, and the approach for each of your apps may need to be a little
+  different. You should start by thinking about your potential users and asking
+  questions such as:
+</p>
+
+<ul>
+  <li>
+  <p>
+    How will my users prefer to interact? Game users may prefer a modern feed
+    style community, users of a financial management app a more traditional
+    discussion forum.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Should I have a community for all my apps or should each app have its
+    own? Will users be turned off if the community isn’t just about the app
+    that interests them or can I make it a way to turn them onto my other
+    apps?
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Will different countries or territories, or speakers of particular
+    languages need separate forums? How will I handle feedback in languages I
+    don’t know?
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Do I need any additional policies beyond those governing the tool used to
+    host the community?
+  </p>
+  </li>
+</ul>
+
+<p>
+  Any way you do it, starting your community early helps you build momentum as
+  you turn happy users into influencers.
+</p>
+
+<p>
+  Consider inviting your existing users through a rich notification or an
+  opt-in on your website. Don’t overlook inviting your critics too. If you have
+  been able to address their earlier issues you may convert them into
+  supporters — it’s not unknown for your harshest critics to become your most
+  enthusiastic fans if you address their concerns.
+</p>
+
+<p>
+  When you use the <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">beta-testing
+  feature</a> in Google Play, you’ll create a testers group through a <a href=
+  "https://support.google.com/groups/answer/46601">Google Group</a> or <a href=
+  "https://support.google.com/plus/topic/2888488">Google+ Community</a> to
+  define who gets your software for testing. Consider managing these groups as
+  communities in their own right.
+</p>
+
+<div class="headerLine">
+  <h1 id="tools-to-build-your-community">
+  Tools to Build Your Community
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  There are many tools you can use to build your community. Before you launch,
+  inviting <a href="http://www.google.com/+/business/">Google+</a> users or
+  <a href="https://support.google.com/groups/answer/46601?hl=en">Google
+  Groups</a> to <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">beta-test</a>
+  your app can help you kickstart your community while you listen to and
+  respond to your user feedback.
+</p>
+
+<p>
+  Once you’ve launched, your Google+ or other social media presence can help
+  you continue to gather feedback, answer questions, and get input on updates.
+  Use social media to get the conversation started. Post updates to your
+  followers, announce new apps, and host contests. Ask followers to re-post so
+  that they bring new users into the conversation. Fans love to profess their
+  passion for great apps, so be sure to give them plenty of reason to do so.
+</p>
+
+<p>
+  Forums like <a href=
+  "https://support.google.com/groups/answer/46601?hl=en">Google Groups</a> are
+  particularly well suited to help you and your users provide support to
+  others. By helping out your community, you’re building your fan base who will
+  share their experiences with other prospective customers.
+</p>
+
+<p>
+  Respond to comments and reviews on both your product details page on Google
+  Play and <a href="http://youtube.com">YouTube</a> pages. Prospective
+  customers are influenced by reviews and comments, so be sure to manage your
+  brand in every channel you can.
+</p>
+
+<div class="headerLine">
+  <h1 id="managing-your-community">
+  Managing Your Community
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-community-0.png">
+</div>
+
+<p>
+  Engaged users want you to succeed. Let them know you’re listening! Responding
+  to posts, comments, and other social media mentions improves your ratings by
+  letting users know you care.
+</p>
+
+<p>
+  Update the product based on user feedback and announce new releases. Users
+  often change their original star ratings after feeling heard, inspiring more
+  users to install your apps.
+</p>
+
+<p>
+  There are many ways to make your community feel special. Consider polls to
+  let users influence product updates. Use competitions to inspire and reward
+  your community. Giving a special <em>member of the week</em> badge is an easy
+  way to recognize those that help others. Or get users involved in testing new
+  versions or new apps to make them feel special.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="related-resources">
+  Related Resources
+  </h1>
+  <hr>
+</div>
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/users/buildcommunity"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
\ No newline at end of file
diff --git a/docs/html/distribute/users/expand-to-new-markets.jd b/docs/html/distribute/users/expand-to-new-markets.jd
new file mode 100644
index 0000000..cc94a92
--- /dev/null
+++ b/docs/html/distribute/users/expand-to-new-markets.jd
@@ -0,0 +1,325 @@
+page.title=Expand Into New Markets
+page.metaDescription=Tap fast-growing markets in Japan, Korea, India, Brazil, and many other countries around the world.
+page.image=/distribute/images/expand-into-new-markets.jpg
+page.tags="users, growth, global"
+
+@jd:body
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>
+      Contents
+    </h2>
+
+    <ol>
+      <li>
+        <a href="#localize-your-product">Localize Your Product</a>
+      </li>
+
+      <li>
+        <a href="#testing-and-support">Testing and Support</a>
+      </li>
+
+      <li>
+        <a href="#localize-your-google-play-listing">Localize Your Store
+        Listing</a>
+      </li>
+
+      <li>
+        <a href="#marketing">Marketing</a>
+      </li>
+
+      <li>
+        <a href="#related-resources">Related Resources</a>
+      </li>
+    </ol>
+  </div>
+</div>
+<p>
+  Android and Google Play give you a worldwide audience for your apps, with an
+  addressable user base that's growing very rapidly in countries such as Japan,
+  Korea, India, and Brazil. You can sell your app in more than 130 countries.
+</p>
+
+<p>
+  To <strong>maximize your app's distribution potential and earn high
+  ratings</strong> from users around the world, we encourage you to localize
+  your app. Once you’ve built a solid foundation in your home market, take
+  advantage of Android’s powerful growth around the world and expand your app
+  to new markets.
+</p>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <p>
+      <strong>Tip:</strong> Localization is more than translation. Plan product
+      features, launch, and marketing for key markets.
+    </p>
+  </div>
+</div>
+
+<p class="caution" style="font-size:15.5px;">
+</p>
+
+<p>
+  Localization involves a variety of tasks throughout your app development
+  cycle, and advance planning is essential. But <strong>localization is more
+  than just translating your UI</strong>. To be successful, you also need to
+  localize your Google Play listing and ensure your marketing is suitable for
+  the demographic you’re addressing.
+</p>
+
+<p>
+  To reduce development and maintenance effort, use a single APK for all
+  regions. A single APK also allows you to more easily track metrics by
+  country. Google Play takes care of providing the appropriate localized
+  version of your app based on user location.
+</p>
+
+<div class="headerLine">
+  <h1 id="localize-your-product">
+    Localize Your Product
+  </h1>
+
+  <hr>
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <p>
+      <strong>Tip:</strong> Use a professional translation service located in
+      your target country to ensure high quality and good user ratings.
+    </p>
+  </div>
+</div>
+
+<p>
+  The first step is to identify your target markets and associated languages,
+  then focus your product localization on those countries. Some of the tasks
+  include translating your UI strings and localizing dates and times, layouts,
+  text direction, and finally your Google Play store listing. To learn more
+  about how to localize your app, visit our <a href=
+  "{@docRoot}distribute/tools/localization-checklist.html">Localization
+  Checklist</a>.
+</p>
+<!-- <p>[Need graphic highlighting that it’s all about getting high ratings]</p> -->
+
+<p>
+  Work with a professional translator, preferably located in the country you’re
+  localizing your apps for, to ensure high quality results. Machine
+  translations may affect your apps’ ratings, as they’re less reliable than
+  high-quality professional translations. For example, a professional service
+  will know to consider the vocabulary expansion, left-to-right and
+  right-to-left support, and other factors in each language. Learn more about
+  UI considerations and other factors in the <a href=
+  "{@docRoot}distribute/tools/localization-checklist.html#design">Design for
+  Localization</a> section of the Localization Checklist.
+</p>
+
+<p>
+  <strong>Google Play App Translation Service</strong> can help you quickly
+  find and purchase translations of your apps. In the <a href=
+  "https://play.google.com/apps/publish/">Developer Console</a>, you can browse
+  a list of third-party vendors who are pre-qualified by Google to offer
+  high-quality professional translations at competitive prices.
+</p>
+
+<div style="float:left; width:48%; padding:8px;">
+  <img src="{@docRoot}images/gp-listing-3.jpg">
+</div>
+
+<div style="width:48%; padding:8px; float:left">
+  <img src="{@docRoot}images/gp-expand-2.jpg">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="testing-and-support">
+    Testing and Support
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Before you launch, be sure to use our <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">beta
+  testing</a> and <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#staged-rollouts">staged
+  rollouts</a> to identify and address issues before users can rate your app.
+  Feedback can be gathered using a <a href=
+  "https://support.google.com/groups/answer/46601">Google Group</a> or <a href=
+  "https://support.google.com/plus/topic/2888488">Google+ Community</a>. Watch
+  user sentiment and respond if necessary as you add countries.
+</p>
+
+<p>
+  After you launch, <strong>offer support hours in the local time zone in the
+  local language</strong>. When possible, having a local presence can
+  dramatically increase your daily active users and revenue. For example,
+  <a href="">this developer</a> was able to <strong>increase their revenue over
+  500% after creating a local presence</strong> in Asia and taking great care
+  of their users.
+</p>
+
+<div class="headerLine">
+  <h1 id="localize-your-google-play-listing">
+    Localize Your Google Play Store Listing
+  </h1>
+
+  <hr>
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <p>
+      <strong>Tip:</strong> You can select regions, set regional pricing, and
+      localize your listing while maintaining only one APK.
+    </p>
+  </div>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-buyer-currency.png" class="border-img">
+</div>
+
+<p>
+  Within your Google Play listing, you’ll need to set the regions in which your
+  apps will be available, set pricing for each, and customize your Google Play
+  listing to ensure it speaks to local audiences. You can change your country
+  and carrier targeting at any time just by saving changes in the Google Play
+  Developer Console.
+</p>
+
+<h3>
+  Region selection
+</h3>
+
+<p>
+  In the Developer Console, you can set the regions you make your app available
+  to, pricing in local currencies, and all Google Play listing marketing. You
+  can specify which countries and territories you want to distribute to, and
+  even which carriers (for some countries).
+</p>
+
+<h3>
+  Pricing
+</h3>
+
+<p>
+  When you start to address new markets you have several options for setting
+  the prices of your products: apps, in-app products, and subscriptions. You
+  can set a default price for each product and allow Google Play to adjust this
+  each month for changes in exchange rates, or manually set prices.
+</p>
+
+<p>
+  There are several reasons why it might be beneficial to set prices manually,
+  such as:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Cost of living differences. To better target developing markets you may
+      consider offering your apps at a lower price to make them more affordable
+      in relation to local incomes.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Price perception. Users in some countries respond well to prices set to
+      x.99, while others prefer x.00 pricing.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Numerology. You may wish to avoid using certain numbers that are
+      considered unlucky, such as 13 or 4.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Competition. Your app may have local competition in some markets that you
+      need to account for.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Local trends and interests. Your apps may be able to bear a higher price
+      in some markets. For example, the interest in various sports varies
+      greatly from country to country.
+    </p>
+  </li>
+</ul>
+
+<p>
+  You may also want to run short-term promotions and discounts in specific
+  countries.
+</p>
+
+<p>
+  The <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#selling-pricing-your-products">
+  Pricing &amp; Distribution</a> section in the <a href=
+  "https://play.google.com/apps/publish/">Developer Console</a> is where you
+  set and manage regional distribution and local prices.
+</p>
+
+<h3>
+  Copy and creative
+</h3>
+
+<p>
+  To market to users around the world, <strong>localize your store listing,
+  including app details and description, promotional graphics, screenshots, and
+  more.</strong> Graphical assets and copy can be uploaded for each country you
+  are targeting.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-expand-4.jpg" class="border-img">
+</div>
+
+<div>
+  <img src="{@docRoot}images/gp-expand-5.jpg" class="border-img">
+</div>
+
+<p>
+  Learn more about how to localize your <a href=
+  "{@docRoot}distribute/tools/launch-checklist.html#prepare-graphics">store
+  listing</a>.
+</p>
+
+<div class="headerLine">
+  <h1 id="marketing">
+    Marketing
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-badge-jp.png">
+</div>
+
+<p>
+  Just like your Google Play listing, all other marketing should be localized
+  to speak to the local audience. This includes images, colors, icons, and
+  audio. To maximize effectiveness, <strong>run promotions, contests, and
+  announcements at local time</strong>. You can build a localized <a href=
+  "{@docRoot}distribute/tools/promote/badges.html">Google Play badge</a> and
+  <a href="{@docRoot}distribute/tools/promote/device-art.html">device art</a>
+  for each language you support.
+</p>
+
+<div class="headerLine clearfloat"><h1 id="related-resources">Related Resources</h1><hr></div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/getusers/expandnewmarkets"
+  data-sortOrder="-timestamp"
+  data-cardSizes="6x3,6x3,6x3,6x3,6x3,6x3"
+  data-maxResults="6"></div>
diff --git a/docs/html/distribute/users/index.jd b/docs/html/distribute/users/index.jd
new file mode 100644
index 0000000..77ef609
--- /dev/null
+++ b/docs/html/distribute/users/index.jd
@@ -0,0 +1,30 @@
+page.title=Get Users
+section.landing=true
+nonavpage=true
+
+@jd:body
+
+<p>
+  You’ve published your app, now how do you acquire users? Every app and game
+  is different, but there are some common themes from successful Google Play
+  developers. These best practices are critical to your app or game’s success.
+</p>
+
+<div class="dynamic-grid">
+
+<div class="resource-widget resource-flow-layout landing col-16"
+  data-query="collection:distribute/users"
+  data-cardSizes="6x6, 6x6, 6x6, 9x6, 9x6, 6x6, 6x6, 6x6"
+  data-maxResults="8">
+</div>
+
+<h3>Related resources</h3>
+
+  <div class="resource-widget resource-flow-layout col-16"
+    data-query="type:youtube+tag:users,tag:global,type:blog+tag:users"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x3"
+    data-maxResults="6">
+  </div>
+  
+</div>
diff --git a/docs/html/distribute/users/know-your-user.jd b/docs/html/distribute/users/know-your-user.jd
new file mode 100644
index 0000000..fb91a05
--- /dev/null
+++ b/docs/html/distribute/users/know-your-user.jd
@@ -0,0 +1,153 @@
+page.title=Know Your User
+page.metaDescription=It\'s essential to understand your users and listen to their input. Here are some ideas.
+page.image=/distribute/images/know-your-user.jpg
+page.tags="users, growth, global"
+
+@jd:body
+
+<div style="width:100%">
+  <img src="{@docRoot}images/gp-androidify.png">
+</div>
+
+<p>
+  A key part of growing your apps' installed base is knowing more about your
+  users &mdash; how they discover your app, what devices they use, what they do
+  when they use your app, and how often they return to it.
+</p>
+
+<div class="headerLine">
+  <h1 id="read-ratings-comments">
+  Read Ratings Comments
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  The most obvious way to get to know your users is by reading review comments
+  for your apps on Google Play. While the details provided in reviews will vary
+  greatly, in addition to telling you about what users like and dislike in your
+  apps, they can also provide insight into your users’ motivations for using
+  your apps. And remember that users can update their ratings and comments
+  about an app when you fix issues.
+</p>
+
+<p>
+  Learn more about <a href=
+  "{@docRoot}distribute/essentials/optimizing-your-app.html#listen-to-your-users">
+  how to listen to users</a>.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-your-user-0.jpg" class="border-img">
+  <p class="img-caption">
+  User ratings
+  </p>
+</div>
+
+<div class="headerLine">
+  <h1 id="start-community">
+  Start a Community
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Another great way to get to know your users, learn who they are, and what
+  they are looking for, is to start a community. There are many support tools
+  you can use, from forums such as <a href="http://groups.google.com/">Google
+  Groups</a> to comprehensive customer support products. You can integrate some
+  directly into your apps. And once you deploy a support tool, make sure to
+  fill in the support link in your Google Play product details page.
+</p>
+
+<p>
+  <a href="{@docRoot}distribute/users/build-community.html">Learn more about
+  starting and managing a community</a>.
+</p>
+
+<div class="headerLine">
+  <h1 id="create-survey">
+  Create a Survey
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Consider using a survey to gather information about your users and their
+  views on your apps. Compared to app reviews, a questionnaire enables you to
+  seek specific information. However use with care, as the creation of suitable
+  question is something of an art. Also consider providing an appropriate
+  incentive for completing the questionnaire, as too few responses can be worse
+  than no responses at all.
+</p>
+
+<p>
+  You can create a questionnaire with <a href=
+  "http://www.google.com/drive/apps.html#forms">Google Drive Forms</a> or use
+  one of the various third-party survey and questionnaire hosting tools
+  available, such as SurveyMonkey.
+</p>
+
+<div class="headerLine">
+  <h1 id="add-analytics">
+  Add Analytics to your Apps
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Analytics data can tell you a lot about your users, by exposing their
+  behaviour in your apps. You can use <a href=
+  "http://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html">
+  Google Analytics by linking it with your Google Play account</a> or use a
+  third-party analytics tool. Analytics tools can help you gather information
+  on app installs, feature popularity, unused features, and more. You can see
+  any usage pattern differences by region, device, time day and other
+  variables.
+</p>
+
+<p>
+  Read more about <a href=
+  "{@docRoot}distribute/essentials/optimizing-your-app.html#measuring-analyzing-responding">
+  measuring behavior</a>.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-dc-stats.png" class="border-img">
+</div>
+
+<div class="headerLine">
+  <h1 id="use-google">
+  Use Google+
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  <a href="https://plus.google.com/">Google+</a> is a great way to gather user
+  feedback, announce surveys and contests, and see how users react to new
+  features and functionality. Many developers manage a Google+ page to
+  communicate with their users. It’s also a good way to get feedback from your
+  beta-testing. Some developers have a page for each of their apps. This is
+  especially true for game developers, who post challenges and tournaments.
+  Google+ can also be used to post game walkthroughs and tips.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-your-user-2.jpg">
+</div>
+
+<div class="headerLine clearfloat">
+<h1 id="related-resources">Related Resources</h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/users/knowyouruser"
+  data-sortOrder="-timestamp"
+  data-cardSizes="6x3"
+  data-maxResults="6"></div>
\ No newline at end of file
diff --git a/docs/html/distribute/users/users_toc.cs b/docs/html/distribute/users/users_toc.cs
new file mode 100644
index 0000000..a2437a6
--- /dev/null
+++ b/docs/html/distribute/users/users_toc.cs
@@ -0,0 +1,40 @@
+<ul id="nav">
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/know-your-user.html">
+            <span class="en">Know Your User</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/your-listing.html">
+            <span class="en">Create a Great Listing</span>
+          </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/build-buzz.html">
+          <span class="en">Build Buzz</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/build-community.html">
+          <span class="en">Build Community</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/expand-to-new-markets.html">
+          <span class="en">Expand to New Markets</span>
+        </a>
+    </div>
+  </li>
+
+</ul>
+
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
diff --git a/docs/html/distribute/users/your-listing.jd b/docs/html/distribute/users/your-listing.jd
new file mode 100644
index 0000000..cc72fff
--- /dev/null
+++ b/docs/html/distribute/users/your-listing.jd
@@ -0,0 +1,191 @@
+page.title=Create a Great Listing
+page.metaDescription=Make your listing page compelling and integrate it into your marketing campaigns.
+page.image=/distribute/images/create-listing.jpg
+page.tags="listing, google play, users, growth"
+
+@jd:body
+
+<p>
+  Your Google Play app listings are a vital part of your app marketing, from
+  organic traffic or visits you generate through marketing and promotion.
+  Potential users will quickly move on from a poor listing, so the importance
+  of having a great one can't be ignored.
+</p>
+
+<div class="headerLine">
+  <h1 id="graphics-imagery">
+    Graphics &amp; Imagery Tips
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Be sure to supply a variety of high-quality graphic assets to showcase your
+  apps or brand on Google Play search results and your product details pages.
+  These graphic assets are key parts of successful product details pages that
+  attracts and engages users, so consider having a professional produce them
+  for you.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-listing-0.jpg" class="border-img">
+</div>
+
+<h3>
+  Icons
+</h3>
+
+<p>
+  For most users, the <a href=
+  "{@docRoot}design/style/iconography.html#launcher">launcher icon</a>
+  (sometimes referred to as the app icon) is the first impression of your app.
+  As higher density screens on both phones and tablets gain popularity, it's
+  important to make sure your launcher icon is crisp and high quality. To do
+  this, make sure you’re including XHDPI (320dpi) and XXHDPI (480dpi) versions
+  of the icon in your apps. Learn more about <a href=
+  "http://android-developers.blogspot.com/2013/07/making-beautiful-android-app-icons.html">
+  Making Beautiful Android App Icons</a> from the <a href=
+  "http://android-developers.blogspot.com/">Android Developers blog</a>.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-listing-1.png" class="border-img">
+</div>
+
+<h3>
+  Screenshots and videos
+</h3>
+
+<p>
+  Be sure to showcase how your apps look, their important features, and what
+  makes them different. Showcase any game play, characters, and their
+  personalities. Some developers build special screens to highlight what’s
+  happening in the screenshot, and extra video footage to highlight the brand.
+  Get more details <a href=
+  "{@docRoot}distribute/tools/launch-checklist.html#prepare-graphics">here</a>.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-listing-2.jpg">
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <p>
+      <strong>Tip:</strong> If your app runs on both phones and tablets, be
+      sure to include screenshots from both devices, including both horizontal
+      and portrait aspect ratios.
+    </p>
+  </div>
+</div>
+
+<h3>
+  Featured image
+</h3>
+
+<p>
+  Choosing the right featured image is important, it needs to convey as much
+  about the features of your apps and what makes them special as possible,
+  without being cluttered and confusing. Check out the <a href=
+  "http://android-developers.blogspot.com/">Android Developers blog</a> post
+  for more <a href=
+  "http://android-developers.blogspot.com/2011/10/android-market-featured-image.html">
+  Featured-Image Guidelines</a>.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="localization-tips">
+    Localization Tips
+  </h1>
+
+  <hr>
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <p>
+      <strong>Tip:</strong> Translate any embedded text, use different imagery
+      or presentation, and match any marketing promotion to the needs of users
+      in other markets. For example: Some eastern markets respond to price
+      points that end in .00 or .05 more than .99.
+    </p>
+  </div>
+</div>
+
+<p>
+  Many developers start in their country of strength, then expand into new
+  markets. To help you market your apps more effectively to a global audience,
+  create <a href=
+  "http://android-developers.blogspot.com/2012/12/localize-your-promotional-graphics-on.html">
+  localized versions of your promotional graphics, screenshots, and videos</a>.
+  When a user visits your product display pages, Google Play will show the
+  localized assets that you’ve provided for that country. Find out more about
+  <a href="{@docRoot}distribute/users/expand-to-new-markets.html">capitalize on
+  the growing international audience</a>.
+</p>
+
+<div style="float:left;">
+  <img src="{@docRoot}images/gp-listing-3.jpg">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="keyword-tips">
+    Keyword Tips
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Think carefully about the keywords you use for your apps. Think about words
+  that represent the core feature of your apps. Also consider other words that
+  the user might use to search for your app. For example, if you have a Live
+  Wallpaper app, you may want to include the term ‘background’. This way, users
+  who don’t yet know the terminology can find your app.
+</p>
+
+<div class="headerLine">
+  <h1 id="app-indexing">
+    Sign Up for App Indexing
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  App Indexing provides deep links from Google searches to your apps. Get more
+  details and a link to the sign up page <a href=
+  "https://developers.google.com/app-indexing/">here</a>.
+</p>
+
+<div class="center-img">
+  <img src="{@docRoot}images/gp-listing-4.jpg">
+</div>
+
+<div class="headerLine">
+  <h1 id="education-app">
+    Education App Tips
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  If you’ve an educational app for the K-12 market, include it in Google Play
+  for Education. Google Play for Education can help your innovative educational
+  apps gain visibility with the right audiences, without having to knock on
+  school doors. Learn more about <a href=
+  "{@docRoot}distribute/googleplay/edu/about.html">Google Play for
+  Education</a>.
+</p>
+
+<div class="headerLine">
+<h1 id="related-resources">Related Resources</h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/users/createagreatlisting"
+  data-sortOrder="-timestamp"
+  data-cardSizes="6x3"
+  data-maxResults="6"></div>
\ No newline at end of file
diff --git a/docs/html/google/play/billing/billing_subscriptions.jd b/docs/html/google/play/billing/billing_subscriptions.jd
index aa25092..d0e6dc5 100644
--- a/docs/html/google/play/billing/billing_subscriptions.jd
+++ b/docs/html/google/play/billing/billing_subscriptions.jd
@@ -1,6 +1,10 @@
-page.title=Subscriptions
+page.title=Google Play In-App Subscriptions
 parent.title=In-app Billing
 parent.link=index.html
+page.metaDescription=Subscriptions let you sell content or features in your app with automated, recurring billing.
+page.image=/images/play_dev.jpg
+page.tags="inapp, iap, billing"
+meta.tags="monetization, inappbilling, subscriptions"
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/google/play/billing/billing_testing.jd b/docs/html/google/play/billing/billing_testing.jd
index 9d1964a..df6c657 100644
--- a/docs/html/google/play/billing/billing_testing.jd
+++ b/docs/html/google/play/billing/billing_testing.jd
@@ -367,6 +367,6 @@
 publish your application on Google Play. You can follow the normal steps for <a
 href="{@docRoot}tools/publishing/preparing.html">preparing</a>, <a
 href="{@docRoot}tools/publishing/app-signing.html">signing</a>, and <a
-href="{@docRoot}distribute/googleplay/publish/preparing.html">publishing on Google Play</a>.
+href="{@docRoot}distribute/tools/launch-checklist.html">publishing on Google Play</a>.
 </p>
 
diff --git a/docs/html/google/play/billing/index.jd b/docs/html/google/play/billing/index.jd
index 481a79c..dce20cb 100644
--- a/docs/html/google/play/billing/index.jd
+++ b/docs/html/google/play/billing/index.jd
@@ -1,4 +1,8 @@
 page.title=Google Play In-app Billing
+page.metaDescription=In-app Billing lets you sell digital content as one-time purchases or subscriptions.
+page.image=/images/play_dev.jpg
+meta.tags="monetizing, inappbilling, subscriptions"
+page.tags="inapp, iap, subscriptions"
 @jd:body
 
 <p>In-app Billing is a Google Play service that lets you sell digital content from inside
@@ -40,8 +44,6 @@
 
 <p>To get started, read the documents below or take the <a href="{@docRoot}training/in-app-billing/index.html">Selling 
     In-app Products</a> training class.</p>
-</div>
-</div>
 
 <dl>
   <dt><strong><a href="{@docRoot}google/play/billing/billing_overview.html">Overview</a></strong></dt>
diff --git a/docs/html/google/play/billing/v2/billing_subscriptions.jd b/docs/html/google/play/billing/v2/billing_subscriptions.jd
index 9c86e20..f8051a9 100644
--- a/docs/html/google/play/billing/v2/billing_subscriptions.jd
+++ b/docs/html/google/play/billing/v2/billing_subscriptions.jd
@@ -382,7 +382,7 @@
 startActivity(intent);</pre>
 
 <p>For more information, see 
-  <a href="{@docRoot}distribute/googleplay/promote/linking.html">Linking to Your Products</a>.</p>
+  <a href="{@docRoot}distribute/tools/promote/linking.html">Linking to Your Products</a>.</p>
 
 <h2 id="purchase-state-changes">Recurring Billing, Cancellation, and Changes In Purchase State</h2>
 
diff --git a/docs/html/google/play/expansion-files.jd b/docs/html/google/play/expansion-files.jd
index a21fbc5..e90f8fa 100644
--- a/docs/html/google/play/expansion-files.jd
+++ b/docs/html/google/play/expansion-files.jd
@@ -1,4 +1,6 @@
 page.title=APK Expansion Files
+page.metaDescription=If your app needs more than the 50MB APK max, use free APK expansion files from Google Play.
+page.tags="apk size, apk max, large assets"
 @jd:body
 
 
diff --git a/docs/html/google/play/licensing/adding-licensing.jd b/docs/html/google/play/licensing/adding-licensing.jd
index 93561f6..3bf4c1a 100644
--- a/docs/html/google/play/licensing/adding-licensing.jd
+++ b/docs/html/google/play/licensing/adding-licensing.jd
@@ -646,7 +646,7 @@
 deep-links the user to the application's details page on Google Play, from which the
 use can purchase the application. For more information on how to set up such
 links, see <a
-href="{@docRoot}distribute/googleplay/promote/linking.html">Linking to Your Products</a>. </li>
+href="{@docRoot}distribute/tools/promote/linking.html">Linking to Your Products</a>. </li>
 <li>Display a Toast notification that indicates that the features of the
 application are limited because it is not licensed. </li>
 </ul>
@@ -988,7 +988,7 @@
 publish the application on Google Play. Follow the normal steps to <a
 href="{@docRoot}tools/publishing/preparing.html">prepare</a>, <a
 href="{@docRoot}tools/publishing/app-signing.html">sign</a>, and then <a
-href="{@docRoot}distribute/googleplay/publish/preparing.html">publish the application</a>.
+href="{@docRoot}distribute/tools/launch-checklist.html">publish the application</a>.
 </p>
 
 
diff --git a/docs/html/google/play/licensing/index.jd b/docs/html/google/play/licensing/index.jd
index 6632fc0..a7ae57a 100644
--- a/docs/html/google/play/licensing/index.jd
+++ b/docs/html/google/play/licensing/index.jd
@@ -1,4 +1,7 @@
-page.title=Application Licensing
+page.title=App Licensing
+page.metaDescription=Information on using the licensing feature of Google Play to protect your apps.
+meta.tags="licensing, drm"
+page.image=/assets/images/resource-card-default-android.jpg
 @jd:body
 
 
diff --git a/docs/html/google/play/licensing/setting-up.jd b/docs/html/google/play/licensing/setting-up.jd
index d83f91b..f43e4aba 100644
--- a/docs/html/google/play/licensing/setting-up.jd
+++ b/docs/html/google/play/licensing/setting-up.jd
@@ -42,7 +42,7 @@
 using your Google account and agree to the Google Play terms of service.</p>
 
 <p>For more information, see <a
-href="{@docRoot}distribute/googleplay/publish/register.html">Get Started with Publishing</a>.</p>
+href="{@docRoot}distribute/googleplay/start.html">Get Started with Publishing</a>.</p>
 
 <p>If you already have a publisher account on Google Play, use your
 Developer Console to set up licensing.</p>
diff --git a/docs/html/guide/components/index.jd b/docs/html/guide/components/index.jd
index 37fb7e9..811d015 100644
--- a/docs/html/guide/components/index.jd
+++ b/docs/html/guide/components/index.jd
@@ -1,7 +1,9 @@
 page.title=App Components
 page.landing=true
 page.landing.intro=Android's application framework lets you create rich and innovative apps using a set of reusable components. This section explains how you can build the components that define the building blocks of your app and how to connect them together using intents. 
+page.metaDescription=Android's application framework lets you create rich and innovative apps using a set of reusable components. This section explains how you can build the components that define the building blocks of your app and how to connect them together using intents. 
 page.landing.image=images/develop/app_components.png
+page.image=images/develop/app_components.png
 
 @jd:body
 
diff --git a/docs/html/guide/components/intents-common.jd b/docs/html/guide/components/intents-common.jd
index a0f7ce1..b4813a5 100644
--- a/docs/html/guide/components/intents-common.jd
+++ b/docs/html/guide/components/intents-common.jd
@@ -737,7 +737,7 @@
 <pre>
 public void editContact(Uri contactUri, String email) {
     Intent intent = new Intent(Intent.ACTION_EDIT);
-    intent.setDataAndType(contactUri, Contacts.CONTENT_TYPE);
+    intent.setData(contactUri);
     intent.putExtra(Intents.Insert.EMAIL, email);
     if (intent.resolveActivity(getPackageManager()) != null) {
         startActivity(intent);
diff --git a/docs/html/guide/practices/screens_support.jd b/docs/html/guide/practices/screens_support.jd
index 8c76411..dbe6c1a 100644
--- a/docs/html/guide/practices/screens_support.jd
+++ b/docs/html/guide/practices/screens_support.jd
@@ -1,4 +1,7 @@
 page.title=Supporting Multiple Screens
+page.metaDescription=Nanaging UIs for the best display on multiple screen sizes.
+meta.tags="multiple screens"
+
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd
index 4057736..a716bf8 100644
--- a/docs/html/guide/topics/manifest/uses-feature-element.jd
+++ b/docs/html/guide/topics/manifest/uses-feature-element.jd
@@ -584,9 +584,14 @@
 </tr>
 <tr>
   <td><code>android.hardware.camera.any</code></td>
-  <td>The application uses at least one camera facing in any direction. Use this
-in preference to <code>android.hardware.camera</code> if a back-facing camera is
-not required.</td>
+  <td>The application uses at least one camera facing in any direction, or an
+external camera device if one is connected. Use this in preference to
+<code>android.hardware.camera</code> if a back-facing camera is not required.
+  </td>
+</tr>
+<tr>
+  <td><code>android.hardware.camera.external</code></td>
+  <td>The application uses an external camera device if one is connected.</td>
 </tr>
 
 <tr>
@@ -684,7 +689,7 @@
   <td>The application requires landscape orientation.</td>
   <td rowspan="2">
      <p>For example, if your app requires portrait orientation, you should declare
-<code>&lt;uses-feature android:name="android.hardware.screen.portrait"/></code> so that only devices
+<code>&lt;uses-feature android:name="android.hardware.screen.portrait"/&gt;</code> so that only devices
 that support portrait orientation (whether always or by user choice) can install your app. If your
 application <em>supports</em> both orientations, then you don't need to declare either.</p>
     <p>Both orientations are assumed <em>not required</em>, by default, so your app may be installed
diff --git a/docs/html/guide/topics/resources/index.jd b/docs/html/guide/topics/resources/index.jd
index 386abf5..b85170b 100644
--- a/docs/html/guide/topics/resources/index.jd
+++ b/docs/html/guide/topics/resources/index.jd
@@ -2,6 +2,8 @@
 page.landing=true
 page.landing.intro=It takes more than just code to build a great app. Resources are the additional files and static content that your code uses, such as bitmaps, layout definitions, user interface strings, animation instructions, and more.  
 page.landing.image=images/develop/resources.png
+page.image=/images/develop/resources.png
+page.metaDescription=Developer guide about how to use resources in your Android apps.
 
 @jd:body
 
diff --git a/docs/html/guide/topics/resources/localization.jd b/docs/html/guide/topics/resources/localization.jd
index 3bb9ab5..e86d4c9 100644
--- a/docs/html/guide/topics/resources/localization.jd
+++ b/docs/html/guide/topics/resources/localization.jd
@@ -1,485 +1,487 @@
-page.title=Localizing with Resources
-parent.title=Application Resources
-page.tags=localizing,localization,resources,formats,l10n
-parent.link=index.html
-@jd:body
-
-<div id="qv-wrapper">
-    <div id="qv">
-
-<h2>Quickview</h2>
-
-<ul>
-  <li>Use resource sets to create a localized app.</li>
-  <li>Android loads the correct resource set for the user's language and locale.</li>
-  <li>If localized resources are not available, Android loads your default resources.</li>
-</ul>
-
-<h2>In this document</h2>
-<ol>
-  <li><a href="#resource-switching">Overview: Resource-Switching in Android</a></li>
-<li><a href="#using-framework">Using Resources for Localization</a></li>
-<li><a href="#strategies">Localization Tips</a></li>
-<li><a href="#testing">Testing Localized Applications</a></li>
-</ol>
-
-<h2>See also</h2>
-  <ol>
-    <li><a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization Checklist</a></li>
-    <li><a href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a></li>
-    <li><a href="{@docRoot}guide/topics/ui/declaring-layout.html">Layouts</a></li>
-    <li><a href="{@docRoot}reference/android/app/Activity.html#ActivityLifecycle">Activity Lifecycle</a></li>
-</ol>
-</div>
-</div>
-
-<p>Android will run on many  devices in many  regions. To reach the most users,
-your application should handle text, audio files, numbers, currency, and
-graphics in ways appropriate to the locales where your application will be used.
-</p>
-
-<p>This document describes best practices for localizing Android
-applications. The principles apply whether you are developing your application
-using ADT with Eclipse, Ant-based tools, or any other IDE. </p>
-
-<p>You should already have a working knowledge of Java and be  familiar with
-Android resource loading, the declaration of user interface elements in XML,
-development considerations such as Activity lifecycle, and general principles of
-internationalization and localization. </p>
-
-<p>It is good practice to use the Android resource framework to separate the
-localized aspects of your application as much as possible from the core Java
-functionality:</p>
-
-<ul>
-  <li>You can put most or all of the <em>contents</em> of your application's
-user interface into resource files, as described in this document and in <a
-href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a>.</li>
-  <li>The <em>behavior</em> of the user interface, on the other hand, is driven
-by your Java code.
-    For example, if users input data that needs to be formatted or sorted
-differently depending on locale, then you would use Java to handle the data
-programmatically. This document does not cover how to  localize your Java code.
-</li>
-</ul>
-
-<p>For a short guide to localizing strings in your app, see the training lesson, <a
-href="{@docRoot}training/basics/supporting-devices/languages.html">Supporting Different Languages</a>. </p>
-
-
-<h2 id="resource-switching">Overview: Resource-Switching in Android</h2>
-
-<p>Resources are text strings, layouts, sounds, graphics, and any other static
-data that your  Android application  needs. An application can include multiple
-sets of resources, each customized for a different device configuration. When a
-user runs the application,  Android    automatically selects and loads the
-resources that best match the device.</p>
-
-<p>(This document focuses on localization and locale. For a complete description
-of resource-switching and all the types of configurations that you can
-specify &#8212; screen orientation, touchscreen type, and so on &#8212; see <a
-href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing
-Alternative Resources</a>.)</p>
-
-<table border="0" cellspacing="0" cellpadding="0">
-  <tr border="0">
-    <td width="180" style="border: 0pt none ;"><p class="special-note">
-    <strong>When you write your application:</strong>
-    <br><br>
-    You create a set of default resources, plus alternatives to be used in
-    different locales.</p></td>
-    <td style="border: 0pt none; padding:0">
-    <p style="border:0; padding:0"><img src="../../../images/resources/right-arrow.png" alt="right-arrow"
-    width="51" height="17"></p></td>
-    <td width="180" style="border: 0pt none ;"><p class="special-note">
-    <strong>When a user runs your application:</strong>
-    <br><br>The Android system selects which resources to load, based on the
-    device's locale.</p></td>
-  </tr>
-</table>
-
-<p>When you write your application, you create default and alternative resources
-for your application to use. To create  resources, you place files within
-specially named subdirectories of the project's <code>res/</code> directory.
-</p>
-
-
-
-<h3 id="defaults-r-important">Why Default Resources Are Important</h3>
-
-<p>Whenever the application runs in a locale for which you have not provided
-locale-specific text,  Android will load the default strings from
-<code>res/values/strings.xml</code>. If this default  file is absent, or if it
-is missing a string that your application needs, then your application will not run
-and will show an error.
-The example below illustrates what can happen when the default text file is incomplete. </p>
-
-<p><em>Example:</em>
-<p>An application's Java code refers to just two strings, <code>text_a</code> and
-  <code>text_b</code>. This application includes a localized resource file
-  (<code>res/values-en/strings.xml</code>) that defines <code>text_a</code> and
-  <code>text_b</code> in English. This application also includes a default
-  resource file (<code>res/values/strings.xml</code>) that includes a
-definition for <code>text_a</code>, but not for <code>text_b</code>:
-<ul>
-  <li>This application might compile without a problem. An IDE such as Eclipse
-    will not highlight any errors if a resource is missing.</li>
-  <li>When this application is launched on a device with locale set to English,
-    the application  might run without a problem, because
-    <code>res/values-en/strings.xml</code> contains both of the needed text
-    strings.</li>
-  <li>However, <strong>the user  will see an error message and a Force Close
-    button</strong> when this application is launched on a device set to a
-    language other than English. The application will not load.</li>
-</ul>
-
-
-<p>To prevent this situation, make sure that a <code>res/values/strings.xml</code>
-  file exists and that it defines every needed string. The situation applies to
-  all types of resources, not just strings: You
-  need to create a  set of default resource files containing all
-  the resources that your application calls upon &#8212; layouts, drawables,
-  animations, etc. For information about testing, see <a href="#test-for-default">
-  Testing for Default Resources</a>.</p>
-
-<h2 id="using-framework">Using Resources for Localization</h2>
-
-<h3 id="creating-defaults">How to Create Default Resources</h3>
-
-<p>Put the application's default text in
-a file with the following location and name:</p>
-<p><code>&nbsp;&nbsp;&nbsp;&nbsp;res/values/strings.xml</code> (required directory)</p>
-
-<p>The text strings in <code>res/values/strings.xml</code> should  use the
-default language, which is the language that you expect most of your application's users to
-speak.  </p>
-
-<p>The default resource set must also include any default drawables and layouts,
-  and can include other types of resources such as animations.
-<br>
-  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/drawable/</code>(required directory holding at least
-  one graphic file, for the application's icon on Google Play)<br>
-  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/layout/</code> (required directory holding an XML
-  file that defines the default layout)<br>
-  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/anim/</code> (required if you have any
-  <code>res/anim-<em>&lt;qualifiers&gt;</em></code> folders)<br>
-  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/xml/</code> (required if you have any
-  <code>res/xml-<em>&lt;qualifiers&gt;</em></code> folders)<br>
-  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/raw/</code> (required if you have any
-  <code>res/raw-<em>&lt;qualifiers&gt;</em></code> folders)
-</p>
-
-<p class="note"><strong>Tip:</strong> In your code, examine each reference to
-  an Android resource. Make sure that a default resource is defined for each
-  one. Also make sure that the default string file is complete: A <em>
-  localized</em> string file can contain a subset of the strings, but the
-  <em>default</em> string file must contain them all.
-</p>
-
-<h3 id="creating-alternatives">How to Create Alternative Resources</h3>
-
-<p>A large part of localizing an application is providing alternative text for
-different languages. In some cases you will also provide alternative graphics,
-sounds, layouts, and other locale-specific resources. </p>
-
-<p>An application can specify many <code>res/<em>&lt;qualifiers&gt;</em>/</code>
-directories, each with different qualifiers. To create an alternative resource for
-a different locale, you use a qualifier that specifies a language or a
-language-region combination. (The name of a resource directory must conform
-to the naming scheme described in
-<a href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing
-Alternative Resources</a>,
-or else it will not compile.)</p>
-
-<p><em>Example:</em></p>
-
-<p>Suppose that your application's default language is English. Suppose also
-that you want to localize all the text in your application to French, and most
-of the text in your application (everything except the application's title) to
-Japanese. In this case, you could create three alternative <code>strings.xml</code>
-files, each stored in a locale-specific resource directory:</p>
-
-<ol>
-  <li><code>res/values/strings.xml</code><br>
-    Contains  English text for all  the strings that the application uses,
-including text for a string named <code>title</code>.</li>
-  <li><code>res/values-fr/strings.xml</code><br>
-    Contain French text for all  the strings, including <code>title</code>.</li>
-  <li><code>res/values-ja/strings.xml</code><br>
-    Contain Japanese text for all  the strings <em>except</em>
-<code>title</code>.<br>
-  <code></code></li>
-</ol>
-
-<p>If your Java code refers to <code>R.string.title</code>,  here is what will
-happen at runtime:</p>
-
-<ul>
-  <li>If the device is set to any language other than French, Android will load
-<code>title</code> from the <code>res/values/strings.xml</code> file.</li>
-  <li>If the device is set to French, Android will load <code>title</code> from
-the <code>res/values-fr/strings.xml</code> file.</li>
-</ul>
-
-<p>Notice that if the device is set to Japanese, Android will look for
-<code>title</code> in the <code>res/values-ja/strings.xml</code> file. But
-because no such string is included in that file, Android will fall back to the
-default, and will load  <code>title</code> in English from the
-<code>res/values/strings.xml</code> file.  </p>
-
-<h3 id="resource-precedence">Which Resources Take Precedence?</h3>
-
-<p> If multiple resource files match a device's configuration, Android follows a
-set of rules in deciding which file to use. Among the qualifiers that can be
-specified in a resource directory name, <strong>locale almost always takes
-precedence</strong>. </p>
-<p><em>Example:</em></p>
-
-<p>Assume that an application  includes a default set of graphics and two other
-sets of graphics, each optimized for a different device setup:</p>
-
-<ul>
-  <li><code>res/drawable/</code><br>
-    Contains
-  default graphics.</li>
-  <li><code>res/drawable-small-land-stylus/</code><br>
-  Contains  graphics optimized for use with a device that expects input from a
-  stylus and has a QVGA low-density screen in landscape orientation.</li>
-  <li><code>res/drawable-ja/</code> <br>
-  Contains  graphics optimized for use with Japanese.</li>
-</ul>
-
-<p>If the application runs on a device that is configured to use Japanese,
-Android will load graphics from  <code>res/drawable-ja/</code>, even if the
-device happens to be one that expects input from a stylus and has a QVGA
-low-density screen in landscape orientation.</p>
-
-<p class="note"><strong>Exception:</strong> The only qualifiers that take
-precedence over locale in the selection process are MCC and MNC (mobile country
-code and mobile network code). </p>
-
-<p><em>Example:</em></p>
-
-<p>Assume that you have the following situation:</p>
-
-<ul>
-  <li>The application code calls for <code>R.string.text_a</code></li>
-  <li>Two relevant resource files are available:
-    <ul>
-      <li><code>res/values-mcc404/strings.xml</code>, which includes
-<code>text_a</code> in the application's default language, in this case
-English.</li>
-      <li><code>res/values-hi/strings.xml</code>, which includes
-<code>text_a</code> in Hindi.</li>
-    </ul>
-  </li>
-  <li>The application is running on a device that has the following
-configuration:
-    <ul>
-      <li>The SIM card is connected to a mobile network in India (MCC 404).</li>
-      <li>The language is set to Hindi (<code>hi</code>).</li>
-    </ul>
-  </li>
-</ul>
-
-<p>Android will load <code>text_a</code> from
-<code>res/values-mcc404/strings.xml</code> (in English), even if the device is
-configured for Hindi. That is because in the resource-selection process, Android
-will prefer an MCC match over a language match. </p>
-
-<p>The selection process is not always as straightforward as these examples
-suggest. Please read  <a
-href="{@docRoot}guide/topics/resources/providing-resources.html#BestMatch">How Android Finds
-the Best-matching Resource</a> for a more nuanced description of the
-process. All the qualifiers are described and listed in order of
-precedence in <a
-href="{@docRoot}guide/topics/resources/providing-resources.html#table2">Table 2 of Providing
-Alternative Resources</a>.</p>
-
-<h3 id="referring-to-resources">Referring to Resources in Java</h3>
-
-<p>In your application's Java code, you refer to  resources using the syntax
-<code>R.<em>resource_type</em>.<em>resource_name</em></code> or
-<code>android.R.<em>resource_type</em>.<em>resource_name</em></code><em>.</em>
-For more about this, see <a
-href="{@docRoot}guide/topics/resources/accessing-resources.html">Accessing Resources</a>.</p>
-
-<h2 id="checklist">Localization Checklist</h2>
-
-<p>For a complete overview of the process of localizing and distributing an Android application,
-see the <a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization
-Checklist</a> document.</p>
-
-<h2 id="strategies">Localization Tips</h2>
-
-<h4 id="failing2">Design your application  to work in any locale</h4>
-
-<p>You cannot assume anything about the device on which a user will
-run your application. The device might have hardware that you were not
-anticipating, or it might be set to a locale that you did not plan for or that
-you cannot test. Design your application so that it will function normally or fail gracefully no
-matter what device it runs on.</p>
-
-<p class="note"><strong>Important:</strong> Make sure that your application
-includes a full set of default resources.</p> <p>Make sure to include
-<code>res/drawable/</code> and a <code>res/values/</code> folders (without any
-additional modifiers in the folder names) that contain all the images and text
-that your application will need. </p>
-
-<p>If an application is missing even one default resource, it will not run on a
-  device that is set to an unsupported locale. For example, the
-  <code>res/values/strings.xml</code> default file might lack one string that
-  the application needs: When the application runs in an unsupported locale and
-  attempts to load <code>res/values/strings.xml</code>, the user will see an
-  error message and a Force Close button. An IDE such as Eclipse will not
-  highlight this kind of error, and you will not see the problem when you
-  test the application on a device or emulator that is set to a supported locale.</p>
-
-<p>For more information, see <a href="#test-for-default">Testing for Default Resources</a>.</p>
-
-<h4>Design a flexible layout</h4>
-
-<p> If you need to rearrange your layout to fit a certain language (for example
-German with its long words), you can create an alternative layout for that
-language (for example <code>res/layout-de/main.xml</code>). However, doing this
-can make your application harder to maintain.  It is better to create a single
-layout that is more flexible.</p>
-
-<p>Another typical situation is a language that requires something different in
-its layout. For example, you might have a contact form that should include  two
-name fields when the application runs in Japanese, but three name fields when
-the application  runs in some other language. You could handle this in either of
-two ways:</p>
-
-<ul>
-  <li>Create  one  layout with a field that you can programmatically enable or
-disable, based on the language, or</li>
-  <li>Have the main layout include another layout that  includes the changeable
-field. The second layout can have different configurations for different
-languages.</li>
-</ul>
-
-<h4>Avoid creating more resource files and text strings than you need</h4>
-
-<p>You probably do not need to create a locale-specific
-alternative for every resource in your application. For example, the layout
-defined in the <code>res/layout/main.xml</code> file might work in any locale,
-in which case there would be no need to create any alternative layout files.
-</p>
-
-<p>Also, you might not need to create alternative text for every
-string. For example, assume the following:</p>
-
-<ul>
-  <li>Your application's default language is American
-English. Every string that the application uses is defined, using American
-English spellings, in <code>res/values/strings.xml</code>. </li>
-
-  <li>For  a few important phrases, you want to provide
-British English spelling. You want these alternative strings to be used when your
-application runs on a device in the United Kingdom. </li>
-</ul>
-
-<p>To do this, you could create a small file called
-<code>res/values-en-rGB/strings.xml</code> that includes only the strings that
-should be different when the application  runs in the U.K. For all the rest of
-the strings, the application will fall back to the defaults and use what is
-defined in <code>res/values/strings.xml</code>.</p>
-
-<h4>Use the Android Context object for manual locale lookup</h4>
-
-<p>You can look up the locale using the {@link android.content.Context} object
-that Android makes available:</p>
-
-<pre>String locale = context.getResources().getConfiguration().locale.getDisplayName();</pre>
-
-<h2 id="testing">Testing Localized Applications</h2>
-
-<h3 id="device">Testing on a Device</h3>
-<p>Keep in mind that the device you are testing may be significantly different from
-  the devices available to consumers in other geographies. The locales available
-  on your device may differ from those available on other devices. Also, the
-  resolution and density of the device screen may differ, which could affect
-  the display of strings and drawables in your UI.</p>
-
-<p>To change the locale on a device, use  the Settings application  (Home &gt;
-Menu &gt; Settings &gt; Locale &amp; text &gt; Select locale). </p>
-
-<h3 id="emulator">Testing on an Emulator</h3>
-
-<p>For details about using the emulator, see See <a
-href="{@docRoot}tools/help/emulator.html">Android Emulator</a>.</p>
-<h4>Creating and using a custom locale</h4>
-
-<p>A &quot;custom&quot; locale is a language/region combination that the Android
-system image does not explicitly support. (For a list of supported locales in
-Android platforms see the Version Notes in the <a
-href="{@docRoot}sdk/index.html">SDK</a> tab). You can test
-how your application will run in a custom locale by creating a custom locale in
-the emulator. There are two ways to do this:</p>
-
-<ul>
-  <li>Use the Custom Locale application, which is accessible from the
-Application tab. (After you create a custom locale, switch to it by
-pressing and holding the locale name.)</li>
-  <li>Change to a custom locale from the adb shell, as described below.</li>
-</ul>
-
-<p>When you set the emulator to a locale that is not available in the Android
-system image, the system itself will display in its default language. Your
-application, however, should localize properly.</p>
-
-<h4>Changing the emulator locale from the adb shell</h4>
-
-<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>
-  <li>Launch an emulator.</li>
-  <li>From a command-line shell on the host computer, run the following
-command:<br>
-    <code>adb shell</code><br>
-  or if you have a device attached, specify that you want the emulator by adding
-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>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>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
-example, click the Run icon in Eclipse), and the application will launch with
-the new locale. </p>
-
-<h3 id="test-for-default">Testing for Default Resources</h3>
-<p>Here's how to test whether an application includes every string resource that it needs:  </p>
-<ol><li>Set the emulator or device to a language that your application does not
-  support. For example, if the application has French strings in
-  <code>res/values-fr/</code> but does not have any Spanish strings in
-  <code>res/values-es/</code>, then set the emulator's locale to Spanish.
-  (You can use the Custom Locale application to set the emulator to an
-  unsupported locale.)</li>
-  <li>Run the application.</li>
-<li>If the application shows an error message and a Force Close button, it might
-  be looking for a string that is not available. Make sure that your
-  <code>res/values/strings.xml</code> file includes a definition for
-  every string that the application uses.</li>
-</ol>
-</p>
-
-<p>If the test is successful, repeat it for other types of
-  configurations. For example, if the application has a layout file called
-  <code>res/layout-land/main.xml</code> but does not contain a file called
-  <code>res/layout-port/main.xml</code>, then set the emulator or device to
-  portrait orientation and see if the application will run.
-
+page.title=Localizing with Resources

+parent.title=Application Resources

+page.tags="localizing","localization","resources", "formats", "l10n"

+parent.link=index.html

+@jd:body

+

+<div id="qv-wrapper">

+    <div id="qv">

+

+<h2>Quickview</h2>

+

+<ul>

+  <li>Use resource sets to create a localized app.</li>

+  <li>Android loads the correct resource set for the user's language and locale.</li>

+  <li>If localized resources are not available, Android loads your default resources.</li>

+</ul>

+

+<h2>In this document</h2>

+<ol>

+  <li><a href="#resource-switching">Overview: Resource-Switching in Android</a></li>

+<li><a href="#using-framework">Using Resources for Localization</a></li>

+<li><a href="#strategies">Localization Tips</a></li>

+<li><a href="#testing">Testing Localized Applications</a></li>

+</ol>

+

+<h2>See also</h2>

+  <ol>

+    <li><a href="{@docRoot}distribute/tools/localization-checklist.html">Localization Checklist</a></li>

+    <li><a href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a></li>

+    <li><a href="{@docRoot}guide/topics/ui/declaring-layout.html">Layouts</a></li>

+    <li><a href="{@docRoot}reference/android/app/Activity.html#ActivityLifecycle">Activity Lifecycle</a></li>

+</ol>

+</div>

+</div>

+

+<p>Android will run on many  devices in many  regions. To reach the most users,

+your application should handle text, audio files, numbers, currency, and

+graphics in ways appropriate to the locales where your application will be used.

+</p>

+

+<p>This document describes best practices for localizing Android

+applications. The principles apply whether you are developing your application  

+using ADT with Eclipse, Ant-based tools, or any other IDE. </p>

+

+<p>You should already have a working knowledge of Java and be  familiar with

+Android resource loading, the declaration of user interface elements in XML,

+development considerations such as Activity lifecycle, and general principles of

+internationalization and localization. </p>

+

+<p>It is good practice to use the Android resource framework to separate the

+localized aspects of your application as much as possible from the core Java

+functionality:</p>

+

+<ul>

+  <li>You can put most or all of the <em>contents</em> of your application's

+user interface into resource files, as described in this document and in <a

+href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a>.</li>

+  <li>The <em>behavior</em> of the user interface, on the other hand, is driven

+by your Java code. 

+    For example, if users input data that needs to be formatted or sorted

+differently depending on locale, then you would use Java to handle the data

+programmatically. This document does not cover how to  localize your Java code.

+</li>

+</ul>

+

+<p>For a short guide to localizing strings in your app, see the training lesson, <a

+href="{@docRoot}training/basics/supporting-devices/languages.html">Supporting Different Languages</a>. </p>

+

+

+<h2 id="resource-switching">Overview: Resource-Switching in Android</h2>

+

+<p>Resources are text strings, layouts, sounds, graphics, and any other static

+data that your  Android application  needs. An application can include multiple

+sets of resources, each customized for a different device configuration. When a

+user runs the application,  Android    automatically selects and loads the 

+resources that best match the device.</p>

+

+<p>(This document focuses on localization and locale. For a complete description

+of resource-switching and all the types of configurations that you can

+specify &#8212; screen orientation, touchscreen type, and so on &#8212; see <a

+href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing

+Alternative Resources</a>.)</p>

+

+<table border="0" cellspacing="0" cellpadding="0">

+  <tr border="0">

+    <td width="180" style="border: 0pt none ;"><p class="special-note">

+    <strong>When you write your application:</strong>

+    <br><br>

+    You create a set of default resources, plus alternatives to be used in

+    different locales.</p></td>

+    <td style="border: 0pt none; padding:0">

+    <p style="border:0; padding:0"><img src="../../../images/resources/right-arrow.png" alt="right-arrow" 

+    width="51" height="17"></p></td>

+    <td width="180" style="border: 0pt none ;"><p class="special-note">

+    <strong>When a user runs your application:</strong>

+    <br><br>The Android system selects which resources to load, based on the

+    device's locale.</p></td>

+  </tr>

+</table>

+

+<p>When you write your application, you create default and alternative resources

+for your application to use. To create  resources, you place files within

+specially named subdirectories of the project's <code>res/</code> directory.

+</p>

+

+

+

+<h3 id="defaults-r-important">Why Default Resources Are Important</h3>

+

+<p>Whenever the application runs in a locale for which you have not provided

+locale-specific text,  Android will load the default strings from

+<code>res/values/strings.xml</code>. If this default  file is absent, or if it 

+is missing a string that your application needs, then your application will not run 

+and will show an error. 

+The example below illustrates what can happen when the default text file is incomplete. </p>

+

+<p><em>Example:</em>

+<p>An application's Java code refers to just two strings, <code>text_a</code> and 

+	<code>text_b</code>. This application includes a localized resource file 

+	(<code>res/values-en/strings.xml</code>) that defines <code>text_a</code> and 

+	<code>text_b</code> in English. This application also includes a default 

+	resource file (<code>res/values/strings.xml</code>) that includes a

+definition for <code>text_a</code>, but not for <code>text_b</code>:

+<ul>

+  <li>This application might compile without a problem. An IDE such as Eclipse 

+  	will not highlight any errors if a resource is missing.</li>

+  <li>When this application is launched on a device with locale set to English, 

+  	the application  might run without a problem, because 

+  	<code>res/values-en/strings.xml</code> contains both of the needed text 

+  	strings.</li>

+  <li>However, <strong>the user  will see an error message and a Force Close 

+  	button</strong> when this application is launched on a device set to a 

+  	language other than English. The application will not load.</li>

+</ul>

+

+

+<p>To prevent this situation, make sure that a <code>res/values/strings.xml</code> 

+	file exists and that it defines every needed string. The situation applies to 

+	all types of resources, not just strings: You 

+	need to create a  set of default resource files containing all 

+	the resources that your application calls upon &#8212; layouts, drawables, 

+	animations, etc. For information about testing, see <a href="#test-for-default">

+	Testing for Default Resources</a>.</p>

+

+<h2 id="using-framework">Using Resources for Localization</h2>

+

+<h3 id="creating-defaults">How to Create Default Resources</h3>

+

+<p>Put the application's default text in

+a file with the following location and name:</p>

+<p><code>&nbsp;&nbsp;&nbsp;&nbsp;res/values/strings.xml</code> (required directory)</p>

+

+<p>The text strings in <code>res/values/strings.xml</code> should  use the

+default language, which is the language that you expect most of your application's users to

+speak.  </p>

+

+<p>The default resource set must also include any default drawables and layouts, 

+	and can include other types of resources such as animations. 

+<br>

+  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/drawable/</code>(required directory holding at least

+  one graphic file, for the application's icon on Google Play)<br>

+  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/layout/</code> (required directory holding an XML

+  file that defines the default layout)<br>

+  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/anim/</code> (required if you have any 

+  <code>res/anim-<em>&lt;qualifiers&gt;</em></code> folders)<br>

+  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/xml/</code> (required if you have any 

+  <code>res/xml-<em>&lt;qualifiers&gt;</em></code> folders)<br>

+  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/raw/</code> (required if you have any 

+  <code>res/raw-<em>&lt;qualifiers&gt;</em></code> folders)

+</p>

+

+<p class="note"><strong>Tip:</strong> In your code, examine each reference to 

+	an Android resource. Make sure that a default resource is defined for each

+	one. Also make sure that the default string file is complete: A <em>

+	localized</em> string file can contain a subset of the strings, but the 

+	<em>default</em> string file must contain them all. 

+</p>

+

+<h3 id="creating-alternatives">How to Create Alternative Resources</h3>

+

+<p>A large part of localizing an application is providing alternative text for

+different languages. In some cases you will also provide alternative graphics,

+sounds, layouts, and other locale-specific resources. </p>

+

+<p>An application can specify many <code>res/<em>&lt;qualifiers&gt;</em>/</code>

+directories, each with different qualifiers. To create an alternative resource for

+a different locale, you use a qualifier that specifies a language or a 

+language-region combination. (The name of a resource directory must conform 

+to the naming scheme described in 

+<a href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing

+Alternative Resources</a>,

+or else it will not compile.)</p>

+

+<p><em>Example:</em></p>

+

+<p>Suppose that your application's default language is English. Suppose also

+that you want to localize all the text in your application to French, and most

+of the text in your application (everything except the application's title) to

+Japanese. In this case, you could create three alternative <code>strings.xml</code>

+files, each stored in a locale-specific resource directory:</p>

+

+<ol>

+  <li><code>res/values/strings.xml</code><br>

+    Contains  English text for all  the strings that the application uses,

+including text for a string named <code>title</code>.</li>

+  <li><code>res/values-fr/strings.xml</code><br>

+    Contain French text for all  the strings, including <code>title</code>.</li>

+  <li><code>res/values-ja/strings.xml</code><br>

+    Contain Japanese text for all  the strings <em>except</em>

+<code>title</code>.<br>

+  <code></code></li>

+</ol>

+

+<p>If your Java code refers to <code>R.string.title</code>,  here is what will

+happen at runtime:</p>

+

+<ul>

+  <li>If the device is set to any language other than French, Android will load

+<code>title</code> from the <code>res/values/strings.xml</code> file.</li>

+  <li>If the device is set to French, Android will load <code>title</code> from

+the <code>res/values-fr/strings.xml</code> file.</li>

+</ul>

+

+<p>Notice that if the device is set to Japanese, Android will look for

+<code>title</code> in the <code>res/values-ja/strings.xml</code> file. But

+because no such string is included in that file, Android will fall back to the

+default, and will load  <code>title</code> in English from the

+<code>res/values/strings.xml</code> file.  </p>

+

+<h3 id="resource-precedence">Which Resources Take Precedence?</h3>

+

+<p> If multiple resource files match a device's configuration, Android follows a

+set of rules in deciding which file to use. Among the qualifiers that can be

+specified in a resource directory name, <strong>locale almost always takes

+precedence</strong>. </p>

+<p><em>Example:</em></p>

+

+<p>Assume that an application  includes a default set of graphics and two other

+sets of graphics, each optimized for a different device setup:</p>

+

+<ul>

+  <li><code>res/drawable/</code><br>

+    Contains

+  default graphics.</li>

+  <li><code>res/drawable-small-land-stylus/</code><br>

+  Contains  graphics optimized for use with a device that expects input from a 

+  stylus and has a QVGA low-density screen in landscape orientation.</li>

+  <li><code>res/drawable-ja/</code> <br>

+  Contains  graphics optimized for use with Japanese.</li>

+</ul>

+

+<p>If the application runs on a device that is configured to use Japanese,

+Android will load graphics from  <code>res/drawable-ja/</code>, even if the

+device happens to be one that expects input from a stylus and has a QVGA 

+low-density screen in landscape orientation.</p>

+

+<p class="note"><strong>Exception:</strong> The only qualifiers that take

+precedence over locale in the selection process are MCC and MNC (mobile country

+code and mobile network code). </p>

+

+<p><em>Example:</em></p>

+

+<p>Assume that you have the following situation:</p>

+

+<ul>

+  <li>The application code calls for <code>R.string.text_a</code></li>

+  <li>Two relevant resource files are available:

+    <ul>

+      <li><code>res/values-mcc404/strings.xml</code>, which includes

+<code>text_a</code> in the application's default language, in this case

+English.</li>

+      <li><code>res/values-hi/strings.xml</code>, which includes

+<code>text_a</code> in Hindi.</li>

+    </ul>

+  </li>

+  <li>The application is running on a device that has the following

+configuration:

+    <ul>

+      <li>The SIM card is connected to a mobile network in India (MCC 404).</li>

+      <li>The language is set to Hindi (<code>hi</code>).</li>

+    </ul>

+  </li>

+</ul>

+

+<p>Android will load <code>text_a</code> from

+<code>res/values-mcc404/strings.xml</code> (in English), even if the device is

+configured for Hindi. That is because in the resource-selection process, Android

+will prefer an MCC match over a language match. </p>

+

+<p>The selection process is not always as straightforward as these examples

+suggest. Please read  <a

+href="{@docRoot}guide/topics/resources/providing-resources.html#BestMatch">How Android Finds

+the Best-matching Resource</a> for a more nuanced description of the

+process. All the qualifiers are described and listed in order of

+precedence in <a

+href="{@docRoot}guide/topics/resources/providing-resources.html#table2">Table 2 of Providing

+Alternative Resources</a>.</p>

+

+<h3 id="referring-to-resources">Referring to Resources in Java</h3>

+

+<p>In your application's Java code, you refer to  resources using the syntax

+<code>R.<em>resource_type</em>.<em>resource_name</em></code> or

+<code>android.R.<em>resource_type</em>.<em>resource_name</em></code><em>.</em>

+For more about this, see <a

+href="{@docRoot}guide/topics/resources/accessing-resources.html">Accessing Resources</a>.</p>

+

+<h2 id="checklist">Localization Checklist</h2>

+

+<p>For a complete overview of the process of localizing and distributing an Android application,

+see the <a href="{@docRoot}distribute/tools/localization-checklist.html">Localization

+Checklist</a> document.</p>

+

+<h2 id="strategies">Localization Tips</h2>

+

+<h4 id="failing2">Design your application  to work in any locale</h4>

+

+<p>You cannot assume anything about the device on which a user will

+run your application. The device might have hardware that you were not

+anticipating, or it might be set to a locale that you did not plan for or that 

+you cannot test. Design your application so that it will function normally or fail gracefully no 

+matter what device it runs on.</p>

+

+<p class="note"><strong>Important:</strong> Make sure that your application

+includes a full set of default resources.</p> <p>Make sure to include

+<code>res/drawable/</code> and a <code>res/values/</code> folders (without any

+additional modifiers in the folder names) that contain all the images and text

+that your application will need. </p>

+

+<p>If an application is missing even one default resource, it will not run on a 

+	device that is set to an unsupported locale. For example, the 

+	<code>res/values/strings.xml</code> default file might lack one string that 

+	the application needs: When the application runs in an unsupported locale and 

+	attempts to load <code>res/values/strings.xml</code>, the user will see an 

+	error message and a Force Close button. An IDE such as Eclipse will not 

+	highlight this kind of error, and you will not see the problem when you 

+	test the application on a device or emulator that is set to a supported locale.</p>

+

+<p>For more information, see <a href="#test-for-default">Testing for Default Resources</a>.</p>

+

+<h4>Design a flexible layout</h4>

+

+<p> If you need to rearrange your layout to fit a certain language (for example

+German with its long words), you can create an alternative layout for that

+language (for example <code>res/layout-de/main.xml</code>). However, doing this

+can make your application harder to maintain.  It is better to create a single

+layout that is more flexible.</p>

+

+<p>Another typical situation is a language that requires something different in

+its layout. For example, you might have a contact form that should include  two

+name fields when the application runs in Japanese, but three name fields when

+the application  runs in some other language. You could handle this in either of

+two ways:</p>

+

+<ul>

+  <li>Create  one  layout with a field that you can programmatically enable or

+disable, based on the language, or</li>

+  <li>Have the main layout include another layout that  includes the changeable

+field. The second layout can have different configurations for different

+languages.</li>

+</ul>

+

+<h4>Avoid creating more resource files and text strings than you need</h4>

+

+<p>You probably do not need to create a locale-specific

+alternative for every resource in your application. For example, the layout

+defined in the <code>res/layout/main.xml</code> file might work in any locale,

+in which case there would be no need to create any alternative layout files.

+</p>

+

+<p>Also, you might not need to create alternative text for every

+string. For example, assume the following:</p>

+

+<ul>

+  <li>Your application's default language is American

+English. Every string that the application uses is defined, using American

+English spellings, in <code>res/values/strings.xml</code>. </li>

+

+  <li>For  a few important phrases, you want to provide

+British English spelling. You want these alternative strings to be used when your

+application runs on a device in the United Kingdom. </li>

+</ul>

+

+<p>To do this, you could create a small file called

+<code>res/values-en-rGB/strings.xml</code> that includes only the strings that

+should be different when the application  runs in the U.K. For all the rest of

+the strings, the application will fall back to the defaults and use what is

+defined in <code>res/values/strings.xml</code>.</p>

+

+<h4>Use the Android Context object for manual locale lookup</h4>

+

+<p>You can look up the locale using the {@link android.content.Context} object

+that Android makes available:</p>

+

+<pre>String locale = context.getResources().getConfiguration().locale.getDisplayName();</pre>

+

+<h2 id="testing">Testing Localized Applications</h2>

+

+<h3 id="device">Testing on a Device</h3>

+<p>Keep in mind that the device you are testing may be significantly different from 

+	the devices available to consumers in other geographies. The locales available 

+	on your device may differ from those available on other devices. Also, the 

+	resolution and density of the device screen may differ, which could affect 

+	the display of strings and drawables in your UI.</p>

+

+<p>To change the locale on a device, use  the Settings application  (Home &gt;

+Menu &gt; Settings &gt; Locale &amp; text &gt; Select locale). </p>

+

+<h3 id="emulator">Testing on an Emulator</h3>

+

+<p>For details about using the emulator, see See <a

+href="{@docRoot}tools/help/emulator.html">Android Emulator</a>.</p>

+<h4>Creating and using a custom locale</h4>

+

+<p>A &quot;custom&quot; locale is a language/region combination that the Android

+system image does not explicitly support. (For a list of supported locales in

+Android platforms see the Version Notes in the <a

+href="{@docRoot}sdk/index.html">SDK</a> tab). You can test

+how your application will run in a custom locale by creating a custom locale in

+the emulator. There are two ways to do this:</p>

+

+<ul>

+  <li>Use the Custom Locale application, which is accessible from the

+Application tab. (After you create a custom locale, switch to it by 

+pressing and holding the locale name.)</li>

+  <li>Change to a custom locale from the adb shell, as described below.</li>

+</ul>

+

+<p>When you set the emulator to a locale that is not available in the Android

+system image, the system itself will display in its default language. Your

+application, however, should localize properly.</p>

+

+<h4>Changing the emulator locale from the adb shell</h4>

+

+<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>

+  <li>Launch an emulator.</li>

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

+command:<br>

+    <code>adb shell</code><br>

+  or if you have a device attached, specify that you want the emulator by adding

+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>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>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

+example, click the Run icon in Eclipse), and the application will launch with

+the new locale. </p>

+

+<h3 id="test-for-default">Testing for Default Resources</h3>

+<p>Here's how to test whether an application includes every string resource that it needs:  </p>

+<ol><li>Set the emulator or device to a language that your application does not 

+	support. For example, if the application has French strings in 

+	<code>res/values-fr/</code> but does not have any Spanish strings in 

+	<code>res/values-es/</code>, then set the emulator's locale to Spanish. 

+	(You can use the Custom Locale application to set the emulator to an 

+	unsupported locale.)</li>

+	<li>Run the application.</li>  

+<li>If the application shows an error message and a Force Close button, it might 

+	be looking for a string that is not available. Make sure that your 

+	<code>res/values/strings.xml</code> file includes a definition for 

+	every string that the application uses.</li>

+</ol> 

+</p> 

+

+<p>If the test is successful, repeat it for other types of 

+	configurations. For example, if the application has a layout file called 

+	<code>res/layout-land/main.xml</code> but does not contain a file called 

+	<code>res/layout-port/main.xml</code>, then set the emulator or device to 

+	portrait orientation and see if the application will run. 

+

+

+

diff --git a/docs/html/guide/topics/resources/string-resource.jd b/docs/html/guide/topics/resources/string-resource.jd
index 5a96ba1..e2326ec 100644
--- a/docs/html/guide/topics/resources/string-resource.jd
+++ b/docs/html/guide/topics/resources/string-resource.jd
@@ -20,9 +20,6 @@
 information about styling and formatting strings, see the section about <a
 href="#FormattingAndStyling">Formatting and Styling</a>.</p>
 
-
-
-
 <h2 id="String">String</h2>
 
 <p>A single string that can be referenced from the application or from other resource files (such
@@ -433,7 +430,7 @@
 
 
 
-<h3>Styling with HTML markup</h3>
+<h3 id="StylingWithHTML">Styling with HTML markup</h3>
 
 <p>You can add styling to your strings with HTML markup. For example:</p>
 <pre>
@@ -497,5 +494,107 @@
 CharSequence styledText = Html.fromHtml(text);
 </pre>
 
+<h2 id="StylingWithSpannables">Styling with Spannables</h2>
+<p>
+A {@link android.text.Spannable} is a text object that you can style with
+typeface properties such as color and font weight. You use
+{@link android.text.SpannableStringBuilder} to build
+your text and then apply styles defined in the {@link android.text.style}
+package to the text.
+</p>
 
+<p>You can use the following helper methods to set up much of the work
+of creating spannable text:</p>
 
+<pre style="pretty-print">
+/**
+ * Returns a CharSequence that concatenates the specified array of CharSequence
+ * objects and then applies a list of zero or more tags to the entire range.
+ *
+ * @param content an array of character sequences to apply a style to
+ * @param tags the styled span objects to apply to the content
+ *        such as android.text.style.StyleSpan
+ *
+ */
+private static CharSequence apply(CharSequence[] content, Object... tags) {
+    SpannableStringBuilder text = new SpannableStringBuilder();
+    openTags(text, tags);
+    for (CharSequence item : content) {
+        text.append(item);
+    }
+    closeTags(text, tags);
+    return text;
+}
+
+/**
+ * Iterates over an array of tags and applies them to the beginning of the specified
+ * Spannable object so that future text appended to the text will have the styling
+ * applied to it. Do not call this method directly.
+ */
+private static void openTags(Spannable text, Object[] tags) {
+    for (Object tag : tags) {
+        text.setSpan(tag, 0, 0, Spannable.SPAN_MARK_MARK);
+    }
+}
+
+/**
+ * "Closes" the specified tags on a Spannable by updating the spans to be
+ * endpoint-exclusive so that future text appended to the end will not take
+ * on the same styling. Do not call this method directly.
+ */
+private static void closeTags(Spannable text, Object[] tags) {
+    int len = text.length();
+    for (Object tag : tags) {
+        if (len > 0) {
+            text.setSpan(tag, 0, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        } else {
+            text.removeSpan(tag);
+        }
+    }
+}
+</pre>
+
+<p>
+The following <code>bold</code>, <code>italic</code>, and <code>color</code>
+methods show you how to call the helper methods to apply
+styles defined in the {@link android.text.style} package. You
+can create similar methods to do other types of text styling.
+</p>
+
+<pre style="pretty-print">
+/**
+ * Returns a CharSequence that applies boldface to the concatenation
+ * of the specified CharSequence objects.
+ */
+public static CharSequence bold(CharSequence... content) {
+    return apply(content, new StyleSpan(Typeface.BOLD));
+}
+
+/**
+ * Returns a CharSequence that applies italics to the concatenation
+ * of the specified CharSequence objects.
+ */
+public static CharSequence italic(CharSequence... content) {
+    return apply(content, new StyleSpan(Typeface.ITALIC));
+}
+
+/**
+ * Returns a CharSequence that applies a foreground color to the
+ * concatenation of the specified CharSequence objects.
+ */
+public static CharSequence color(int color, CharSequence... content) {
+    return apply(content, new ForegroundColorSpan(color));
+}
+</pre>
+
+<p>
+Here's an example of how to chain these methods to create a character sequence
+with different types of styling applied to individual words:
+</p>
+
+<pre style="pretty-print">
+// Create an italic "hello, " a red "world",
+// and bold the entire sequence.
+CharSequence text = bold(italic(res.getString(R.string.hello)),
+    color(Color.RED, res.getString(R.string.world)));
+</pre>
\ No newline at end of file
diff --git a/docs/html/guide/topics/ui/accessibility/index.jd b/docs/html/guide/topics/ui/accessibility/index.jd
index 56efc4c..dcc22d7 100644
--- a/docs/html/guide/topics/ui/accessibility/index.jd
+++ b/docs/html/guide/topics/ui/accessibility/index.jd
@@ -1,5 +1,9 @@
 page.title=Accessibility
 parent.title=User Interface
+page.metaDescription=How to make your apps accessible to users with visual, physical, or other limitations. Robust support will increase your app's user base.
+
+page.tags="accessibility"
+page.image=/design/media/accessibility_contentdesc.png
 parent.link=../index.html
 @jd:body
 
diff --git a/docs/html/guide/topics/ui/notifiers/notifications.jd b/docs/html/guide/topics/ui/notifiers/notifications.jd
index 3b1292e..59c2269 100644
--- a/docs/html/guide/topics/ui/notifiers/notifications.jd
+++ b/docs/html/guide/topics/ui/notifiers/notifications.jd
@@ -16,6 +16,7 @@
       <li><a href="#Required">Required notification contents</a></li>
       <li><a href="#Optional">Optional notification contents and settings</a></li>
       <li><a href="#Actions">Notification actions</a></li>
+      <li><a href="#Priority">Notification priority</a></li>
       <li><a href="#SimpleNotification">Creating a simple notification</a></li>
       <li><a href="#ApplyStyle">Applying a big view style to a notification</a></li>
       <li><a href="#Compatibility">Handling compatibility</a></li>
@@ -290,6 +291,26 @@
     {@link android.support.v4.app.NotificationCompat.Builder}.
 </p>
 <!-- ------------------------------------------------------------------------------------------ -->
+<h3 id="Priority">Notification priority</h3>
+<p>
+    If you wish, you can set the priority of a notification. The priority acts
+    as a hint to the device UI about how the notification should be displayed.
+    To set a notification's priority, call {@link
+    android.support.v4.app.NotificationCompat.Builder#setPriority(int)
+    NotificationCompat.Builder.setPriority()} and pass in one of the {@link
+    android.support.v4.app.NotificationCompat} priority constants. There are
+    five priority levels, ranging from {@link
+    android.support.v4.app.NotificationCompat#PRIORITY_MIN} (-2) to {@link
+    android.support.v4.app.NotificationCompat#PRIORITY_MAX} (2); if not set, the
+    priority defaults to {@link
+    android.support.v4.app.NotificationCompat#PRIORITY_DEFAULT} (0).
+</p>
+<p> For information about setting an appropriate priority level, see "Correctly
+    set and manage notification priority" in the <a
+    href="{@docRoot}design/patterns/notifications.html">Notifications</a> Design
+    guide.
+</p>
+<!-- ------------------------------------------------------------------------------------------ -->
 <h3 id="SimpleNotification">Creating a simple notification</h3>
 <p>
     The following snippet illustrates a simple notification that specifies an activity to open when
diff --git a/docs/html/images/blog.jpg b/docs/html/images/blog.jpg
new file mode 100644
index 0000000..a3ee7d8
--- /dev/null
+++ b/docs/html/images/blog.jpg
Binary files differ
diff --git a/docs/html/images/device-art-ex-crop.jpg b/docs/html/images/device-art-ex-crop.jpg
new file mode 100644
index 0000000..42c769b
--- /dev/null
+++ b/docs/html/images/device-art-ex-crop.jpg
Binary files differ
diff --git a/docs/html/images/gp-about-0.jpg b/docs/html/images/gp-about-0.jpg
new file mode 100644
index 0000000..2dd6a8c
--- /dev/null
+++ b/docs/html/images/gp-about-0.jpg
Binary files differ
diff --git a/docs/html/images/gp-about-listing.jpg b/docs/html/images/gp-about-listing.jpg
new file mode 100644
index 0000000..256c051
--- /dev/null
+++ b/docs/html/images/gp-about-listing.jpg
Binary files differ
diff --git a/docs/html/images/gp-about-picks1.jpg b/docs/html/images/gp-about-picks1.jpg
new file mode 100644
index 0000000..555bd7b
--- /dev/null
+++ b/docs/html/images/gp-about-picks1.jpg
Binary files differ
diff --git a/docs/html/images/gp-about-picks2.jpg b/docs/html/images/gp-about-picks2.jpg
new file mode 100644
index 0000000..ec25e74
--- /dev/null
+++ b/docs/html/images/gp-about-picks2.jpg
Binary files differ
diff --git a/docs/html/images/gp-about-picks3.jpg b/docs/html/images/gp-about-picks3.jpg
new file mode 100644
index 0000000..eb57da9
--- /dev/null
+++ b/docs/html/images/gp-about-picks3.jpg
Binary files differ
diff --git a/docs/html/images/gp-about-top.jpg b/docs/html/images/gp-about-top.jpg
new file mode 100644
index 0000000..01a2744
--- /dev/null
+++ b/docs/html/images/gp-about-top.jpg
Binary files differ
diff --git a/docs/html/images/gp-androidify.png b/docs/html/images/gp-androidify.png
new file mode 100644
index 0000000..122d596
--- /dev/null
+++ b/docs/html/images/gp-androidify.png
Binary files differ
diff --git a/docs/html/images/gp-apps-home.png b/docs/html/images/gp-apps-home.png
deleted file mode 100644
index 851f722..0000000
--- a/docs/html/images/gp-apps-home.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-badge-jp.png b/docs/html/images/gp-badge-jp.png
new file mode 100644
index 0000000..00b5d1f
--- /dev/null
+++ b/docs/html/images/gp-badge-jp.png
Binary files differ
diff --git a/docs/html/images/gp-badges-set.png b/docs/html/images/gp-badges-set.png
new file mode 100644
index 0000000..e2e0e94
--- /dev/null
+++ b/docs/html/images/gp-badges-set.png
Binary files differ
diff --git a/docs/html/images/gp-balance.png b/docs/html/images/gp-balance.png
new file mode 100644
index 0000000..7802bcc
--- /dev/null
+++ b/docs/html/images/gp-balance.png
Binary files differ
diff --git a/docs/html/images/gp-build-buzz-yt.png b/docs/html/images/gp-build-buzz-yt.png
new file mode 100644
index 0000000..7901aa5
--- /dev/null
+++ b/docs/html/images/gp-build-buzz-yt.png
Binary files differ
diff --git a/docs/html/images/gp-buzz-1.jpg b/docs/html/images/gp-buzz-1.jpg
new file mode 100644
index 0000000..ce2444b
--- /dev/null
+++ b/docs/html/images/gp-buzz-1.jpg
Binary files differ
diff --git a/docs/html/images/gp-collectibles.png b/docs/html/images/gp-collectibles.png
deleted file mode 100644
index a63cd50..0000000
--- a/docs/html/images/gp-collectibles.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-community-0.png b/docs/html/images/gp-community-0.png
new file mode 100644
index 0000000..bb8fde2
--- /dev/null
+++ b/docs/html/images/gp-community-0.png
Binary files differ
diff --git a/docs/html/images/gp-core-quality.png b/docs/html/images/gp-core-quality.png
new file mode 100644
index 0000000..196459f
--- /dev/null
+++ b/docs/html/images/gp-core-quality.png
Binary files differ
diff --git a/docs/html/images/gp-dc-ab.png b/docs/html/images/gp-dc-ab.png
new file mode 100644
index 0000000..0604a1b
--- /dev/null
+++ b/docs/html/images/gp-dc-ab.png
Binary files differ
diff --git a/docs/html/images/gp-dc-inapp.jpg b/docs/html/images/gp-dc-inapp.jpg
new file mode 100644
index 0000000..e830e31
--- /dev/null
+++ b/docs/html/images/gp-dc-inapp.jpg
Binary files differ
diff --git a/docs/html/images/gp-dc-invite.png b/docs/html/images/gp-dc-invite.png
new file mode 100644
index 0000000..403b53d
--- /dev/null
+++ b/docs/html/images/gp-dc-invite.png
Binary files differ
diff --git a/docs/html/images/gp-dc-startscreen.jpg b/docs/html/images/gp-dc-startscreen.jpg
new file mode 100644
index 0000000..afaa91b
--- /dev/null
+++ b/docs/html/images/gp-dc-startscreen.jpg
Binary files differ
diff --git a/docs/html/images/gp-details-pages-magicpiano.png b/docs/html/images/gp-details-pages-magicpiano.png
deleted file mode 100644
index 4bb1962..0000000
--- a/docs/html/images/gp-details-pages-magicpiano.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-details-ww.png b/docs/html/images/gp-details-ww.png
deleted file mode 100644
index ccc522c..0000000
--- a/docs/html/images/gp-details-ww.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-e-value.png b/docs/html/images/gp-e-value.png
new file mode 100644
index 0000000..86c8f86
--- /dev/null
+++ b/docs/html/images/gp-e-value.png
Binary files differ
diff --git a/docs/html/images/gp-ecom-0.png b/docs/html/images/gp-ecom-0.png
new file mode 100644
index 0000000..22b6040
--- /dev/null
+++ b/docs/html/images/gp-ecom-0.png
Binary files differ
diff --git a/docs/html/images/gp-edu-monetize.png b/docs/html/images/gp-edu-monetize.png
new file mode 100644
index 0000000..6db273c
--- /dev/null
+++ b/docs/html/images/gp-edu-monetize.png
Binary files differ
diff --git a/docs/html/images/gp-edu-optin-console.jpg b/docs/html/images/gp-edu-optin-console.jpg
new file mode 100644
index 0000000..239b966
--- /dev/null
+++ b/docs/html/images/gp-edu-optin-console.jpg
Binary files differ
diff --git a/docs/html/images/gp-edu-quality.png b/docs/html/images/gp-edu-quality.png
new file mode 100644
index 0000000..b103483
--- /dev/null
+++ b/docs/html/images/gp-edu-quality.png
Binary files differ
diff --git a/docs/html/images/gp-engage-0.jpg b/docs/html/images/gp-engage-0.jpg
new file mode 100644
index 0000000..b4f44b5
--- /dev/null
+++ b/docs/html/images/gp-engage-0.jpg
Binary files differ
diff --git a/docs/html/images/gp-engage-5.jpg b/docs/html/images/gp-engage-5.jpg
new file mode 100644
index 0000000..10fa0c2
--- /dev/null
+++ b/docs/html/images/gp-engage-5.jpg
Binary files differ
diff --git a/docs/html/images/gp-engage-6.jpg b/docs/html/images/gp-engage-6.jpg
new file mode 100644
index 0000000..2da09e1
--- /dev/null
+++ b/docs/html/images/gp-engage-6.jpg
Binary files differ
diff --git a/docs/html/images/gp-engage-9.jpg b/docs/html/images/gp-engage-9.jpg
new file mode 100644
index 0000000..46b94f0
--- /dev/null
+++ b/docs/html/images/gp-engage-9.jpg
Binary files differ
diff --git a/docs/html/images/gp-engage-share-plus.png b/docs/html/images/gp-engage-share-plus.png
new file mode 100644
index 0000000..a1aa46e
--- /dev/null
+++ b/docs/html/images/gp-engage-share-plus.png
Binary files differ
diff --git a/docs/html/images/gp-engage-smule.jpg b/docs/html/images/gp-engage-smule.jpg
new file mode 100644
index 0000000..087da79
--- /dev/null
+++ b/docs/html/images/gp-engage-smule.jpg
Binary files differ
diff --git a/docs/html/images/gp-expand-2.jpg b/docs/html/images/gp-expand-2.jpg
new file mode 100644
index 0000000..a7b6916
--- /dev/null
+++ b/docs/html/images/gp-expand-2.jpg
Binary files differ
diff --git a/docs/html/images/gp-expand-4.jpg b/docs/html/images/gp-expand-4.jpg
new file mode 100644
index 0000000..1d5b1a1
--- /dev/null
+++ b/docs/html/images/gp-expand-4.jpg
Binary files differ
diff --git a/docs/html/images/gp-expand-5.jpg b/docs/html/images/gp-expand-5.jpg
new file mode 100644
index 0000000..b2b2264
--- /dev/null
+++ b/docs/html/images/gp-expand-5.jpg
Binary files differ
diff --git a/docs/html/images/gp-freemium-0.jpg b/docs/html/images/gp-freemium-0.jpg
new file mode 100644
index 0000000..767c1f3
--- /dev/null
+++ b/docs/html/images/gp-freemium-0.jpg
Binary files differ
diff --git a/docs/html/images/gp-freemium-1.jpg b/docs/html/images/gp-freemium-1.jpg
new file mode 100644
index 0000000..1e509c5
--- /dev/null
+++ b/docs/html/images/gp-freemium-1.jpg
Binary files differ
diff --git a/docs/html/images/gp-games-home.png b/docs/html/images/gp-games-home.png
deleted file mode 100644
index 81b7f7a..0000000
--- a/docs/html/images/gp-games-home.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-growth-downloads.png b/docs/html/images/gp-growth-downloads.png
deleted file mode 100644
index 4a4b194..0000000
--- a/docs/html/images/gp-growth-downloads.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-launch-checklist-1.png b/docs/html/images/gp-launch-checklist-1.png
new file mode 100644
index 0000000..069cd69
--- /dev/null
+++ b/docs/html/images/gp-launch-checklist-1.png
Binary files differ
diff --git a/docs/html/images/gp-linking-ex-crop.png b/docs/html/images/gp-linking-ex-crop.png
new file mode 100644
index 0000000..c108651
--- /dev/null
+++ b/docs/html/images/gp-linking-ex-crop.png
Binary files differ
diff --git a/docs/html/images/gp-listing-0.jpg b/docs/html/images/gp-listing-0.jpg
new file mode 100644
index 0000000..a204f9f
--- /dev/null
+++ b/docs/html/images/gp-listing-0.jpg
Binary files differ
diff --git a/docs/html/images/gp-listing-1.png b/docs/html/images/gp-listing-1.png
new file mode 100644
index 0000000..ed15d96
--- /dev/null
+++ b/docs/html/images/gp-listing-1.png
Binary files differ
diff --git a/docs/html/images/gp-listing-2.jpg b/docs/html/images/gp-listing-2.jpg
new file mode 100644
index 0000000..73304f4
--- /dev/null
+++ b/docs/html/images/gp-listing-2.jpg
Binary files differ
diff --git a/docs/html/images/gp-listing-3.jpg b/docs/html/images/gp-listing-3.jpg
new file mode 100644
index 0000000..a4def2e
--- /dev/null
+++ b/docs/html/images/gp-listing-3.jpg
Binary files differ
diff --git a/docs/html/images/gp-listing-4.jpg b/docs/html/images/gp-listing-4.jpg
new file mode 100644
index 0000000..f580f86
--- /dev/null
+++ b/docs/html/images/gp-listing-4.jpg
Binary files differ
diff --git a/docs/html/images/gp-localization-trans-0.png b/docs/html/images/gp-localization-trans-0.png
new file mode 100644
index 0000000..2e7b73e
--- /dev/null
+++ b/docs/html/images/gp-localization-trans-0.png
Binary files differ
diff --git a/docs/html/images/gp-optimize-analytics.png b/docs/html/images/gp-optimize-analytics.png
new file mode 100644
index 0000000..81298d0
--- /dev/null
+++ b/docs/html/images/gp-optimize-analytics.png
Binary files differ
diff --git a/docs/html/images/gp-optimize-speed.png b/docs/html/images/gp-optimize-speed.png
new file mode 100644
index 0000000..6ebb995
--- /dev/null
+++ b/docs/html/images/gp-optimize-speed.png
Binary files differ
diff --git a/docs/html/images/gp-optimize.png b/docs/html/images/gp-optimize.png
new file mode 100644
index 0000000..e8388ea
--- /dev/null
+++ b/docs/html/images/gp-optimize.png
Binary files differ
diff --git a/docs/html/images/gp-optimizing-chat-bubbles.png b/docs/html/images/gp-optimizing-chat-bubbles.png
new file mode 100644
index 0000000..71ac767
--- /dev/null
+++ b/docs/html/images/gp-optimizing-chat-bubbles.png
Binary files differ
diff --git a/docs/html/images/gp-optimizing-image-4.jpg b/docs/html/images/gp-optimizing-image-4.jpg
new file mode 100644
index 0000000..949ca81
--- /dev/null
+++ b/docs/html/images/gp-optimizing-image-4.jpg
Binary files differ
diff --git a/docs/html/images/gp-payments-1.png b/docs/html/images/gp-payments-1.png
new file mode 100644
index 0000000..6eaca93
--- /dev/null
+++ b/docs/html/images/gp-payments-1.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-eula-violation.png b/docs/html/images/gp-policy-ads-eula-violation.png
deleted file mode 100644
index 204c320..0000000
--- a/docs/html/images/gp-policy-ads-eula-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-impersonate-violation-app-ui.png b/docs/html/images/gp-policy-ads-impersonate-violation-app-ui.png
deleted file mode 100644
index a2a39a9..0000000
--- a/docs/html/images/gp-policy-ads-impersonate-violation-app-ui.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-impersonate-violation-sys-warning.png b/docs/html/images/gp-policy-ads-impersonate-violation-sys-warning.png
deleted file mode 100644
index f323b06..0000000
--- a/docs/html/images/gp-policy-ads-impersonate-violation-sys-warning.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-impersonate-violation.png b/docs/html/images/gp-policy-ads-impersonate-violation.png
deleted file mode 100644
index 385ae6e..0000000
--- a/docs/html/images/gp-policy-ads-impersonate-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-interstitial-violation.png b/docs/html/images/gp-policy-ads-interstitial-violation.png
deleted file mode 100644
index 4871493..0000000
--- a/docs/html/images/gp-policy-ads-interstitial-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-maturity-violation.png b/docs/html/images/gp-policy-ads-maturity-violation.png
deleted file mode 100644
index d41870e..0000000
--- a/docs/html/images/gp-policy-ads-maturity-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-notif-attr-violation.png b/docs/html/images/gp-policy-ads-notif-attr-violation.png
deleted file mode 100644
index 3d6393b..0000000
--- a/docs/html/images/gp-policy-ads-notif-attr-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-notif-attr.png b/docs/html/images/gp-policy-ads-notif-attr.png
deleted file mode 100644
index da39cfb..0000000
--- a/docs/html/images/gp-policy-ads-notif-attr.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-paywall-violation.png b/docs/html/images/gp-policy-ads-paywall-violation.png
deleted file mode 100644
index 8bbfd1b..0000000
--- a/docs/html/images/gp-policy-ads-paywall-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-paywall.png b/docs/html/images/gp-policy-ads-paywall.png
deleted file mode 100644
index e7b1e19..0000000
--- a/docs/html/images/gp-policy-ads-paywall.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-terms.png b/docs/html/images/gp-policy-ads-terms.png
deleted file mode 100644
index dcbdf4a..0000000
--- a/docs/html/images/gp-policy-ads-terms.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ip-copyright-violation.png b/docs/html/images/gp-policy-ip-copyright-violation.png
deleted file mode 100644
index a4e96a8..0000000
--- a/docs/html/images/gp-policy-ip-copyright-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ip-impersonation-violation.png b/docs/html/images/gp-policy-ip-impersonation-violation.png
deleted file mode 100644
index b1d9923..0000000
--- a/docs/html/images/gp-policy-ip-impersonation-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ip-trademark-violation.png b/docs/html/images/gp-policy-ip-trademark-violation.png
deleted file mode 100644
index c05b67b..0000000
--- a/docs/html/images/gp-policy-ip-trademark-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-spam-negreview.png b/docs/html/images/gp-policy-spam-negreview.png
deleted file mode 100644
index f68eba3..0000000
--- a/docs/html/images/gp-policy-spam-negreview.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-spam-reqrating.png b/docs/html/images/gp-policy-spam-reqrating.png
deleted file mode 100644
index 20e17c1..0000000
--- a/docs/html/images/gp-policy-spam-reqrating.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-premium-0.png b/docs/html/images/gp-premium-0.png
new file mode 100644
index 0000000..4bacc25
--- /dev/null
+++ b/docs/html/images/gp-premium-0.png
Binary files differ
diff --git a/docs/html/images/gp-rating-web.png b/docs/html/images/gp-rating-web.png
index 0885826..14582af 100644
--- a/docs/html/images/gp-rating-web.png
+++ b/docs/html/images/gp-rating-web.png
Binary files differ
diff --git a/docs/html/images/gp-sendto.png b/docs/html/images/gp-sendto.png
deleted file mode 100644
index 7409c14..0000000
--- a/docs/html/images/gp-sendto.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-start-button.png b/docs/html/images/gp-start-button.png
new file mode 100644
index 0000000..fa3d5e1
--- /dev/null
+++ b/docs/html/images/gp-start-button.png
Binary files differ
diff --git a/docs/html/images/gp-start-wallet-icon.png b/docs/html/images/gp-start-wallet-icon.png
new file mode 100644
index 0000000..3ecbcf6
--- /dev/null
+++ b/docs/html/images/gp-start-wallet-icon.png
Binary files differ
diff --git a/docs/html/images/gp-subs.png b/docs/html/images/gp-subs.png
deleted file mode 100644
index 9b3a7df..0000000
--- a/docs/html/images/gp-subs.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-subscription-0.jpg b/docs/html/images/gp-subscription-0.jpg
new file mode 100644
index 0000000..0c4b389
--- /dev/null
+++ b/docs/html/images/gp-subscription-0.jpg
Binary files differ
diff --git a/docs/html/images/gp-tab.png b/docs/html/images/gp-tab.png
deleted file mode 100644
index 4673d21..0000000
--- a/docs/html/images/gp-tab.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-tablet-quality-4.jpg b/docs/html/images/gp-tablet-quality-4.jpg
new file mode 100644
index 0000000..33dfcbd
--- /dev/null
+++ b/docs/html/images/gp-tablet-quality-4.jpg
Binary files differ
diff --git a/docs/html/images/gp-tablet-quality-5.jpg b/docs/html/images/gp-tablet-quality-5.jpg
new file mode 100644
index 0000000..668482a
--- /dev/null
+++ b/docs/html/images/gp-tablet-quality-5.jpg
Binary files differ
diff --git a/docs/html/images/gp-tablets-full-feature-set.png b/docs/html/images/gp-tablets-full-feature-set.png
new file mode 100644
index 0000000..fa04082
--- /dev/null
+++ b/docs/html/images/gp-tablets-full-feature-set.png
Binary files differ
diff --git a/docs/html/images/gp-top-new-paid.png b/docs/html/images/gp-top-new-paid.png
deleted file mode 100644
index d98d6ca..0000000
--- a/docs/html/images/gp-top-new-paid.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-your-user-0.jpg b/docs/html/images/gp-your-user-0.jpg
new file mode 100644
index 0000000..9286b54
--- /dev/null
+++ b/docs/html/images/gp-your-user-0.jpg
Binary files differ
diff --git a/docs/html/images/gp-your-user-2.jpg b/docs/html/images/gp-your-user-2.jpg
new file mode 100644
index 0000000..0f44e2a
--- /dev/null
+++ b/docs/html/images/gp-your-user-2.jpg
Binary files differ
diff --git a/docs/html/images/gpfe-developer.png b/docs/html/images/gpfe-developer.png
new file mode 100644
index 0000000..4b3251c
--- /dev/null
+++ b/docs/html/images/gpfe-developer.png
Binary files differ
diff --git a/docs/html/images/gpfe-educator.png b/docs/html/images/gpfe-educator.png
new file mode 100644
index 0000000..6e49a7fd
--- /dev/null
+++ b/docs/html/images/gpfe-educator.png
Binary files differ
diff --git a/docs/html/images/gpfe-start-0.jpg b/docs/html/images/gpfe-start-0.jpg
new file mode 100644
index 0000000..e97381d
--- /dev/null
+++ b/docs/html/images/gpfe-start-0.jpg
Binary files differ
diff --git a/docs/html/images/gpp-cat-feature280-photo.png b/docs/html/images/gpp-cat-feature280-photo.png
deleted file mode 100644
index ae2749b..0000000
--- a/docs/html/images/gpp-cat-feature280-photo.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gpp-cat-feature280-puzzle.png b/docs/html/images/gpp-cat-feature280-puzzle.png
deleted file mode 100644
index db203c6..0000000
--- a/docs/html/images/gpp-cat-feature280-puzzle.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gpp-cat-feature280-sports.png b/docs/html/images/gpp-cat-feature280-sports.png
deleted file mode 100644
index dcd70aa..0000000
--- a/docs/html/images/gpp-cat-feature280-sports.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/play_dev.jpg b/docs/html/images/play_dev.jpg
new file mode 100644
index 0000000..6aae165
--- /dev/null
+++ b/docs/html/images/play_dev.jpg
Binary files differ
diff --git a/docs/html/images/play_dev.png b/docs/html/images/play_dev_sm.png
similarity index 100%
rename from docs/html/images/play_dev.png
rename to docs/html/images/play_dev_sm.png
Binary files differ
diff --git a/docs/html/images/plus.jpg b/docs/html/images/plus.jpg
new file mode 100644
index 0000000..652aa1a
--- /dev/null
+++ b/docs/html/images/plus.jpg
Binary files differ
diff --git a/docs/html/images/tools/studio_error_gradle5.png b/docs/html/images/tools/studio_error_gradle5.png
deleted file mode 100644
index 13de607..0000000
--- a/docs/html/images/tools/studio_error_gradle5.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/tools/studio_error_supportlib.png b/docs/html/images/tools/studio_error_supportlib.png
deleted file mode 100644
index 603b54c..0000000
--- a/docs/html/images/tools/studio_error_supportlib.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/video-Colopl.png b/docs/html/images/video-Colopl.png
deleted file mode 100644
index 0ee88c6..0000000
--- a/docs/html/images/video-Colopl.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index 99a469a..a4b0683 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -39,13 +39,12 @@
                       <script src="//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
                       <div style="box-shadow: 3px 10px 18px 1px #999;width:600px;height:336px">
                         <div id="ytapiplayer">
-                          <a href="http://www.youtube.com/watch?v=i2uvYI6blEE"><img width=600 
-                          src="https://i1.ytimg.com/vi/i2uvYI6blEE/maxresdefault.jpg"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. -->
+                          <a href="http://www.youtube.com/watch?v=WWArLD6nqrk"><img width=600 src="{@docRoot}images/video-kiwi.jpg"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. -->
                         </div>
                         <script type="text/javascript">
                             var params = { allowScriptAccess: "always" };
                             var atts = { id: "ytapiplayer" };
-                            swfobject.embedSWF("//www.youtube.com/v/i2uvYI6blEE?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1",
+                            swfobject.embedSWF("//www.youtube.com/v/WWArLD6nqrk?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1",
                               "ytapiplayer", "600", "336", "8", null, null, params, atts);
 
                             // Callback used to pause/resume carousel based on video state
@@ -74,9 +73,10 @@
                       </div>
                     </div>
                     <div class="content-right col-4">
-                    <h1 style="white-space:nowrap;line-height:1.2em;">Developer Story: <br />Box Inc.</h1>
-                    <p>Box is a cloud-based platform and app for users to share business information. See how they got over 5 million downloads by leveraging the flexibility in the Android platform.</p>
-                      <p><a href="{@docRoot}distribute/googleplay/spotlight/index.html" class="button">Watch more videos </a></p>
+                    <h1 style="white-space:nowrap;line-height:1.2em;">Developer Story: <br />Kiwi, Inc.</h1>
+                    <p>Game developer Kiwi has had five titles in the top 25 grossing on Google Play. Hear how Google Play
+                      has helped them double revenue every six months.</p>
+                      <p><a href="{@docRoot}distribute/stories/index.html" class="button">Watch more videos </a></p>
                     </div>
                 </li>
 
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
new file mode 100644
index 0000000..8a4ac47
--- /dev/null
+++ b/docs/html/jd_collections.js
@@ -0,0 +1,697 @@
+var RESOURCE_COLLECTIONS = {
+  "launch/static": {
+    "title": "",
+    "resources": [
+      "http://www.youtube.com/watch?v=1RIz-cmTQB4",
+      "http://www.youtube.com/watch?v=MVBMWDzyHAI",
+      "http://android-developers.blogspot.com/2013/11/app-translation-service-now-available.html",
+      "http://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
+      "http://android-developers.blogspot.com/2013/11/bring-your-apps-into-classroom-with.html",
+      "distribute/essentials/quality/tablets.html",
+      "distribute/users/build-buzz.html",
+      "distribute/monetize/premium.html",
+      "distribute/monetize/freemium.html",
+      "distribute/monetize/ads.html",
+      "distribute/essentials/best-practices/apps.html",
+      "distribute/essentials/best-practices/games.html",
+      "distribute/users/know-your-user.html",
+      "distribute/googleplay/developer-console.html"
+    ]
+  },
+  "distribute/gp/gplanding": {
+    "resources": [
+      "distribute/googleplay/about.html",
+      "distribute/googleplay/start.html",
+      "distribute/googleplay/developer-console.html"
+    ]
+  },
+  "distribute/gp/gpfelanding": {
+    "resources": [
+      "distribute/googleplay/edu/about.html",
+      "distribute/googleplay/edu/start.html",
+      "distribute/googleplay/edu/faq.html"
+    ]
+  },
+  "distribute/essentials": {
+    "resources": [
+      "distribute/essentials/quality/core.html",
+      "distribute/essentials/quality/tablets.html",
+      "distribute/essentials/gpfe-guidelines.html",
+      "distribute/essentials/optimizing-your-app.html",
+      "distribute/essentials/best-practices/apps.html",
+      "distribute/essentials/best-practices/games.html"
+    ]
+  },
+  "distribute/users": {
+    "title": "",
+    "resources": [
+      "distribute/users/know-your-user.html",
+      "distribute/users/your-listing.html",
+      "distribute/users/build-buzz.html",
+      "distribute/users/build-community.html",
+      "distribute/users/expand-to-new-markets.html"
+    ]
+  },
+  "distribute/engagelanding": {
+    "resources": [
+      "distribute/engage/widgets.html",
+      "distribute/engage/notifications.html",
+      "distribute/engage/gcm.html",
+      "distribute/engage/easy-signin.html",
+      "distribute/engage/deep-linking.html",
+      "distribute/engage/game-services.html",
+      "distribute/engage/app-updates.html",
+      "distribute/engage/community.html",
+      "distribute/engage/video.html"
+    ]
+  },
+  "distribute/monetize": {
+    "resources": [
+      "distribute/monetize/premium.html",
+      "distribute/monetize/freemium.html",
+      "distribute/monetize/subscriptions.html",
+      "distribute/monetize/ecommerce.html",
+      "distribute/monetize/ads.html",
+      "distribute/monetize/payments.html"
+    ]
+  },
+  "distribute/tools/checklists": {
+    "title": "",
+    "resources": [
+      "distribute/tools/launch-checklist.html",
+      "distribute/tools/localization-checklist.html"
+    ]
+  },
+  "distribute/tools/promote": {
+    "resources": [
+      "distribute/tools/promote/device-art.html",
+      "distribute/tools/promote/badges.html",
+      "distribute/tools/promote/linking.html"
+    ]
+  },
+  "distribute/tools/support": {
+    "title": "Google Play",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer",
+      "https://support.google.com/googleplay/android-developer/answer/4430948",
+      "support.html"
+    ]
+  },
+  "distribute/tools/news": {
+    "title": "",
+    "resources": [
+      "http://android-developers.blogspot.com/",
+      "https://plus.google.com/+AndroidDevelopers/"
+    ]
+  },
+  "distribute/tools/more": {
+    "title": "Google Play",
+    "resources": [
+      "distribute/tools/promote/brand.html",
+      "distribute/tools/open-distribution.html",
+      "about/dashboards/index.html"
+    ]
+  },
+  "distribute/googleplay": {
+    "title": "Google Play",
+    "resources": [
+      "distribute/googleplay/developer-console.html",
+      "distribute/essentials/best-practices/apps.html",
+      "distribute/tools/launch-checklist.html",
+      "distribute/essentials/best-practices/games.html",
+    ]
+  },
+  "distribute/googleplay/gettingstarted": {
+    "title": "Get Started",
+    "resources": [
+      "distribute/googleplay/developer-console.html",
+      "https://support.google.com/googleplay/android-developer/answer/113468",
+      "https://support.google.com/googleplay/android-developer/answer/138294",
+      "https://support.google.com/googleplay/android-developer"
+    ]
+  },
+  "distribute/googleplay/developerconsole": {
+    "title": "Developer Console",
+    "resources": [
+      "google/play/billing/index.html",
+      "https://support.google.com/googleplay/android-developer/answer/138294"
+    ]
+  },
+  "distribute/googleplay/gpfe/highlight": {
+    "title": "About Google Play for Education",
+    "resources": [
+      "http://youtu.be/vzvpcEffvaE"
+    ]
+  },
+  "distribute/googleplay/gpfe/dev/about": {
+    "title": "About Google Play for Education / Developers",
+    "resources": [
+      "distribute/googleplay/edu/start.html",
+      "distribute/essentials/gpfe-guidelines.html",
+      "distribute/googleplay/edu/faq.html",
+      "distribute/essentials/quality/tablets.html"
+    ]
+  },
+  "distribute/googleplay/gpfe/dev": {
+    "title": "About Google Play for Education / Developers",
+    "resources": [
+      "distribute/googleplay/edu/about.html",
+      "distribute/essentials/gpfe-guidelines.html",
+      "distribute/essentials/quality/tablets.html",
+      "distribute/googleplay/developer-console.html",
+      "http://play.google.com/about/developer-distribution-agreement-addendum.html",
+    ]
+  },
+  "distribute/googleplay/aboutgpfe/educators/about": {
+    "title": "About Google Play for Education / Educators",
+    "resources": [
+      "http://www.google.com/edu/tablets/",
+      "http://www.youtube.com/watch?v=haEmsMo0f3w"
+    ]
+  },
+  "distribute/googleplay/aboutgpfe/educators": {
+    "title": "About Google Play for Education / Educators",
+    "resources": [
+      "http://www.google.com/edu/tablets/",
+      "http://youtu.be/vzvpcEffvaE"
+    ]
+  },
+  "distribute/googleplay/gettingstartedgpfe/educators": {
+    "title": "About Google Play for Education / Educators",
+    "resources": [
+      "http://www.google.com/edu/tablets/",
+      "http://youtu.be/vzvpcEffvaE"
+    ]
+  },
+  "distribute/essentials/eduessentials/developers": {
+    "title": "",
+    "resources": [
+      "distribute/googleplay/developer-console.html",
+      "distribute/googleplay/edu/start.html",
+      "distribute/googleplay/edu/faq.html"
+    ]
+  },
+  "distribute/essentials/eduessentials/educators": {
+    "title": "",
+    "resources": [
+      "http://www.google.com/edu/tablets/",
+      "distribute/essentials/quality/tablets.html",
+    ]
+  },
+  "distribute/essentials/optimizing": {
+    "title": "Optimizing Your App",
+    "resources": [
+      "design/index.html",
+      "training/articles/perf-anr.html",
+      "http://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html"
+     ]
+  },
+  "distribute/users/knowyouruser": {
+    "title": "",
+    "resources": [
+      "distribute/essentials/optimizing-your-app.html",
+      "http://www.youtube.com/watch?v=RRelFvc6Czo",
+      "distribute/stories/localization.html"
+    ]
+  },
+  "distribute/users/buildbuzz": {
+    "title": "",
+    "resources": [
+      "distribute/tools/promote/badges.html",
+      "distribute/tools/promote/linking.html",
+      "distribute/tools/promote/device-art.html",
+      "http://plus.google.com/+GooglePlay"
+    ]
+  },
+  "distribute/users/createagreatlisting": {
+    "title": "",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer/answer/1078870",
+      "http://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
+      "distribute/tools/launch-checklist.html",
+      "http://android-developers.blogspot.com/2013/07/making-beautiful-android-app-icons.html",
+      "http://android-developers.blogspot.com/2012/12/localize-your-promotional-graphics-on.html",
+      "http://android-developers.blogspot.com/2013/10/making-your-app-content-more-accessible.html"
+    ]
+  },
+  "distribute/users/buildcommunity": {
+    "title": "",
+    "resources": [
+      "distribute/googleplay/developer-console.html",
+      "https://support.google.com/groups/answer/46601",
+      "https://support.google.com/plus/topic/2888488",
+      "http://www.youtube.com/yt/dev/"
+    ]
+  },
+  "distribute/toolsreference/bestpractices/apps": {
+    "title": "",
+    "resources": [
+      "distribute/googleplay/developer-console.html",
+      "http://android-developers.blogspot.com/"
+    ]
+  },
+  "distribute/toolsreference/bestpractices/games": {
+    "title": "",
+    "resources": [
+      "google/play-services/games.html",
+      "http://android-developers.blogspot.com/",
+      "distribute/googleplay/developer-console.html",
+      "http://www.youtube.com/watch?v=1RIz-cmTQB4"
+    ]
+  },
+  "distribute/essentials/corequalityguidelines/visualdesign": {
+    "title": "",
+    "resources": [
+      "design/index.html",
+      "design/patterns/navigation.html",
+      "design/patterns/actionbar.html",
+      "design/style/iconography.html",
+      "design/patterns/notifications.html"
+    ]
+  },
+  "distribute/essentials/corequalityguidelines/functionality": {
+    "title": "",
+    "resources": [
+      "http://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html",
+      "guide/components/tasks-and-back-stack.html",
+      "training/basics/activity-lifecycle/recreating.html"
+    ]
+  },
+  "distribute/essentials/core/performance": {
+    "title": "",
+    "resources": [
+      "http://android-developers.blogspot.com/2010/12/new-gingerbread-api-strictmode.html",
+      "training/articles/perf-anr.html",
+      "http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html"
+    ]
+  },
+  "distribute/essentials/core/play": {
+    "title": "",
+    "resources": [
+      "distribute/tools/launch-checklist.html",
+      "http://play.google.com/about/developer-content-policy.html",
+      "https://support.google.com/googleplay/android-developer/answer/188189",
+      "https://support.google.com/googleplay/android-developer/answer/1078870",
+      "http://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
+      "https://support.google.com/googleplay/android-developer/answer/113477"
+    ]
+  },
+  "distribute/essentials/tabletguidelines/optimize": {
+    "title": "",
+    "resources": [
+      "design/style/metrics-grids.html",
+      "design/style/devices-displays.html",
+      "guide/practices/screens_support.html",
+      //"guide/practices/screens_support.html#ConfigurationExamples",
+    ]
+  },
+  "distribute/essentials/tabletguidelines/extrascreen": {
+    "title": "",
+    "resources": [
+      "design/patterns/multi-pane-layouts.html",
+      "training/design-navigation/multiple-sizes.html",
+      "training/multiscreen/index.html",
+    ]
+  },
+  "distribute/essentials/tabletguidelines/assets": {
+    "title": "",
+    "resources": [
+      "design/style/iconography.html",
+      "guide/topics/resources/providing-resources.html",
+      "guide/practices/screens_support.html",
+      "training/basics/supporting-devices/screens.html"
+    ]
+  },
+  "distribute/essentials/tabletguidelines/fonts": {
+    "title": "",
+    "resources": [
+      "design/style/metrics-grids.html",
+      "design/style/typography.html",
+      "guide/practices/screens_support.html",
+      "training/multiscreen/screendensities.html"
+    ]
+  },
+  "distribute/essentials/tabletguidelines/widgets": {
+    "title": "",
+    "resources": [
+      "guide/topics/appwidgets/index.html#MetaData",
+      "guide/topics/appwidgets/index.html",
+      "design/patterns/widgets.html"
+    ]
+  },
+  "distribute/essentials/tabletguidelines/versions": {
+    "title": "",
+    "resources": [
+      "guide/topics/manifest/uses-sdk-element.html#ApiLevels",
+      "guide/topics/manifest/uses-sdk-element.html",
+      "training/basics/supporting-devices/platforms.html"
+    ]
+  },
+  "distribute/essentials/tabletguidelines/hardware": {
+    "title": "",
+    "resources": [
+      "guide/topics/manifest/uses-feature-element.html",
+      "guide/topics/manifest/uses-feature-element.html#testing"
+    ]
+  },
+ "distribute/essentials/tabletguidelines/tabletscreens": {
+    "title": "",
+    "resources": [
+      "guide/practices/screens_support.html#DeclaringScreenSizeSupport",
+      "guide/practices/screens_support.html"
+    ]
+  },
+  "distribute/essentials/tabletguidelines/showcase": {
+    "title": "",
+    "resources": [
+      "distribute/tools/launch-checklist.html",
+      "https://play.google.com/apps/publish/",
+      "distribute/tools/promote/badges.html",
+      "distribute/tools/promote/device-art.html"
+    ]
+  },
+  "distribute/essentials/tabletguidelines/googleplay": {
+    "title": "",
+    "resources": [
+      "http://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
+      "google/play/filters.html"
+    ]
+  },
+  "distribute/essentials/tabletguidelines": {
+    "title": "",
+    "resources": [
+      "distribute/essentials/quality/core.html",
+      "http://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
+      "distribute/tools/launch-checklist.html",
+      "distribute/tools/promote/device-art.html"
+    ]
+  },
+  "distribute/getusers/notifications": {
+    "title": "",
+    "resources": [
+      "design/patterns/notifications.html",
+      "distribute/engage/gcm.html",
+      "http://play.google.com/about/developer-content-policy.html"
+    ]
+  },
+  "distribute/engage/widgets": {
+    "title": "",
+    "resources": [
+      "design/patterns/widgets.html",
+      "guide/topics/appwidgets/index.html"
+    ]
+  },
+  "distribute/getusers/expandnewmarkets": {
+    "title": "",
+    "resources": [
+      "distribute/tools/localization-checklist.html",
+      "https://support.google.com/googleplay/android-developer/table/3541286",
+      "distribute/stories/localization.html",
+      "distribute/tools/promote/badges.html",
+      "distribute/tools/promote/device-art.html",
+      "http://www.youtube.com/watch?v=SkHHPf3EdzE"
+    ]
+  },
+  "distribute/engage/gcm": {
+    "title": "",
+    "resources": [
+      "google/gcm/index.html",
+      "http://developer.chrome.com/apps/cloudMessagingV2",
+      "http://www.youtube.com/watch?v=y76rjidm8cU"
+    ]
+  },
+  "distribute/engage/googleplaygames": {
+    "title": "",
+    "resources": [
+      "google/play-services/games.html",
+      "distribute/essentials/best-practices/games.html"
+    ]
+  },
+  "distribute/engage/gplus": {
+    "title": "",
+    "resources": [
+      "google/play-services/plus.html",
+      "google/play-services/games.html",
+      "https://developers.google.com/+/mobile/android/share/interactive-post",
+      "https://developers.google.com/+/mobile/android/share/deep-link"
+    ]
+  },
+  "distribute/engage/community": {
+    "title": "",
+    "resources": [
+      "distribute/users/build-community.html",
+      "distribute/engage/video.html"
+    ]
+  },
+  "distribute/engage/deeplinks": {
+    "title": "",
+    "resources": [
+      "distribute/engage/easy-signin.html",
+      "https://developers.google.com/app-indexing/",
+      "https://developers.google.com/+/mobile/android/share/interactive-post"
+    ]
+  },
+  "distribute/engage/appupdates": {
+    "title": "",
+    "resources": [
+      "distribute/essentials/optimizing-your-app.html",
+      "distribute/tools/launch-checklist.html",
+      "distribute/googleplay/developer-console.html",
+      "design/patterns/notifications.html"
+    ]
+  },
+  "distribute/engage/video/more": {
+    "title": "",
+    "resources": [
+      "http://www.youtube.com/yt/dev/",
+      "distribute/essentials/best-practices/games.html",
+      "http://www.youtube.com/watch?v=RRelFvc6Czo"
+    ]
+  },
+  "distribute/engage/community": {
+    "title": "",
+    "resources": [
+      "distribute/users/build-community.html",
+      "distribute/engage/video.html"
+    ]
+  },
+  "distribute/engage/kiwi": {
+    "title": "",
+    "resources": [
+      "http://www.youtube.com/watch?v=WWArLD6nqrk"
+    ]
+  },
+  "distribute/toolsreference/gpfefaq": {
+    "title": "",
+    "resources": [
+      "http://www.google.com/edu/tablets/",
+      "distribute/googleplay/edu/start.html",
+      "http://play.google.com/about/developer-distribution-agreement-addendum.html",
+      "distribute/essentials/quality/core.html",
+      "distribute/essentials/quality/tablets.html"
+    ]
+  },
+  "distribute/toolsreference/localizationchecklist/identifylocales": {
+    "title": "",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer/answer/138294"
+    ]
+  },
+  "distribute/tools/loc/designforloc": {
+    "title": "",
+    "resources": [
+      "http://android-developers.blogspot.com/2013/03/native-rtl-support-in-android-42.html",
+      "guide/topics/resources/string-resource.html#Plurals",
+      "guide/topics/resources/string-resource.html",
+      "reference/java/util/Locale.html"
+    ]
+  },
+  "distribute/toolsreference/localizationchecklist/managestrings": {
+    "title": "",
+    "resources": [
+      "guide/topics/resources/string-resource.html",
+      "design/style/writing.html",
+      "http://en.wikipedia.org/wiki/XLIFF"
+    ]
+  },
+  "distribute/toolsreference/localizationchecklist/translatestrings": {
+    "title": "",
+    "resources": [
+      "distribute/stories/localization.html",
+    ]
+  },
+  "distribute/toolsreference/localizationchecklist/preplaunch": {
+    "title": "",
+    "resources": [
+      "distribute/tools/promote/badges.html",
+      "distribute/tools/promote/device-art.html"
+    ]
+  },
+  "distribute/toolsreference/localizationchecklist/supportlaunch": {
+    "title": "",
+    "resources": [
+      "distribute/tools/launch-checklist.html",
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/understanding": {
+    "title": "",
+    "resources": [
+      "tools/publishing/publishing_overview.html",
+      "tools/publishing/preparing.html"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/policies": {
+    "title": "",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer/answer/4430948",
+      "https://support.google.com/googleplay/android-developer/topic/2364761",
+      "https://support.google.com/googleplay/android-developer"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/quality": {
+    "title": "",
+    "resources": [
+      "distribute/essentials/quality/core.html",
+      "distribute/essentials/quality/tablets.html",
+      "distribute/essentials/gpfe-guidelines.html"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/rating": {
+    "title": "",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer/answer/188189",
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/country": {
+    "title": "",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer/answer/138294"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/size": {
+    "title": "",
+    "resources": [
+      "google/play/expansion-files.html",
+      "tools/help/proguard.html"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/platform": {
+    "title": "",
+    "resources": [
+      "guide/practices/screens_support.html",
+      "about/dashboards/index.html",
+      "guide/topics/manifest/uses-sdk-element.html"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/price": {
+    "title": "",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer/table/3541286",
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/purchasemethod": {
+    "title": "",
+    "resources": [
+      "google/play/billing/index.html",
+      "google/play/billing/billing_subscriptions.html"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/setprice": {
+    "title": "",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer/answer/1169947",
+      "https://support.google.com/googleplay/android-developer/answer/138412",
+      "https://support.google.com/googleplay/android-developer/answer/112622",
+      "https://support.google.com/googleplay/android-developer/answer/138000"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/localization": {
+    "title": "",
+    "resources": [
+      "distribute/tools/localization-checklist.html",
+      "guide/topics/resources/localization.html",
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/graphics": {
+    "title": "",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer/answer/1078870",
+      "http://android-developers.blogspot.com/2011/10/android-market-featured-image.html"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/productdetails": {
+    "title": "",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer/answer/113475",
+      "https://support.google.com/googleplay/android-developer/answer/1078870"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/badges": {
+    "title": "",
+    "resources": [
+      "distribute/tools/promote/badges.html",
+      "distribute/tools/promote/linking.html"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/finalchecks": {
+    "title": "",
+    "resources": [
+      "http://play.google.com/about/developer-content-policy.html",
+      "https://support.google.com/googleplay/android-developer/answer/113476",
+      "support.html"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/afterlaunch": {
+    "title": "",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer/answer/113477",
+      "https://support.google.com/googleplay/android-developer/answer/1153479",
+      "https://support.google.com/payments/answer/2741495",
+      "distribute/essentials/optimizing-your-app.html"
+    ]
+  },
+  "distribute/monetize/premium": {
+    "title": "",
+    "resources": [
+      "google/play/billing/index.html",
+      "https://support.google.com/googleplay/android-developer/answer/4407611"
+    ]
+  },  
+  "distribute/monetize/freemium": {
+    "title": "",
+    "resources": [
+      "google/play/billing/index.html",
+      "https://support.google.com/googleplay/android-developer/answer/4407611"
+    ]
+  },
+  "distribute/monetize/subscriptions": {
+    "title": "",
+    "resources": [
+      "google/play/billing/billing_subscriptions.html",
+      "https://support.google.com/googleplay/android-developer/answer/4407611"
+    ]
+  },
+  "distribute/monetize/ecommerce": {
+    "title": "",
+    "resources": [
+      "https://developers.google.com/wallet/instant-buy/",
+      "https://support.google.com/googleplay/android-developer/answer/4407611"
+    ]
+  },
+  "distribute/monetize/advertising": {
+    "title": "",
+    "resources": [
+      "http://www.google.com/ads/admob/#subid=us-en-et-dac",
+      "http://www.google.com/doubleclick/publishers/small-business/index.html",
+      "http://support.google.com/googleplay/android-developer/topic/2985714",
+      "training/monetization/ads-and-ux.html"
+    ]
+  },
+  "distribute/monetize/paymentmethods": {
+    "title": "",
+    "resources": [
+      "https://play.google.com/about/giftcards/",
+      "https://support.google.com/googleplay/answer/2651410"
+    ]
+  },
+}
diff --git a/docs/html/jd_extras.js b/docs/html/jd_extras.js
new file mode 100644
index 0000000..f26b747b
--- /dev/null
+++ b/docs/html/jd_extras.js
@@ -0,0 +1,1104 @@
+/* Metadata represendations of resources that are outside of the autogenerated
+   local resource lists, or that override local resource representations.
+
+   Resources listed here are referenced from sitemap sections and collections,
+   matched by url string if there is no resource existing in ALL_RESOURCES.
+
+   Currently, these articles can override only the generated resources
+   in DISTRIBUTE_RESOURCES. A representation defined here will not be applied
+   when a collection or section specifies a url that's not in DISTRIBUTE_RESOURCEs.
+   Also
+   So if a section url refers to a static doc that's
+   not in a distribute section, you need to create an item for
+   it in this file. Fix is to compare across
+   ALL_RESOURCES_BY_URL.  */
+
+DISTRIBUTE_RESOURCES = DISTRIBUTE_RESOURCES.concat([
+  {
+    "title":"Developer Registration",
+    "titleFriendly":"",
+    "summary":"Additional information about the registration process.",
+    "url":"https://support.google.com/googleplay/android-developer/answer/113468",
+    "group":"",
+    "keywords": [],
+    "tags": [],
+    "image":"images/play_dev.jpg",
+    "type":"google"
+  },
+  {
+    "title": "Google Play Distribution and Seller Countries",
+    "titleFriendly":"",
+    "summary": "List of countries and territories where you can distribute your apps in Google Play.",
+    "url":"https://support.google.com/googleplay/android-developer/answer/138294",
+    "group":"",
+    "keywords": [],
+    "tags": [],
+    "image":"images/play_dev.jpg",
+    "type":"google"
+  },
+  {
+    "title":"Google Play Content Policies",
+    "titleFriendly":"",
+    "summary":"Details on policies relating to your developer account and app distribution is governed.",
+    "url":"https://support.google.com/googleplay/android-developer/topic/3453577",
+    "group":"",
+    "keywords": [],
+    "tags": ["#developersupport"],
+    "image":"images/play_dev.jpg",
+    "type":"google"
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["#developersupport #termsandpolicies"],
+    "url": "https://support.google.com/googleplay/android-developer/answer/4407611",
+    "timestamp": 1194884220000,
+    "image": 'images/play_dev.jpg',
+    "title": "Google Play Terms and Policies",
+    "summary": "Developer terms and policies that apply when you distribute apps in Google Play.",
+    "keywords": [],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "title":"Google Play Policy Center",
+    "titleFriendly":"",
+    "summary":"A central resource for you to learn about Google Play policies and guidelines.",
+    "url":"https://support.google.com/googleplay/android-developer/answer/4430948",
+    "group":"",
+    "keywords": [],
+    "tags": [],
+    "image":"http://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389397_en_v0",
+    "type":"google"
+  },
+  {
+    "title":"Developer Help Center",
+    "titleFriendly":"",
+    "summary":"Complete details on getting started, publishing, troubleshooting, and more.",
+    "url":"https://support.google.com/googleplay/android-developer",
+    "group":"",
+    "keywords": [],
+    "tags": [],
+    "image":"images/play_dev.jpg",
+    "type":"google"
+  },
+  {
+    "title":"Google for Education",
+    "titleFriendly":"",
+    "summary":"Find out more about how Google can support your work with apps and tablets.",
+    "url":"http://www.google.com/edu/tablets/",
+    "group":"",
+    "keywords": [],
+    "tags": [],
+    "image":"distribute/images/gp-edu-apps-image.jpg",
+    "type":"google"
+  },
+  {
+    "title":"Keeping Your App Responsive",
+    "titleFriendly":"",
+    "summary":"This document describes how the Android system determines whether an application is not responding and provides guidelines for ensuring that your application stays responsive.",
+    "url":"training/articles/perf-anr.html",
+    "group":"",
+    "keywords": [],
+    "tags": [],
+    "image":"",
+    "type":"google"
+  },
+  {
+    "title":"Google Play Game Services",
+    "titleFriendly":"",
+    "summary":"Tools to offer a better game experience.",
+    "url":"google/play-services/games.html",
+    "group":"",
+    "keywords": [],
+    "tags": [],
+    "image":"",
+    "type":"google"
+  },
+
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "versions", "blog", "googleplay"
+    ],
+    "url": "http://android-developers.blogspot.com/",
+    "timestamp": 1004884220000,
+    "image": "images/blog.jpg",
+    "title": "Android Developers Blog",
+    "summary": "Follow the latest news on Android design, development, and distribution.",
+    "keywords": [],
+    "type": "blog",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "http://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Making Android Apps that Play Nice",
+    "summary": "Audio lifecycle and expected audio behaviors for Android apps.",
+    "keywords": [],
+    "type": "blog",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Multithreading for Performance",
+    "summary": "Ways to improve performance through multi-threading.",
+    "keywords": [],
+    "type": "blog",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "http://play.google.com/about/developer-content-policy.html",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Developer Program Policies",
+    "summary": "Guidelines acceptable content in Google Play. Please read and understand the policies before publishing.",
+    "keywords": [],
+    "type": "google",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/188189",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Rating your application content for Google Play",
+    "summary": "How to choose the appropriate content ratings level for your apps.",
+    "keywords": [],
+    "type": "support",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "http://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Google Play Featured Image Guidelines",
+    "summary": "How to create attractive, effective Featured Images for your apps.",
+    "keywords": [],
+    "type": "support",
+    "titleFriendly": ""
+  },
+{
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/113477",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Supporting your users",
+    "summary": "Options for supporting users.",
+    "keywords": [],
+    "type": "support",
+    "titleFriendly": ""
+  },   
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "guide/practices/screens_support.html#ConfigurationExamples",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Configuration examples",
+    "summary": "How to declare layouts and other resources for specific screen sizes.",
+    "keywords": [],
+    "type": "design",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "training/design-navigation/multiple-sizes.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Planning for Multiple Touchscreen Sizes",
+    "summary": "",
+    "keywords": [],
+    "type": "design",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "training/multiscreen/index.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Designing for Multiple Screens",
+    "summary": "Designing an intuitive, effective navigation for tablets and other devices.",
+    "keywords": [],
+    "type": "design",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "guide/topics/resources/providing-resources.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Providing Resources",
+    "summary": "Layouts and drawable resources for specific ranges of device screens.",
+    "keywords": [],
+    "type": "design",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "training/basics/supporting-devices/screens.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Supporting Different Screens",
+    "summary": "Optimizing the user experience for different screen sizes and densities.",
+    "keywords": [],
+    "type": "design",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "guide/topics/appwidgets/index.html#MetaData",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Adding the AppWidgetProviderInfo Metadata",
+    "summary": "How to set the height and width dimensions of a widget.",
+    "keywords": [],
+    "type": "design",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "guide/topics/manifest/uses-sdk-element.html#ApiLevels",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Android API Levels",
+    "summary": "Introduction to API levels and how they relate to compatibility.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "guide/practices/screens_support.html#DeclaringScreenSizeSupport",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Declaring screen size support",
+    "summary": "How to declare support for screen sizes in your app\'s manifest.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "guide/topics/manifest/uses-feature-element.html#testing",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Checking for hardware feature requirements",
+    "summary": "Determining an app’s hardware and software requirements.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://play.google.com/apps/publish/",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Google Play Developer Console",
+    "summary": "The tools console for publishing your app.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "http://youtu.be/SkHHPf3EdzE",
+    "timestamp": 1194884220000,
+    "image": "http://i1.ytimg.com/vi/SkHHPf3EdzE/maxresdefault.jpg",
+    "title": "Level Up Your Android Game",
+    "summary": "Learn how to take your game to the next level on Google Play.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://developers.google.com/+/mobile/android/share/interactive-post",
+    "timestamp": 1194884220000,
+    "image": 'images/google/gps-googleplus.png',
+    "title": "Sharing interactive posts to Google+ from your Android app",
+    "summary": "Interactive posts provide an easy and prominent way to allow users to share your site or app with their friends and invite them to take a specific action.",
+    "keywords": ["Interactive", "Google+"],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "http://play.google.com/about/developer-distribution-agreement.html",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Developer Distribution Agreement",
+    "summary": "Terms for distributing and selling apps and in-app products in Google Play.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/113417",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Inappropriate content in comments and applications",
+    "summary": "More details on what content is appropriate.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/legal/troubleshooter/1114905",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Removing content from Google",
+    "summary": "Find how how to request the removal of content that infringes on your trademark.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "http://play.google.com/about/developer-distribution-agreement-addendum.html",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Google Play for Education Addendum",
+    "summary": "Review the education-specific requirements.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "http://android-developers.blogspot.com/2013/03/native-rtl-support-in-android-42.html",
+    "timestamp": null,
+    "image": null,
+    "title": "Native RTL Support in Android 4.2",
+    "summary": "Blog post that explains how to support RTL in your UI.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "guide/topics/resources/string-resource.html#Plurals",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Quantity Strings (Plurals)",
+    "summary": "How to work with string plurals according to rules of grammar in a given locale.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "reference/java/util/Locale.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Locale",
+    "summary": "Determine what CLDR data or version of the Unicode spec a particular Android platform version uses.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+    {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "guide/topics/resources/string-resource.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "String Resources",
+    "summary": "Explains how to use string resources in your UI.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "distribute/tools/localization-checklist.html#strings",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Manage strings for localization",
+    "summary": "Guidance on having your strings translation ready.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "tools/publishing/publishing_overview.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "General Publishing Overview",
+    "summary": "Start here for an overview of publishing options for Android apps.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "tools/publishing/preparing.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Preparing for Release",
+    "summary": "Developer documentation on how to build the signed, release-ready APK. This process is the same for all Android apps.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "distribute/googleplay/policies/index.html",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Google Play Policies and Guidelines",
+    "summary": "An overview of Google Play policies for spam, intellectual property, and ads, with examples of common problems.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/topic/2364761",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Policy and Best Practices",
+    "summary": "Help Center document describing various content policies and processes.",
+    "keywords": [],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "google/play/expansion-files.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "APK Expansion Files",
+    "summary": "Developer documentation describing APK Expansion Files and how to support them in your app.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "tools/help/proguard.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "ProGuard",
+    "summary": "Developer documentation describing how to use ProGuard to shrink, optimize, and obfuscate your code prior to release.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "title":"Dashboards",
+    "titleFriendly":"",
+    "summary":"This page provides information about the relative number of devices that share a certain characteristic, such as Android version or screen size. This information may help you prioritize efforts for supporting different devices by revealing which devices…",
+    "url":"about/dashboards/index.html",
+    "group":"",
+    "keywords": ["android","dashboard","platforms","versions"],
+    "tags": ["#ecosystem","#versions","#whatsnew"],
+    "image":"http://chart.googleapis.com/chart?chl=GL%201.1%20only%7CGL%202.0%7CGL%203.0&chf=bg%2Cs%2C00000000&chd=t%3A0.1%2C93.5%2C6.4&chco=c4df9b%2C6fad0c&chs=400x250&cht=p",
+    "lang":"en",
+    "type":"about"
+  }, 
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://developers.google.com/wallet/instant-buy/",
+    "timestamp": 1194884220000,
+    "image": "distribute/images/payment-method.jpg",
+    "title": "Google Wallet Instant Buy APIs",
+    "summary": "Developer documentation describing Instant Buy and how to support it in your apps.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/1169947",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Selling Apps in Multiple Currencies",
+    "summary": "Help Center document describing how pricing works in Google Play.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/138412",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Prices and supported currencies",
+    "summary": "Help Center document listing supported currencies for pricing your apps.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/112622",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Transaction Fees",
+    "summary": "Help Center document describing transaction fees for priced apps and in-app products.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/138000",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Specifying tax rates",
+    "summary": "Help Center document describing how to set tax rates for different countries.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "guide/topics/resources/localization.html",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Localizing with Resources",
+    "summary": "Developer guide to localizing resources in your app.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/113475",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Category types",
+    "summary": "Help Center document listing available categories for apps.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/113476",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Updates",
+    "summary": "Requirements for app updates in Google Play.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/1153479",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "In-app Billing",
+    "summary": "Help Center document describing how to correctly set up In-app Billing.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "#gpfe",
+      "#googleplay"
+    ],
+    "url": "http://youtu.be/vzvpcEffvaE",
+    "timestamp": 1383243492000,
+    "image": "http://i1.ytimg.com/vi/vzvpcEffvaE/maxresdefault.jpg",
+    "title": "Introducing Google Play for Education",
+    "summary": "Google Play for Education is a destination where schools can find great, teacher-approved, educational apps and videos on Play Store. Teachers can filter content by subject matter, grade and other criteria. Bulk purchase and instant distribution let educators bring your apps directly to classrooms and schools.",
+    "keywords": [],
+    "type": "youtube",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "#engagement",
+    ],
+    "url": "http://www.youtube.com/yt/dev/",
+    "timestamp": 1383243492000,
+    "image": "http://www.youtube.com/yt/dev/media/images/yt-dev-home-hero.jpg",
+    "title": "YouTube for Developers",
+    "summary": "The YouTube APIs and Tools enable you to integrate YouTube's video content and functionality into your website, app, or device.",
+    "keywords": [],
+    "type": "youtube",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "#engagement",
+    ],
+    "url": "https://developers.google.com/app-indexing/",
+    "timestamp": 1383243492000,
+    "image": "https://developers.google.com/app-indexing/images/allthecooks_srp.png",
+    "title": "Sign Up for App Indexing",
+    "summary": "Google is working with app developers and webmasters to index the content of apps and relate them to websites. When relevant, Google Search results on Android will include deep links to apps.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "#gcm",
+    ],
+    "url": "http://www.youtube.com/watch?v=y76rjidm8cU",
+    "timestamp": 1383243492000,
+    "image": "http://1.bp.blogspot.com/-IF-1-1kA0sg/UYwTidxdi3I/AAAAAAAAAEU/ellLeQ-E1vs/s800/google-io-lockup-2.png",
+    "title": "Google Cloud Messaging at I/O 2013",
+    "summary": "Google Cloud Messaging allows your services to efficiently send data to applications on Android devices. See what's new, and learn how to use GCM to make your apps more efficient.",
+    "keywords": ["gcm"],
+    "type": "youtube",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "#googleplus",
+    ],
+    "url": "https://developers.google.com/+/mobile/android/people",
+    "timestamp": 1383243492000,
+    "image": "images/google/gps-googleplus.png",
+    "title": "Sign Up for App Indexing",
+    "summary": "After you let users sign in with Google, you can access their age range, language, public profile information, and people that they have circled.",
+    "keywords": ["googleplus"],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "#gcm",
+    ],
+    "url": "http://developer.chrome.com/apps/cloudMessagingV2",
+    "timestamp": 1383243492000,
+    "image": "images/kk-chromium-icon.png",
+    "title": "Google Cloud Messaging for Chrome",
+    "summary": "Google Cloud Messaging for Chrome (GCM) is a service for signed-in Chrome users that helps developers send message data from servers to their Chrome apps and extensions.",
+    "keywords": ["gcm"],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "#sdkupdates"
+    ],
+    "url": "http://android-developers.blogspot.com/2013/07/making-beautiful-android-app-icons.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Make Beautiful Android App Icons",
+    "summary": "Follow these in-depth launcher icon tips on the Android Developers blog.",
+    "keywords": [],
+    "type": "blog",
+    "titleFriendly": ""
+  },
+     {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "#sdkupdates"
+    ],
+    "url": "http://android-developers.blogspot.com/2012/12/localize-your-promotional-graphics-on.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Localize Your Promotional Graphics",
+    "summary": "Learn how to capitalise on international audiences.",
+    "keywords": [],
+    "type": "blog",
+    "titleFriendly": ""
+  },
+   {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "#sdkupdates"
+    ],
+    "url": "http://android-developers.blogspot.com/2013/10/making-your-app-content-more-accessible.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Make your App Content more Accessible with App Linking",
+    "summary": "About using search and deep linking to get more users.",
+    "keywords": [],
+    "type": "blog",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://developers.google.com/+/mobile/android/share/interactive-post",
+    "timestamp": 1194884220000,
+    "image": 'images/google/gps-googleplus.png',
+    "title": "Sharing interactive posts to Google+ from your Android app",
+    "summary": "Interactive posts provide an easy and prominent way to allow users to share your site or app with their friends and invite them to take a specific action.",
+    "keywords": ["Interactive", "Google+"],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/2528691",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "How to add multiple user accounts to your Developer Console for testing and more.",
+    "summary": "",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://developers.google.com/+/mobile/android/share/deep-link",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Adding deep linking to Google+ posts shared from your Android app",
+    "summary": "",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "google/play/licensing/index.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Application Licensing",
+    "summary": "Information on the features of Google Play to protect your apps’ licences.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "design/style/writing.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Writing Style",
+    "summary": "Android Design guidelines for voice and style in your UI.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "http://en.wikipedia.org/wiki/XLIFF",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "XML Localisation Interchange File Format (XLIFF)",
+    "summary": "Background information on XLIFF.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+    {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/1078870",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Graphic Assets for your Application",
+    "summary": "Details about the graphics you can add to your product listing.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/payments/answer/2741495",
+    "timestamp": null,
+    "image": null,
+    "title": "Issuing Refunds",
+    "summary": "Help Center document describing how to issue refunds.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "http://android-developers.blogspot.com/2013/11/bring-your-apps-into-classroom-with.html",
+    "timestamp": null,
+    "image": "distribute/images/gp-edu-apps-image.jpg",
+    "title": "Google play for education",
+    "summary": " ",
+    "keywords": [],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["localization", "pricing", "developer support"],
+    "url": "https://support.google.com/googleplay/android-developer/table/3541286",
+    "timestamp": null,
+    "image": "images/play_dev.jpg",
+    "title": "Supported locations for distributing your apps in Google Play",
+    "summary": "Countries and regions where you can distribute your app in Google Play.",
+    "keywords": [],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["games", "localization", "quality"],
+    "url": "http://www.youtube.com/watch?v=SkHHPf3EdzE",
+    "timestamp": null,
+    "image": "https://developers.google.com/apps/images/io_2013/google-io-logo.png",
+    "title": "Level Up Your Android Game",
+    "summary": "Learn how to take your game to the next level in this Google I/O session.",
+    "keywords": [],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["support"],
+    "url": "https://support.google.com/groups/answer/46601",
+    "timestamp": null,
+    "image": null,
+    "title": "Google Groups",
+    "summary": "Create a group for your community.",
+    "keywords": [],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["support"],
+    "url": "https://support.google.com/plus/topic/2888488",
+    "timestamp": null,
+    "image": null,
+    "title": "Google+ Communities",
+    "summary": "Host a Google+ community for testers or users.",
+    "keywords": [],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["monetize", "ads"],
+    "url": "http://www.google.com/ads/admob/#subid=us-en-et-dac",
+    "timestamp": null,
+    "image": "distribute/images/advertising.png",
+    "title": "AdMob for Android",
+    "summary": "Make money by connecting with over a million Google advertisers all over the world, so your revenue scales with your app.",
+    "keywords": ["ads"],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["monetize", "ads"],
+    "url": "http://www.google.com/doubleclick/publishers/small-business/index.html",
+    "timestamp": null,
+    "image": "http://www.google.com/doubleclick/publishers/small-business/images/define_ad.png",
+    "title": "DoubleClick for Publishers",
+    "summary": "A free ad management solution that helps growing publishers sell, schedule, deliver, and measure all of their digital ad inventory.",
+    "keywords": ["ads"],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["monetize", "ads"],
+    "url": "http://support.google.com/googleplay/android-developer/topic/2985714",
+    "timestamp": null,
+    "image": "http://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389397_en_v0",
+    "title": "Policy Center: Ads",
+    "summary": "Introduction to ads and system interference policies in Google Play",
+    "keywords": ["ads"],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["monetize", "giftcards"],
+    "url": "https://play.google.com/about/giftcards/",
+    "timestamp": null,
+    "image": "images/gp-balance.png",
+    "title": "Google Play Gift Cards",
+    "summary": "Buy Google Play gift cards online or at a variety of retail stores.",
+    "keywords": ["gift card"],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["monetize", "paymentmethods"],
+    "url": "https://support.google.com/googleplay/answer/2651410",
+    "timestamp": null,
+    "image": "images/play_dev.jpg",
+    "title": "Google Play Accepted Payment Methods",
+    "summary": "Support details on the payment methods supported in Google Play.",
+    "keywords": ["gift card"],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["plus", "social"],
+    "url": "https://plus.google.com/+AndroidDevelopers/",
+    "timestamp": null,
+    "image": "images/plus.jpg",
+    "title": "+Android Developers",
+    "summary": "Sharing news, ideas, and techniques for success.",
+    "keywords": ["+AndroidDevelopers"],
+    "type": "Google+",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["plus", "social"],
+    "url": "http://plus.google.com/+GooglePlay",
+    "timestamp": null,
+    "image": "https://lh4.googleusercontent.com/-IKezweZlcXI/AAAAAAAAAAI/AAAAAAABOvg/uK8Z0jekVE4/s120-c/photo.jpg",
+    "title": "+Google Play",
+    "summary": "News and discussion about Google Play, apps, and other content in Google+.",
+    "keywords": ["+GooglePlay"],
+    "type": "Google+",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["support", "android"],
+    "url": "support.html",
+    "timestamp": null,
+    "image": null,
+    "title": "Developer Support",
+    "summary": "Links to community and support resources for Android developers.",
+    "keywords": ["support"],
+    "type": "Google+",
+    "titleFriendly": ""
+  },
+]); 
\ No newline at end of file
diff --git a/docs/html/jd_tag_helpers.js b/docs/html/jd_tag_helpers.js
new file mode 100644
index 0000000..ca01386
--- /dev/null
+++ b/docs/html/jd_tag_helpers.js
@@ -0,0 +1,110 @@
+function mergeArrays() {
+  var arr = arguments[0] || [];
+  for (var i = 1; i < arguments.length; i++) {
+    arr = arr.concat(arguments[i]);
+  }
+  return arr;
+}
+
+var ALL_RESOURCES = mergeArrays(
+  DESIGN_RESOURCES,
+  DISTRIBUTE_RESOURCES,
+  GOOGLE_RESOURCES,
+  GUIDE_RESOURCES,
+  SAMPLES_RESOURCES,
+  TOOLS_RESOURCES,
+  TRAINING_RESOURCES,
+  YOUTUBE_RESOURCES,
+  BLOGGER_RESOURCES
+);
+
+for (var i = 0; i < ALL_RESOURCES.length; i++) {
+  ALL_RESOURCES[i].index = i;
+}
+
+function mergeMaps() {
+  var allRes = {};
+  var offset = 0;
+
+  for (var i = 0; i < arguments.length; i++) {
+    var r = arguments[i];
+    for (var tag in r.map) {
+      allRes[tag] = allRes[tag] || [];
+      allRes[tag] = allRes[tag].concat(r.map[tag].map(function(i){ return ALL_RESOURCES[i + offset]; }));
+    }
+    offset += r.arr.length;
+  }
+
+  return allRes;
+}
+
+function setFromArray(arr) {
+  arr = arr || [];
+  var set = {};
+  for (var i = 0; i < arr.length; i++) {
+    set[arr[i]] = true;
+  }
+  return set;
+}
+
+function buildResourceLookupMap(resourceDict) {
+  var map = {};
+  for (var key in resourceDict) {
+    var dictForKey = {};
+    var srcArr = resourceDict[key];
+    for (var i = 0; i < srcArr.length; i++) {
+      dictForKey[srcArr[i].index] = true;
+    }
+    map[key] = dictForKey;
+  }
+  return map;
+}
+
+// Type lookups
+
+var ALL_RESOURCES_BY_TYPE = {
+  'design': DESIGN_RESOURCES,
+  'distribute': DISTRIBUTE_RESOURCES,
+  'google': GOOGLE_RESOURCES,
+  'guide': GUIDE_RESOURCES,
+  'samples': SAMPLES_RESOURCES,
+  'tools': TOOLS_RESOURCES,
+  'training': TRAINING_RESOURCES,
+  'youtube': YOUTUBE_RESOURCES,
+  'blog': BLOGGER_RESOURCES
+};
+var IS_RESOURCE_OF_TYPE = buildResourceLookupMap(ALL_RESOURCES_BY_TYPE);
+
+// Tag lookups
+
+var ALL_RESOURCES_BY_TAG = mergeMaps(
+  {map:DESIGN_BY_TAG,arr:DESIGN_RESOURCES},
+  {map:DISTRIBUTE_BY_TAG,arr:DISTRIBUTE_RESOURCES},
+  {map:GOOGLE_BY_TAG,arr:GOOGLE_RESOURCES},
+  {map:GUIDE_BY_TAG,arr:GUIDE_RESOURCES},
+  {map:SAMPLES_BY_TAG,arr:SAMPLES_RESOURCES},
+  {map:TOOLS_BY_TAG,arr:TOOLS_RESOURCES},
+  {map:TRAINING_BY_TAG,arr:TRAINING_RESOURCES},
+  {map:YOUTUBE_BY_TAG,arr:YOUTUBE_RESOURCES},
+  {map:BLOGGER_BY_TAG,arr:BLOGGER_RESOURCES}
+);
+var IS_RESOURCE_TAGGED = buildResourceLookupMap(ALL_RESOURCES_BY_TAG);
+
+// URL and language lookups
+
+var ALL_RESOURCES_BY_URL = {};
+var ALL_RESOURCES_BY_LANG = {};
+
+for (var i = 0; i < ALL_RESOURCES.length; i++) {
+  var res = ALL_RESOURCES[i];
+  var lang = res.lang;
+  if (lang) {
+    ALL_RESOURCES_BY_LANG[lang] = ALL_RESOURCES_BY_LANG[lang] || [];
+    ALL_RESOURCES_BY_LANG[lang].push(res);
+  }
+  var url = res.url;
+  if (url) {
+    ALL_RESOURCES_BY_URL[url] = res;
+  }
+}
+var IS_RESOURCE_IN_LANG = buildResourceLookupMap(ALL_RESOURCES_BY_LANG);
\ No newline at end of file
diff --git a/docs/html/legal.jd b/docs/html/legal.jd
index aaa3c39..c6143da 100644
--- a/docs/html/legal.jd
+++ b/docs/html/legal.jd
@@ -1,4 +1,5 @@
 page.title=Legal Notice
+page.type=about
 fullpage=1
 @jd:body
 
@@ -39,7 +40,7 @@
 use of it must be attributed as such.</p>
 
 <p>For more information about Android brands, see the <a
-href="{@docRoot}distribute/googleplay/promote/brand.html">Brand Guidelines</a>.</p>
+href="{@docRoot}distribute/tools/promote/brand.html">Brand Guidelines</a>.</p>
 
 <p>All other trademarks are the property of their respective owners.</p>
 
diff --git a/docs/html/license.jd b/docs/html/license.jd
index b98c912..0f671e2 100644
--- a/docs/html/license.jd
+++ b/docs/html/license.jd
@@ -1,4 +1,5 @@
 page.title=Content License
+page.type=about
 fullpage=1
 excludeFromSuggestions=true
 @jd:body
@@ -68,7 +69,7 @@
 style="margin:0;padding:0 2px;vertical-align:baseline" /> stylized typeface logo) are not included
 in the license.
 Please see <a
-href="{@docRoot}distribute/googleplay/promote/brand.html">Brand Guidelines</a> for
+href="{@docRoot}distribute/tools/promote/brand.html">Brand Guidelines</a> for
 information about this usage. </li>
 
 <li>In some cases, a page may include content, such as an image, that is not 
diff --git a/docs/html/reference/android/preview/support/package-summary.html b/docs/html/reference/android/preview/support/package-summary.html
index d367f87..2f50871 100644
--- a/docs/html/reference/android/preview/support/package-summary.html
+++ b/docs/html/reference/android/preview/support/package-summary.html
@@ -82,13 +82,6 @@
 
 
 
-
-
-
-
-
-
-
 <html>
 <head>
 
@@ -101,13 +94,15 @@
 
 <!-- STYLESHEETS -->
 <link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+  title="roboto">
 <link href="/assets/css/default.css" rel="stylesheet" type="text/css">
 
 
 
 <!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
 <script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
 <script type="text/javascript">
   var toRoot = "/";
@@ -131,7 +126,7 @@
 
 
 <body class="gc-documentation 
-  develop">
+  preview">
   <div id="doc-api-level" class="" style="display:none"></div>
   <a name="top"></a>
 
@@ -139,31 +134,30 @@
   
 <a name="top"></a>
 
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
+<!-- Header -->
+<div id="header-wrapper">
+  <div id="header">
+    <div class="wrap" id="header-wrap">
+      <div class="col_3 logo wear-logo">
+        <a href="/wear/index.html">
+          <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+        </a>
+      </div>
+      <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
 
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
+      
+      
+<div class="menu-container">
+  <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
   <div class="morehover" id="moremenu">
     <div class="top"></div>
     <div class="mid">
       <div class="header">Links</div>
       <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+        <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
         <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
         <li><a href="/about/index.html">About Android</a></li>
       </ul>
@@ -173,16 +167,32 @@
         <li class="active"><a>Android Developers</a></li>
         <li><a href="http://source.android.com">Android Open Source Project</a></li>
       </ul>
-      
-      
-      
-      
 
-
+      
+      
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      
+      
       <br class="clearfix" />
-    </div><!-- end mid -->
+    </div><!-- end 'mid' -->
     <div class="bottom"></div>
-  </div><!-- end morehover -->
+  </div><!-- end 'moremenu' -->
 
   <div class="search" id="search-container">
     <div class="search-inner">
@@ -190,16 +200,16 @@
       <div class="left"></div>
       <form onsubmit="return submit_search()">
         <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
+          onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+          onkeydown="return search_changed(event, true, '/')"
+          onkeyup="return search_changed(event, false, '/')" />
       </form>
       <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
+      <a class="close hide">close</a>
+      <div class="left"></div>
+      <div class="right"></div>
+    </div><!-- end search-inner -->
+  </div><!-- end search-container -->
 
   <div class="search_filtered_wrapper reference">
     <div class="suggest-card reference no-display">
@@ -228,30 +238,37 @@
       <ul class="search_filtered">
       </ul>
     </div>
-  </div><!-- end search_filtered_wrapper -->
-
   </div>
-  <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
 
 
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
+    </div><!-- end header-wrap -->
+  </div><!-- /Header -->
 
 
   <div id="searchResults" class="wrap" style="display:none;">
           <h2 id="searchTitle">Results</h2>
           <div id="leftSearchControl" class="search-control">Loading...</div>
   </div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+  <div>
+    <a class="logo" href="#top"></a>
+    <a class="top" href="#top"></a>
+    <ul class="breadcrumb">
+      
+      <li class="current">Preview Notifications Reference</li>
+    </ul>
+  </div>
+</div>
 
   
 
-  
 
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <ul id="nav">
 
@@ -328,7 +345,7 @@
 
 </ul>
 
-        
+
 
       </div>
     </div> <!-- end side-nav -->
@@ -362,12 +379,6 @@
 
 
 
-
-  
-
-
-
-
     <h2>android.preview.support.v4.app</h2>
     <div class="jd-sumtable">
     
@@ -418,14 +429,6 @@
   
 
 
-
-
-
-
-
-
-
-
   
 
 
diff --git a/docs/html/reference/android/preview/support/v4/app/NotificationManagerCompat.html b/docs/html/reference/android/preview/support/v4/app/NotificationManagerCompat.html
index 6375d9a..8322ab2 100644
--- a/docs/html/reference/android/preview/support/v4/app/NotificationManagerCompat.html
+++ b/docs/html/reference/android/preview/support/v4/app/NotificationManagerCompat.html
@@ -82,13 +82,6 @@
 
 
 
-
-
-
-
-
-
-
 <html>
 <head>
 
@@ -101,13 +94,15 @@
 
 <!-- STYLESHEETS -->
 <link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+  title="roboto">
 <link href="/assets/css/default.css" rel="stylesheet" type="text/css">
 
 
 
 <!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
 <script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
 <script type="text/javascript">
   var toRoot = "/";
@@ -130,7 +125,7 @@
 </head>
 
 <body class="gc-documentation 
-  develop" itemscope itemtype="http://schema.org/Article">
+  preview" itemscope itemtype="http://schema.org/Article">
   <div id="doc-api-level" class="" style="display:none"></div>
   <a name="top"></a>
 
@@ -138,31 +133,30 @@
   
 <a name="top"></a>
 
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
+<!-- Header -->
+<div id="header-wrapper">
+  <div id="header">
+    <div class="wrap" id="header-wrap">
+      <div class="col_3 logo wear-logo">
+        <a href="/wear/index.html">
+          <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+        </a>
+      </div>
+      <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
 
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
+      
+      
+<div class="menu-container">
+  <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
   <div class="morehover" id="moremenu">
     <div class="top"></div>
     <div class="mid">
       <div class="header">Links</div>
       <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+        <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
         <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
         <li><a href="/about/index.html">About Android</a></li>
       </ul>
@@ -172,16 +166,32 @@
         <li class="active"><a>Android Developers</a></li>
         <li><a href="http://source.android.com">Android Open Source Project</a></li>
       </ul>
-      
-      
-      
-      
 
-
+      
+      
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      
+      
       <br class="clearfix" />
-    </div><!-- end mid -->
+    </div><!-- end 'mid' -->
     <div class="bottom"></div>
-  </div><!-- end morehover -->
+  </div><!-- end 'moremenu' -->
 
   <div class="search" id="search-container">
     <div class="search-inner">
@@ -189,16 +199,16 @@
       <div class="left"></div>
       <form onsubmit="return submit_search()">
         <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
+          onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+          onkeydown="return search_changed(event, true, '/')"
+          onkeyup="return search_changed(event, false, '/')" />
       </form>
       <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
+      <a class="close hide">close</a>
+      <div class="left"></div>
+      <div class="right"></div>
+    </div><!-- end search-inner -->
+  </div><!-- end search-container -->
 
   <div class="search_filtered_wrapper reference">
     <div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
       <ul class="search_filtered">
       </ul>
     </div>
-  </div><!-- end search_filtered_wrapper -->
-
   </div>
-  <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
 
 
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
+    </div><!-- end header-wrap -->
+  </div><!-- /Header -->
 
 
   <div id="searchResults" class="wrap" style="display:none;">
           <h2 id="searchTitle">Results</h2>
           <div id="leftSearchControl" class="search-control">Loading...</div>
   </div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+  <div>
+    <a class="logo" href="#top"></a>
+    <a class="top" href="#top"></a>
+    <ul class="breadcrumb">
+      
+      <li class="current">NotificationManagerCompat</li>
+    </ul>
+  </div>
+</div>
 
   
 
-  
 
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <ul id="nav">
 
@@ -327,7 +344,7 @@
 
 </ul>
 
-        
+
 
       </div>
     </div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
 
 
 
+
 <div class="col-12"  id="doc-col">
 
 <div id="api-info-block">
diff --git a/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html b/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html
index 6fbf8b6..77807e4 100644
--- a/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html
+++ b/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html
@@ -82,13 +82,6 @@
 
 
 
-
-
-
-
-
-
-
 <html>
 <head>
 
@@ -101,13 +94,15 @@
 
 <!-- STYLESHEETS -->
 <link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+  title="roboto">
 <link href="/assets/css/default.css" rel="stylesheet" type="text/css">
 
 
 
 <!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
 <script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
 <script type="text/javascript">
   var toRoot = "/";
@@ -130,7 +125,7 @@
 </head>
 
 <body class="gc-documentation 
-  develop" itemscope itemtype="http://schema.org/Article">
+  preview" itemscope itemtype="http://schema.org/Article">
   <div id="doc-api-level" class="" style="display:none"></div>
   <a name="top"></a>
 
@@ -138,31 +133,30 @@
   
 <a name="top"></a>
 
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
+<!-- Header -->
+<div id="header-wrapper">
+  <div id="header">
+    <div class="wrap" id="header-wrap">
+      <div class="col_3 logo wear-logo">
+        <a href="/wear/index.html">
+          <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+        </a>
+      </div>
+      <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
 
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
+      
+      
+<div class="menu-container">
+  <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
   <div class="morehover" id="moremenu">
     <div class="top"></div>
     <div class="mid">
       <div class="header">Links</div>
       <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+        <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
         <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
         <li><a href="/about/index.html">About Android</a></li>
       </ul>
@@ -172,16 +166,32 @@
         <li class="active"><a>Android Developers</a></li>
         <li><a href="http://source.android.com">Android Open Source Project</a></li>
       </ul>
-      
-      
-      
-      
 
-
+      
+      
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      
+      
       <br class="clearfix" />
-    </div><!-- end mid -->
+    </div><!-- end 'mid' -->
     <div class="bottom"></div>
-  </div><!-- end morehover -->
+  </div><!-- end 'moremenu' -->
 
   <div class="search" id="search-container">
     <div class="search-inner">
@@ -189,16 +199,16 @@
       <div class="left"></div>
       <form onsubmit="return submit_search()">
         <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
+          onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+          onkeydown="return search_changed(event, true, '/')"
+          onkeyup="return search_changed(event, false, '/')" />
       </form>
       <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
+      <a class="close hide">close</a>
+      <div class="left"></div>
+      <div class="right"></div>
+    </div><!-- end search-inner -->
+  </div><!-- end search-container -->
 
   <div class="search_filtered_wrapper reference">
     <div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
       <ul class="search_filtered">
       </ul>
     </div>
-  </div><!-- end search_filtered_wrapper -->
-
   </div>
-  <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
 
 
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
+    </div><!-- end header-wrap -->
+  </div><!-- /Header -->
 
 
   <div id="searchResults" class="wrap" style="display:none;">
           <h2 id="searchTitle">Results</h2>
           <div id="leftSearchControl" class="search-control">Loading...</div>
   </div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+  <div>
+    <a class="logo" href="#top"></a>
+    <a class="top" href="#top"></a>
+    <ul class="breadcrumb">
+      
+      <li class="current">RemoteInput.Builder</li>
+    </ul>
+  </div>
+</div>
 
   
 
-  
 
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <ul id="nav">
 
@@ -327,7 +344,7 @@
 
 </ul>
 
-        
+
 
       </div>
     </div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
 
 
 
+
 <div class="col-12"  id="doc-col">
 
 <div id="api-info-block">
diff --git a/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.html b/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.html
index 0e1cebe..43fd36e 100644
--- a/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.html
+++ b/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.html
@@ -82,13 +82,6 @@
 
 
 
-
-
-
-
-
-
-
 <html>
 <head>
 
@@ -101,13 +94,15 @@
 
 <!-- STYLESHEETS -->
 <link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+  title="roboto">
 <link href="/assets/css/default.css" rel="stylesheet" type="text/css">
 
 
 
 <!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
 <script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
 <script type="text/javascript">
   var toRoot = "/";
@@ -130,7 +125,7 @@
 </head>
 
 <body class="gc-documentation 
-  develop" itemscope itemtype="http://schema.org/Article">
+  preview" itemscope itemtype="http://schema.org/Article">
   <div id="doc-api-level" class="" style="display:none"></div>
   <a name="top"></a>
 
@@ -138,31 +133,30 @@
   
 <a name="top"></a>
 
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
+<!-- Header -->
+<div id="header-wrapper">
+  <div id="header">
+    <div class="wrap" id="header-wrap">
+      <div class="col_3 logo wear-logo">
+        <a href="/wear/index.html">
+          <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+        </a>
+      </div>
+      <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
 
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
+      
+      
+<div class="menu-container">
+  <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
   <div class="morehover" id="moremenu">
     <div class="top"></div>
     <div class="mid">
       <div class="header">Links</div>
       <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+        <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
         <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
         <li><a href="/about/index.html">About Android</a></li>
       </ul>
@@ -172,16 +166,32 @@
         <li class="active"><a>Android Developers</a></li>
         <li><a href="http://source.android.com">Android Open Source Project</a></li>
       </ul>
-      
-      
-      
-      
 
-
+      
+      
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      
+      
       <br class="clearfix" />
-    </div><!-- end mid -->
+    </div><!-- end 'mid' -->
     <div class="bottom"></div>
-  </div><!-- end morehover -->
+  </div><!-- end 'moremenu' -->
 
   <div class="search" id="search-container">
     <div class="search-inner">
@@ -189,16 +199,16 @@
       <div class="left"></div>
       <form onsubmit="return submit_search()">
         <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
+          onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+          onkeydown="return search_changed(event, true, '/')"
+          onkeyup="return search_changed(event, false, '/')" />
       </form>
       <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
+      <a class="close hide">close</a>
+      <div class="left"></div>
+      <div class="right"></div>
+    </div><!-- end search-inner -->
+  </div><!-- end search-container -->
 
   <div class="search_filtered_wrapper reference">
     <div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
       <ul class="search_filtered">
       </ul>
     </div>
-  </div><!-- end search_filtered_wrapper -->
-
   </div>
-  <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
 
 
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
+    </div><!-- end header-wrap -->
+  </div><!-- /Header -->
 
 
   <div id="searchResults" class="wrap" style="display:none;">
           <h2 id="searchTitle">Results</h2>
           <div id="leftSearchControl" class="search-control">Loading...</div>
   </div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+  <div>
+    <a class="logo" href="#top"></a>
+    <a class="top" href="#top"></a>
+    <ul class="breadcrumb">
+      
+      <li class="current">RemoteInput</li>
+    </ul>
+  </div>
+</div>
 
   
 
-  
 
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <ul id="nav">
 
@@ -327,7 +344,7 @@
 
 </ul>
 
-        
+
 
       </div>
     </div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
 
 
 
+
 <div class="col-12"  id="doc-col">
 
 <div id="api-info-block">
diff --git a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html
index f27d406..9592e27 100644
--- a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html
+++ b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html
@@ -82,13 +82,6 @@
 
 
 
-
-
-
-
-
-
-
 <html>
 <head>
 
@@ -101,13 +94,15 @@
 
 <!-- STYLESHEETS -->
 <link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+  title="roboto">
 <link href="/assets/css/default.css" rel="stylesheet" type="text/css">
 
 
 
 <!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
 <script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
 <script type="text/javascript">
   var toRoot = "/";
@@ -130,7 +125,7 @@
 </head>
 
 <body class="gc-documentation 
-  develop" itemscope itemtype="http://schema.org/Article">
+  preview" itemscope itemtype="http://schema.org/Article">
   <div id="doc-api-level" class="" style="display:none"></div>
   <a name="top"></a>
 
@@ -138,31 +133,30 @@
   
 <a name="top"></a>
 
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
+<!-- Header -->
+<div id="header-wrapper">
+  <div id="header">
+    <div class="wrap" id="header-wrap">
+      <div class="col_3 logo wear-logo">
+        <a href="/wear/index.html">
+          <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+        </a>
+      </div>
+      <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
 
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
+      
+      
+<div class="menu-container">
+  <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
   <div class="morehover" id="moremenu">
     <div class="top"></div>
     <div class="mid">
       <div class="header">Links</div>
       <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+        <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
         <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
         <li><a href="/about/index.html">About Android</a></li>
       </ul>
@@ -172,16 +166,32 @@
         <li class="active"><a>Android Developers</a></li>
         <li><a href="http://source.android.com">Android Open Source Project</a></li>
       </ul>
-      
-      
-      
-      
 
-
+      
+      
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      
+      
       <br class="clearfix" />
-    </div><!-- end mid -->
+    </div><!-- end 'mid' -->
     <div class="bottom"></div>
-  </div><!-- end morehover -->
+  </div><!-- end 'moremenu' -->
 
   <div class="search" id="search-container">
     <div class="search-inner">
@@ -189,16 +199,16 @@
       <div class="left"></div>
       <form onsubmit="return submit_search()">
         <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
+          onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+          onkeydown="return search_changed(event, true, '/')"
+          onkeyup="return search_changed(event, false, '/')" />
       </form>
       <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
+      <a class="close hide">close</a>
+      <div class="left"></div>
+      <div class="right"></div>
+    </div><!-- end search-inner -->
+  </div><!-- end search-container -->
 
   <div class="search_filtered_wrapper reference">
     <div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
       <ul class="search_filtered">
       </ul>
     </div>
-  </div><!-- end search_filtered_wrapper -->
-
   </div>
-  <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
 
 
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
+    </div><!-- end header-wrap -->
+  </div><!-- /Header -->
 
 
   <div id="searchResults" class="wrap" style="display:none;">
           <h2 id="searchTitle">Results</h2>
           <div id="leftSearchControl" class="search-control">Loading...</div>
   </div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+  <div>
+    <a class="logo" href="#top"></a>
+    <a class="top" href="#top"></a>
+    <ul class="breadcrumb">
+      
+      <li class="current">WearableNotifications.Action.Builder</li>
+    </ul>
+  </div>
+</div>
 
   
 
-  
 
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <ul id="nav">
 
@@ -327,7 +344,7 @@
 
 </ul>
 
-        
+
 
       </div>
     </div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
 
 
 
+
 <div class="col-12"  id="doc-col">
 
 <div id="api-info-block">
diff --git a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html
index ff9c904..8073fa8 100644
--- a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html
+++ b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html
@@ -82,13 +82,6 @@
 
 
 
-
-
-
-
-
-
-
 <html>
 <head>
 
@@ -101,13 +94,15 @@
 
 <!-- STYLESHEETS -->
 <link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+  title="roboto">
 <link href="/assets/css/default.css" rel="stylesheet" type="text/css">
 
 
 
 <!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
 <script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
 <script type="text/javascript">
   var toRoot = "/";
@@ -130,7 +125,7 @@
 </head>
 
 <body class="gc-documentation 
-  develop" itemscope itemtype="http://schema.org/Article">
+  preview" itemscope itemtype="http://schema.org/Article">
   <div id="doc-api-level" class="" style="display:none"></div>
   <a name="top"></a>
 
@@ -138,31 +133,30 @@
   
 <a name="top"></a>
 
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
+<!-- Header -->
+<div id="header-wrapper">
+  <div id="header">
+    <div class="wrap" id="header-wrap">
+      <div class="col_3 logo wear-logo">
+        <a href="/wear/index.html">
+          <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+        </a>
+      </div>
+      <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
 
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
+      
+      
+<div class="menu-container">
+  <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
   <div class="morehover" id="moremenu">
     <div class="top"></div>
     <div class="mid">
       <div class="header">Links</div>
       <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+        <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
         <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
         <li><a href="/about/index.html">About Android</a></li>
       </ul>
@@ -172,16 +166,32 @@
         <li class="active"><a>Android Developers</a></li>
         <li><a href="http://source.android.com">Android Open Source Project</a></li>
       </ul>
-      
-      
-      
-      
 
-
+      
+      
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      
+      
       <br class="clearfix" />
-    </div><!-- end mid -->
+    </div><!-- end 'mid' -->
     <div class="bottom"></div>
-  </div><!-- end morehover -->
+  </div><!-- end 'moremenu' -->
 
   <div class="search" id="search-container">
     <div class="search-inner">
@@ -189,16 +199,16 @@
       <div class="left"></div>
       <form onsubmit="return submit_search()">
         <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
+          onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+          onkeydown="return search_changed(event, true, '/')"
+          onkeyup="return search_changed(event, false, '/')" />
       </form>
       <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
+      <a class="close hide">close</a>
+      <div class="left"></div>
+      <div class="right"></div>
+    </div><!-- end search-inner -->
+  </div><!-- end search-container -->
 
   <div class="search_filtered_wrapper reference">
     <div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
       <ul class="search_filtered">
       </ul>
     </div>
-  </div><!-- end search_filtered_wrapper -->
-
   </div>
-  <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
 
 
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
+    </div><!-- end header-wrap -->
+  </div><!-- /Header -->
 
 
   <div id="searchResults" class="wrap" style="display:none;">
           <h2 id="searchTitle">Results</h2>
           <div id="leftSearchControl" class="search-control">Loading...</div>
   </div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+  <div>
+    <a class="logo" href="#top"></a>
+    <a class="top" href="#top"></a>
+    <ul class="breadcrumb">
+      
+      <li class="current">WearableNotifications.Action</li>
+    </ul>
+  </div>
+</div>
 
   
 
-  
 
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <ul id="nav">
 
@@ -327,7 +344,7 @@
 
 </ul>
 
-        
+
 
       </div>
     </div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
 
 
 
+
 <div class="col-12"  id="doc-col">
 
 <div id="api-info-block">
diff --git a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html
index d6ec260..15d3303 100644
--- a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html
+++ b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html
@@ -82,13 +82,6 @@
 
 
 
-
-
-
-
-
-
-
 <html>
 <head>
 
@@ -101,13 +94,15 @@
 
 <!-- STYLESHEETS -->
 <link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+  title="roboto">
 <link href="/assets/css/default.css" rel="stylesheet" type="text/css">
 
 
 
 <!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
 <script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
 <script type="text/javascript">
   var toRoot = "/";
@@ -130,7 +125,7 @@
 </head>
 
 <body class="gc-documentation 
-  develop" itemscope itemtype="http://schema.org/Article">
+  preview" itemscope itemtype="http://schema.org/Article">
   <div id="doc-api-level" class="" style="display:none"></div>
   <a name="top"></a>
 
@@ -138,31 +133,30 @@
   
 <a name="top"></a>
 
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
+<!-- Header -->
+<div id="header-wrapper">
+  <div id="header">
+    <div class="wrap" id="header-wrap">
+      <div class="col_3 logo wear-logo">
+        <a href="/wear/index.html">
+          <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+        </a>
+      </div>
+      <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
 
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
+      
+      
+<div class="menu-container">
+  <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
   <div class="morehover" id="moremenu">
     <div class="top"></div>
     <div class="mid">
       <div class="header">Links</div>
       <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+        <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
         <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
         <li><a href="/about/index.html">About Android</a></li>
       </ul>
@@ -172,16 +166,32 @@
         <li class="active"><a>Android Developers</a></li>
         <li><a href="http://source.android.com">Android Open Source Project</a></li>
       </ul>
-      
-      
-      
-      
 
-
+      
+      
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      
+      
       <br class="clearfix" />
-    </div><!-- end mid -->
+    </div><!-- end 'mid' -->
     <div class="bottom"></div>
-  </div><!-- end morehover -->
+  </div><!-- end 'moremenu' -->
 
   <div class="search" id="search-container">
     <div class="search-inner">
@@ -189,16 +199,16 @@
       <div class="left"></div>
       <form onsubmit="return submit_search()">
         <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
+          onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+          onkeydown="return search_changed(event, true, '/')"
+          onkeyup="return search_changed(event, false, '/')" />
       </form>
       <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
+      <a class="close hide">close</a>
+      <div class="left"></div>
+      <div class="right"></div>
+    </div><!-- end search-inner -->
+  </div><!-- end search-container -->
 
   <div class="search_filtered_wrapper reference">
     <div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
       <ul class="search_filtered">
       </ul>
     </div>
-  </div><!-- end search_filtered_wrapper -->
-
   </div>
-  <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
 
 
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
+    </div><!-- end header-wrap -->
+  </div><!-- /Header -->
 
 
   <div id="searchResults" class="wrap" style="display:none;">
           <h2 id="searchTitle">Results</h2>
           <div id="leftSearchControl" class="search-control">Loading...</div>
   </div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+  <div>
+    <a class="logo" href="#top"></a>
+    <a class="top" href="#top"></a>
+    <ul class="breadcrumb">
+      
+      <li class="current">WearableNotifications.Builder</li>
+    </ul>
+  </div>
+</div>
 
   
 
-  
 
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <ul id="nav">
 
@@ -327,7 +344,7 @@
 
 </ul>
 
-        
+
 
       </div>
     </div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
 
 
 
+
 <div class="col-12"  id="doc-col">
 
 <div id="api-info-block">
diff --git a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.html b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.html
index e03e16e..c9948b8 100644
--- a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.html
+++ b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.html
@@ -82,13 +82,6 @@
 
 
 
-
-
-
-
-
-
-
 <html>
 <head>
 
@@ -101,13 +94,15 @@
 
 <!-- STYLESHEETS -->
 <link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+  title="roboto">
 <link href="/assets/css/default.css" rel="stylesheet" type="text/css">
 
 
 
 <!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
 <script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
 <script type="text/javascript">
   var toRoot = "/";
@@ -130,7 +125,7 @@
 </head>
 
 <body class="gc-documentation 
-  develop" itemscope itemtype="http://schema.org/Article">
+  preview" itemscope itemtype="http://schema.org/Article">
   <div id="doc-api-level" class="" style="display:none"></div>
   <a name="top"></a>
 
@@ -138,31 +133,30 @@
   
 <a name="top"></a>
 
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
+<!-- Header -->
+<div id="header-wrapper">
+  <div id="header">
+    <div class="wrap" id="header-wrap">
+      <div class="col_3 logo wear-logo">
+        <a href="/wear/index.html">
+          <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+        </a>
+      </div>
+      <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
 
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
+      
+      
+<div class="menu-container">
+  <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
   <div class="morehover" id="moremenu">
     <div class="top"></div>
     <div class="mid">
       <div class="header">Links</div>
       <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+        <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
         <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
         <li><a href="/about/index.html">About Android</a></li>
       </ul>
@@ -172,16 +166,32 @@
         <li class="active"><a>Android Developers</a></li>
         <li><a href="http://source.android.com">Android Open Source Project</a></li>
       </ul>
-      
-      
-      
-      
 
-
+      
+      
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      
+      
       <br class="clearfix" />
-    </div><!-- end mid -->
+    </div><!-- end 'mid' -->
     <div class="bottom"></div>
-  </div><!-- end morehover -->
+  </div><!-- end 'moremenu' -->
 
   <div class="search" id="search-container">
     <div class="search-inner">
@@ -189,16 +199,16 @@
       <div class="left"></div>
       <form onsubmit="return submit_search()">
         <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
+          onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+          onkeydown="return search_changed(event, true, '/')"
+          onkeyup="return search_changed(event, false, '/')" />
       </form>
       <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
+      <a class="close hide">close</a>
+      <div class="left"></div>
+      <div class="right"></div>
+    </div><!-- end search-inner -->
+  </div><!-- end search-container -->
 
   <div class="search_filtered_wrapper reference">
     <div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
       <ul class="search_filtered">
       </ul>
     </div>
-  </div><!-- end search_filtered_wrapper -->
-
   </div>
-  <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
 
 
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
+    </div><!-- end header-wrap -->
+  </div><!-- /Header -->
 
 
   <div id="searchResults" class="wrap" style="display:none;">
           <h2 id="searchTitle">Results</h2>
           <div id="leftSearchControl" class="search-control">Loading...</div>
   </div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+  <div>
+    <a class="logo" href="#top"></a>
+    <a class="top" href="#top"></a>
+    <ul class="breadcrumb">
+      
+      <li class="current">WearableNotifications</li>
+    </ul>
+  </div>
+</div>
 
   
 
-  
 
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <ul id="nav">
 
@@ -327,7 +344,7 @@
 
 </ul>
 
-        
+
 
       </div>
     </div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
 
 
 
+
 <div class="col-12"  id="doc-col">
 
 <div id="api-info-block">
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index e12dfd8..7bf366c 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -75,7 +75,7 @@
 <div class="sidebox-wrapper">
 <div class="sidebox">
 <h2>App Translations in Google Play</h2>
-<p>Google Play <a href="{@docRoot}distribute/googleplay/publish/localizing.html#gp-trans">App
+<p>Google Play <a href="{@docRoot}distribute/tools/localization-checklist.html#gp-trans">App 
 Translation Service</a> is available in the Developer Console to help you
 localize your app for a global user base. You can browse qualified vendors, get
 estimates, upload strings for translation, and then import the translations directly
@@ -99,7 +99,7 @@
 localization works instantly.</p>
 
 <p>For more information about translation services in Google Play, see <a
-href="{@docRoot}distribute/googleplay/publish/localizing.html#gp-trans">Purchase
+href="{@docRoot}distribute/tools/localization-checklist.html#gp-trans">Purchase
 professional translations through the Developer Console</a>.</p>
 
 <p>To install the ADT Translation Manager Plugin follow these steps:</p>
@@ -129,7 +129,7 @@
 <ul>
 <li>The full ADT Plugin must be installed in your Eclipse environment before you install the ADT Translation Manager Plugin.</li>
 <li>ADT Translation Manager Plugin is designed for use with the translation services offered through the Google Play Developer Console. It is not designed for general purpose import/export of strings. </li>
-<li>To use the plugin, you must <a href="{@docRoot}distribute/googleplay/publish/register.html">set up a Developer Console account</a>. </li>
+<li>To use the plugin, you must <a href="{@docRoot}distribute/googleplay/start.html">set up a Developer Console account</a>. </li>
 <li>Currently, translation services are available through the Developer Console only as part of a pilot program. To use the plugin, you must first sign up for the pilot program by visiting the Developer Console.</li>
 <li>If you downloaded ADT as part of the SDK ADT bundle, you may encounter an error when attempting to download the ADT Translation Manager Plugin from the remote repository. In that case, open the <strong>Install New
 Software</strong>, uncheck "Contact all update sites during install to find required software" at the bottom and try again. </li>
diff --git a/docs/html/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd
index 071492d..a2c32f0 100644
--- a/docs/html/sdk/installing/studio.jd
+++ b/docs/html/sdk/installing/studio.jd
@@ -253,36 +253,36 @@
     <td>Windows</td>
     <td>
   <a onclick="return onDownload(this)" id="win-studio"
-      href="http://dl.google.com/android/studio/install/0.4.6/android-studio-bundle-133.1028713-windows.exe">
-      android-studio-bundle-133.1028713-windows.exe
+      href="http://dl.google.com/android/studio/install/0.5.2/android-studio-bundle-135.1078000-windows.exe">
+      android-studio-bundle-135.1078000-windows.exe
       </a>
     </td>
-    <td>519592042 bytes</td>
-    <td>9029c18738a75830786326d62c96d557</td>
+    <td>519082997 bytes</td>
+    <td>ac69889210c4d02ee3ccc1c0f3c5cf3c</td>
   </tr>
 
   <tr>
     <td><nobr>Mac OS X</nobr></td>
     <td>
   <a onclick="return onDownload(this)" id="mac-studio"
-    href="http://dl.google.com/android/studio/install/0.4.6/android-studio-bundle-133.1028713-mac.dmg">
-    android-studio-bundle-133.1028713-mac.dmg
+    href="http://dl.google.com/android/studio/install/0.5.2/android-studio-bundle-135.1078000-mac.dmg">
+    android-studio-bundle-135.1078000-mac.dmg
     </a>
     </td>
-    <td>497595811 bytes</td>
-    <td>eb2474e6d17537ddfa535e6fe8adcf0d</td>
+    <td>495989974 bytes</td>
+    <td>8c7b1ef376b8ca206c99823d9e8fd54d</td>
   </tr>
 
   <tr>
     <td>Linux</td>
     <td>
   <a onclick="return onDownload(this)" id="linux-studio"
-    href="http://dl.google.com/android/studio/install/0.4.6/android-studio-bundle-133.1028713-linux.tgz">
-    android-studio-bundle-133.1028713-linux.tgz
+    href="http://dl.google.com/android/studio/install/0.5.2/android-studio-bundle-135.1078000-linux.tgz">
+    android-studio-bundle-135.1078000-linux.tgz
     </a>
     </td>
-    <td>522177460 bytes</td>
-    <td>cc847dd6249b3033737dabe0377c8c66</td>
+    <td>520523870 bytes</td>
+    <td>689238d5e632fd236b13f9c6d49f0cb4</td>
   </tr>
   </table>
 
@@ -312,11 +312,6 @@
 </div>
 
 
-<p>Also note that due to the update to Android Gradle Plugin 0.6, you will encounter errors when opening
-existing projects. See the <a href="#Troubleshooting">Troubleshooting</a> notes below for
-information about how to resolve them.</p>
-
-
 <h2 id="Installing">Installing Android Studio</h2>
 <p>Android Studio requires JDK 6 or greater (JRE alone is not sufficient). To check if you
 have JDK installed (and which version), open a terminal and type <code>javac -version</code>.
@@ -430,6 +425,19 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>Android Studio v0.5.2</a> <em>(May 2014)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+  <ul>
+    <li>See <a href="http://tools.android.com/recent">tools.android.com</a> for a full list of changes.</li>
+  </ul>
+  </div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>Android Studio v0.4.6</a> <em>(March 2014)</em>
   </p>
 
@@ -478,8 +486,7 @@
     <li>Android Gradle plug-in updated to 0.5.0.
       <p class="caution"><strong>Caution:</strong> This new version is not backwards compatible.
       When opening a project that uses an older version of the plug-in, Studio will show an error
-      stating <strong>Gradle &lt;project_name&gt; project refresh failed.</strong> See <a
-      href="#Troubleshooting">Troubleshooting</a> below for details.</p>
+      stating <strong>Gradle &lt;project_name&gt; project refresh failed.</strong></p>
       <p>The updated Gradle plug-in includes the following changes:</p>
       <ul>
         <li>Fixed IDE model to contain the output file even if it's customized through the DSL. Also
@@ -553,65 +560,7 @@
 
 <h2 id="Troubleshooting">Troubleshooting</h2>
 
-
-<div class="figure" style="width:330px">
-<img src="{@docRoot}images/tools/studio_error_gradle5.png" width="330"/>
-<p class="img-caption"><strong>Figure 1.</strong> Error dialog when opening an existing project.</p>
-</div>
-
-<h3>Error: Gradle project refresh failed</h3>
-
-<p>Android Studio 0.2.0 has updated the Gradle plug-in to 0.5.0, which is not backwards compatible.
-When opening a project that uses an older version of the plug-in, Studio will display the error
-shown in figure 1 in the upper right corner of the IDE.
-To resolve the error, you must change the version of the Android Gradle plug-in to 0.5.0.</p>
-
-<ol>
-  <li>Click the link in the error dialog <strong>Search in build.gradle files</strong>. If the dialog
-is no longer visible, click <strong>Event Log</strong>
-<img src="{@docRoot}images/tools/studio_error_eventlog.png"
-style="vertical-align:bottom;margin:0;height:19px"/> in the bottom-right corner of the IDE,
-then click <strong>Search in build.gradle files</strong>.</li>
-  <li>Double-click the line under the <em>build.gradle</em> usage. For example:
-  <strong>classpath 'com.android.tools.build:gradle:0.4</strong>. This opens the project
-  <code>build.gradle</code> file.</li>
-  <li>Edit the <code>classpath</code> to change the gradle version to <code>0.5.+</code>.
-  For example:
-  <pre class="no-pretty-print">
-dependencies {
-  classpath 'com.android.tools.build:gradle:<strong>0.5.+</strong>'
-}
-</pre>
-  </li>
-  <li>Save the file and rebuild your project.</li>
-</ol>
-
-
-
-<div class="figure" style="width:330px">
-<img src="{@docRoot}images/tools/studio_error_supportlib.png" width="330"/>
-<p class="img-caption"><strong>Figure 2.</strong> Error dialog when creating a new project
-or opening a project using the support library.</p>
-</div>
-
-<h3>Error: Failed to import Gradle project</h3>
-
-<p>If, after updating to Android Studio 0.2.x and creating or opening a project, you receive an
-error stating <em>"Could not find any version that matches
-com.android.support:support-v4:13.0.+"</em>, then you must install the <strong>Android Support
-Repository</strong>. This was likely caused because you're pointing Android Studio to an external
-Android SDK location that does not have the new Maven repository included with Android Studio
-0.2.x. This new Maven repository is used by the new build system for the Support Library, instead
-of using the Support Library JAR files, so must be present in the SDK.</p>
-
-
-<ol>
-  <li>Open the <strong>Android SDK Manager</strong>.</li>
-  <li>Expand the <strong>Extras</strong> directory
-and install <strong>Android Support Repository</strong>.</li>
-</ol>
-
-<p>If you've encountered other problems in Android Studio, look at the following page
+<p>If you encounter problems in Android Studio, look at the following page
 for possible resolutions to known issues: <a href="http://tools.android.com/knownissues"
 >http://tools.android.com/knownissues</a>.</p>
 
@@ -650,7 +599,7 @@
   if (os) {
     /* set up primary ACE download button */
     $('#download-ide-button').show();
-    $('#download-ide-button').append("Download Android Studio <span class='small'>v0.4.6</span>"
+    $('#download-ide-button').append("Download Android Studio <span class='small'>v0.5.2</span>"
         + "<br/> <span class='small'>for " + os + "</span>");
     $('#download-ide-button').click(function() {return onDownload(this,true);}).attr('href', bundlename);
 
diff --git a/docs/html/sitemap.txt b/docs/html/sitemap.txt
index 9bff5d4..cd87d1c 100644
--- a/docs/html/sitemap.txt
+++ b/docs/html/sitemap.txt
@@ -17,8 +17,8 @@
 http://developer.android.com/google/index.html
 http://developer.android.com/distribute/googleplay/publish/index.html
 http://developer.android.com/distribute/googleplay/promote/index.html
-http://developer.android.com/distribute/googleplay/quality/index.html
-http://developer.android.com/distribute/googleplay/spotlight/index.html
+http://developer.android.com/distribute/essentials/quality/index.html
+http://developer.android.com/distribute/stories/index.html
 http://developer.android.com/distribute/open.html
 http://developer.android.com/about/versions/jelly-bean.html
 http://developer.android.com/support.html
@@ -64,9 +64,9 @@
 http://developer.android.com/design/building-blocks/dialogs.html
 http://developer.android.com/design/building-blocks/pickers.html
 http://developer.android.com/google/play-services/maps.html
-http://developer.android.com/distribute/googleplay/quality/tablet.html
-http://developer.android.com/distribute/googleplay/spotlight/tablets.html
-http://developer.android.com/distribute/googleplay/quality/core.html
+http://developer.android.com/distribute/essentials/quality/tablet.html
+http://developer.android.com/distribute/stories/tablets.html
+http://developer.android.com/distribute/essentials/quality/core.html
 http://developer.android.com/guide/topics/ui/notifiers/notifications.html
 http://developer.android.com/guide/topics/ui/dialogs.html
 http://developer.android.com/downloads/design/Android_Design_Downloads_20120823.zip
@@ -173,13 +173,13 @@
 http://developer.android.com/distribute/googleplay/about/visibility.html
 http://developer.android.com/distribute/googleplay/about/monetizing.html
 http://developer.android.com/distribute/googleplay/about/distribution.html
-http://developer.android.com/distribute/googleplay/publish/register.html
+http://developer.android.com/distribute/googleplay/start.html
 http://developer.android.com/distribute/googleplay/publish/console.html
-http://developer.android.com/distribute/googleplay/publish/preparing.html
-http://developer.android.com/distribute/googleplay/promote/linking.html
+http://developer.android.com/distribute/tools/launch-checklist.html
+http://developer.android.com/distribute/tools/promote/linking.html
 http://developer.android.com/distribute/googleplay/promote/badges.html
 http://developer.android.com/distribute/promote/device-art.html
-http://developer.android.com/distribute/googleplay/promote/brand.html
+http://developer.android.com/distribute/tools/promote/brand.html
 http://developer.android.com/distribute/googleplay/strategies/app-quality.html
 http://developer.android.com/google/play/billing/index.html
 http://developer.android.com/google/play/licensing/index.html
diff --git a/docs/html/support.jd b/docs/html/support.jd
index 63bed30..4271eee 100644
--- a/docs/html/support.jd
+++ b/docs/html/support.jd
@@ -1,6 +1,8 @@
 page.title=Developer Support
+page.type=about
 fullpage=1
-excludeFromSuggestions=true
+page.metaDescription=Resources available to help you report and resolve issues while you are developing apps for Android.
+page.image=/images/android-support-card.png
 @jd:body
 
 <div class="wrap" style="width:940px;">
diff --git a/docs/html/tools/device.jd b/docs/html/tools/device.jd
index ccd5903..e9caa44 100644
--- a/docs/html/tools/device.jd
+++ b/docs/html/tools/device.jd
@@ -192,6 +192,10 @@
     <td><code>12d1</code></td>
   </tr>
   <tr>
+    <td>Intel</td>
+    <td><code>8087</code></td>
+  </tr>
+  <tr>
     <td>K-Touch</td>
     <td><code>24e3</code></td>
   </tr>
diff --git a/docs/html/tools/publishing/preparing.jd b/docs/html/tools/publishing/preparing.jd
index 413b56e..7192aa8 100644
--- a/docs/html/tools/publishing/preparing.jd
+++ b/docs/html/tools/publishing/preparing.jd
@@ -22,7 +22,7 @@
     <ol>
       <li><a href="{@docRoot}tools/publishing/publishing_overview.html">Publishing Overview</a></li>
       <li><a href="{@docRoot}tools/publishing/app-signing.html">Signing Your Applications</a></li>
-      <li><a href="{@docRoot}distribute/googleplay/publish/preparing.html">Launch Checklist for Google Play</a></li>
+      <li><a href="{@docRoot}distribute/tools/launch-checklist.html">Launch Checklist for Google Play</a></li>
     </ol>
   </div>
 </div>
@@ -44,7 +44,7 @@
 <p>This document summarizes the main tasks you need to perform to prepare your application for
 release. The tasks that are described in this document apply to all Android applications regardless
 how they are released or distributed to users. If you are releasing your application through Google
-Play, you should also read <a href="{@docRoot}distribute/googleplay/publish/preparing.html">Publishing
+Play, you should also read <a href="{@docRoot}distribute/tools/launch-checklist.html">Publishing
 Checklist for Google Play</a> to be sure your release-ready application satisfies all Google Play
 requirements.</p>
 
@@ -353,7 +353,7 @@
 behaves correctly, you can release your application to users. For more information, see
 <a href="{@docRoot}tools/publishing/publishing_overview.html#publishing-release">Releasing Your
 Application to Users</a>. If you are publishing your application on Google Play, see
-<a href="{@docRoot}distribute/googleplay/publish/preparing.html">Launch Checklist
+<a href="{@docRoot}distribute/tools/launch-checklist.html">Launch Checklist
 for Google Play</a>.</p>
 
 
diff --git a/docs/html/tools/publishing/publishing_overview.jd b/docs/html/tools/publishing/publishing_overview.jd
index ea01e20..c4b3bdf 100644
--- a/docs/html/tools/publishing/publishing_overview.jd
+++ b/docs/html/tools/publishing/publishing_overview.jd
@@ -16,7 +16,7 @@
   </ol>
   <h2>See also</h2>
   <ol>
-    <li><a href="{@docRoot}distribute/googleplay/publish/preparing.html">Publishing on Google Play</a></li>
+    <li><a href="{@docRoot}distribute/tools/launch-checklist.html">Publishing on Google Play</a></li>
   </ol>
 </div>
 </div>
@@ -35,7 +35,7 @@
   </li>
 </ul>
 
-<p>Usually, you release your application through an application marketplace, such as <a href="{@docRoot}distribute/index.html">Google Play</a>.
+<p>Usually, you release your application through an application marketplace, such as <a href="{@docRoot}distribute/googleplay/index.html">Google Play</a>.
 However, you can also release applications by sending them directly to users or by letting users
 download them from your own website.</p>
 
@@ -157,7 +157,7 @@
   </li>
 </ul>
 
-<p>For information complete information, see <a href="{@docRoot}distribute/index.html">Google Play</a>.</p>
+<p>For information complete information, see <a href="{@docRoot}distribute/googleplay/index.html">Google Play</a>.</p>
 
 
 <h3 id="publishing-email">Releasing your application through email</h3>
diff --git a/docs/html/tools/publishing/versioning.jd b/docs/html/tools/publishing/versioning.jd
index a1cfb30..6d3ec2f 100644
--- a/docs/html/tools/publishing/versioning.jd
+++ b/docs/html/tools/publishing/versioning.jd
@@ -25,7 +25,7 @@
 
 <ol>
 <li><a href="{@docRoot}tools/publishing/preparing.html">Preparing to Publish Your Application</a></li>
-<li><a href="{@docRoot}distribute/googleplay/publish/preparing.html">Launch Checklist for Google Play</a></li>
+<li><a href="{@docRoot}distribute/tools/launch-checklist.html">Launch Checklist for Google Play</a></li>
 <li><a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml File</a></li>
 </ol>
 
diff --git a/docs/html/tools/revisions/build-tools.jd b/docs/html/tools/revisions/build-tools.jd
index c3c83ef..d8abab0 100644
--- a/docs/html/tools/revisions/build-tools.jd
+++ b/docs/html/tools/revisions/build-tools.jd
@@ -77,6 +77,26 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>Build Tools, Revision 19.1.0</a> <em>(May 2014)</em>
+  </p>
+  <div class="toggle-content-toggleme">
+
+    <dl>
+      <dt>General Notes:</dt>
+      <dd>
+        <ul>
+          <li>Added <code>zipalign</code> to the Build Tools.</li>
+          <li>Modified <code>aapt</code> to ignore XML files that fail to compile.</li>
+        </ul>
+      </dd>
+    </dl>
+
+  </div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>Build Tools, Revision 19.0.3</a> <em>(March 2014)</em>
   </p>
   <div class="toggle-content-toggleme">
diff --git a/docs/html/training/basics/intents/sending.jd b/docs/html/training/basics/intents/sending.jd
index 30dc95a..2a4dae7 100644
--- a/docs/html/training/basics/intents/sending.jd
+++ b/docs/html/training/basics/intents/sending.jd
@@ -166,7 +166,7 @@
 starts in case you need to disable the feature that uses the intent before the user attempts to use
 it. If you know of a specific app that can handle the intent, you can also provide a link for the
 user to download the app (see how to <a
-href="{@docRoot}distribute/googleplay/promote/linking.html">link to your product on Google
+href="{@docRoot}distribute/tools/promote/linking.html">link to your product on Google
 Play</a>).</p>
 
 
diff --git a/docs/html/training/basics/supporting-devices/languages.jd b/docs/html/training/basics/supporting-devices/languages.jd
index 5a1507c..45e2ab2 100644
--- a/docs/html/training/basics/supporting-devices/languages.jd
+++ b/docs/html/training/basics/supporting-devices/languages.jd
@@ -19,7 +19,7 @@
     </ol>
     <h2>You should also read</h2>
     <ul>
-    <li><a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization Checklist</a></li>
+    <li><a href="{@docRoot}distribute/tools/localization-checklist.html">Localization Checklist</a></li>
       <li><a href="{@docRoot}guide/topics/resources/localization.html">Localization with Resources</a></li>
     </ul>
   </div>
diff --git a/docs/html/training/basics/supporting-devices/platforms.jd b/docs/html/training/basics/supporting-devices/platforms.jd
index c38101a..60aaf6a 100644
--- a/docs/html/training/basics/supporting-devices/platforms.jd
+++ b/docs/html/training/basics/supporting-devices/platforms.jd
@@ -1,4 +1,5 @@
 page.title=Supporting Different Platform Versions
+page.metaDescription=Training on how to declare support for minimum and target API levels.
 parent.title=Supporting Different Devices
 parent.link=index.html
 
diff --git a/docs/html/training/design-navigation/multiple-sizes.jd b/docs/html/training/design-navigation/multiple-sizes.jd
index 26a5828..a0ce103 100644
--- a/docs/html/training/design-navigation/multiple-sizes.jd
+++ b/docs/html/training/design-navigation/multiple-sizes.jd
@@ -8,6 +8,10 @@
 next.title=Providing Descendant and Lateral Navigation
 next.link=descendant-lateral.html
 
+meta.tags="multiple screens"
+page.metaDescription=Designing an intuitive, effective navigation for tablets and other devices.
+page.image=/images/training/app-navigation-multiple-sizes-strategy-stack.png
+
 @jd:body
 
 <div id="tb-wrapper">
diff --git a/docs/html/training/multiscreen/index.jd b/docs/html/training/multiscreen/index.jd
index 45b6161..8eff246 100644
--- a/docs/html/training/multiscreen/index.jd
+++ b/docs/html/training/multiscreen/index.jd
@@ -1,5 +1,6 @@
 page.title=Designing for Multiple Screens
-page.tags=tablet,tv,fragments,support
+page.tags="tablet","tv","fragments","support"
+page.metaDescription=Training on how to add intuitive, effective navigation for tablets and other devices.
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/multiscreen/screendensities.jd b/docs/html/training/multiscreen/screendensities.jd
index 7d6ff44..7817830 100644
--- a/docs/html/training/multiscreen/screendensities.jd
+++ b/docs/html/training/multiscreen/screendensities.jd
@@ -1,4 +1,7 @@
 page.title=Supporting Different Densities
+page.metaDescription=Providing sets of layouts and drawable resources for specific ranges of device screens.
+meta.tags="multiple screens"
+
 parent.title=Designing for Multiple Screens
 parent.link=index.html
 
diff --git a/docs/html/wear/images/notif_summary_framed.png b/docs/html/wear/images/notif_summary_framed.png
new file mode 100644
index 0000000..17b1703
--- /dev/null
+++ b/docs/html/wear/images/notif_summary_framed.png
Binary files differ
diff --git a/docs/html/wear/notifications/stacks.jd b/docs/html/wear/notifications/stacks.jd
index 7f955f6..a2d34ce 100644
--- a/docs/html/wear/notifications/stacks.jd
+++ b/docs/html/wear/notifications/stacks.jd
@@ -2,8 +2,8 @@
 
 @jd:body
 
-<img src="{@docRoot}wear/images/11_bundles_B.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" />
-<img src="{@docRoot}wear/images/11_bundles_A.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" />
+<img src="{@docRoot}wear/images/11_bundles_B.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" alt="" />
+<img src="{@docRoot}wear/images/11_bundles_A.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" alt="" />
 
 <p>When creating notifications for a handheld device, you should always aggregate similar
 notifications into a single summary notification. For example, if your app creates notifications
@@ -29,20 +29,44 @@
 
 <p>To create a stack, call <a
 href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setGroup(java.lang.String, int)">
-<code>setGroup()</code></a> for each notification you want in the stack, passing the same
-group key. For example:</p>
+<code>setGroup()</code></a> for each notification you want in the stack and specify a
+group key. Then call <a href="{@docRoot}reference/android/preview/support/v4/app/NotificationManagerCompat.html#notify(int, android.app.Notification)"><code>notify()</code></a> to send it to the wearable.</p>
 
 <pre style="clear:right">
 final static String GROUP_KEY_EMAILS = "group_key_emails";
 
+// Build the notification and pass this builder to WearableNotifications.Builder
 NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext)
-         .setContentTitle("New mail from " + sender)
-         .setContentText(subject)
+         .setContentTitle("New mail from " + sender1)
+         .setContentText(subject1)
          .setSmallIcon(R.drawable.new_mail);
 
-Notification notif = new WearableNotifications.Builder(builder)
+Notification notif1 = new WearableNotifications.Builder(builder)
          .setGroup(GROUP_KEY_EMAILS)
          .build();
+
+// Issue the notification
+NotificationManagerCompat notificationManager =
+        NotificationManagerCompat.from(this);
+notificationManager.notify(notificationId1, notif);
+</pre>
+
+<p>Later on, when you create another notification, specify
+the same group key. When you call <a href="{@docRoot}reference/android/preview/support/v4/app/NotificationManagerCompat.html#notify(int, android.app.Notification)"><code>notify()</code></a>, this notification appears
+in the same stack as the previous notification, instead of as a new card:</p>
+
+<pre style="clear:right">
+builder = new NotificationCompat.Builder(mContext)
+         .setContentTitle("New mail from " + sender2)
+         .setContentText(subject2)
+         .setSmallIcon(R.drawable.new_mail);
+
+// Use the same group as the previous notification
+Notification notif2 = new WearableNotifications.Builder(builder)
+         .setGroup(GROUP_KEY_EMAILS)
+         .build();
+
+notificationManager.notify(notificationId2, notif);
 </pre>
 
 <p>By default, notifications appear in the order in which you added them, with the most recent
@@ -54,19 +78,55 @@
 
 <h2 id="AddSummary">Add a Summary Notification</h2>
 
+<img src="{@docRoot}wear/images/notif_summary_framed.png" height="242" width="330" style="float:right;margin:0 0 20px 40px" alt="" />
+
 <p>It's important that you still provide a summary notification that appears on handheld devices.
 So in addition to adding each unique notification to the same stack group, also add a summary
 notification, but set its order position to be <a
 href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.html#GROUP_ORDER_SUMMARY"><code>GROUP_ORDER_SUMMARY</code></a>.</p>
 
-<pre>
-Notification summaryNotification = new WearableNotifications.Builder(builder)
-         .setGroup(GROUP_KEY_EMAILS, WearableNotifications.GROUP_ORDER_SUMMARY)
-         .build();
+<p>This notification does not appear in your stack of notifications on the wearable, but
+appears as the only notification on the handheld device.</p>
+
+<pre style="clear:right">
+Bitmap largeIcon = BitmapFactory.decodeResource(getResources(),
+        R.drawable.ic_large_icon);
+
+builder = new NotificationCompat.Builder(this)
+        .setSmallIcon(R.drawable.ic_small_icon)
+        .setLargeIcon(largeIcon);
+
+// Use the same group key and pass this builder to InboxStyle notification
+WearableNotifications.Builder wearableBuilder = new WearableNotifications
+        .Builder(builder)
+        .setGroup(GROUP_KEY_EMAILS,
+                WearableNotifications.GROUP_ORDER_SUMMARY);
+
+// Build the final notification to show on the handset
+Notification summaryNotification = new NotificationCompat.InboxStyle(
+        wearableBuilder.getCompatBuilder())
+        .addLine("Alex Faaborg   Check this out")
+        .addLine("Jeff Chang   Launch Party")
+        .setBigContentTitle("2 new messages")
+        .setSummaryText("johndoe@gmail.com")
+        .build();
+
+notificationManager.notify(notificationId3, summaryNotification);
 </pre>
 
-<p>This notification will not appear in your stack of notifications on the wearable, but
-appears as the only notification on the handheld device.
+<p>
+This notification uses {@link android.support.v4.app.NotificationCompat.InboxStyle},
+which gives you an easy way to create notifications for email or messaging apps.
+You can use this style, another one defined in {@link android.support.v4.app.NotificationCompat},
+or no style for the summary notification.
+</p>
 
+<p class="note"><b>Tip:</b>
+To style the text like in the example screenshot, see
+<a href="{@docRoot}guide/topics/resources/string-resource.html#StylingWithHTML">Styling
+with HTML markup</a> and
+<a href="{@docRoot}guide/topics/resources/string-resource.html#StylingWithSpannables">Styling
+with Spannables</a>.
+</p>
 </body>
-</html>
+</html>
\ No newline at end of file
diff --git a/graphics/java/android/graphics/Camera.java b/graphics/java/android/graphics/Camera.java
index c263a84..a40085b 100644
--- a/graphics/java/android/graphics/Camera.java
+++ b/graphics/java/android/graphics/Camera.java
@@ -154,7 +154,7 @@
             getMatrix(mMatrix);
             canvas.concat(mMatrix);
         } else {
-            nativeApplyToCanvas(canvas.mNativeCanvas);
+            nativeApplyToCanvas(canvas.getNativeCanvas());
         }
     }
 
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index ae3eae1..5b18623 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -39,8 +39,12 @@
 public class Canvas {
 
     // assigned in constructors or setBitmap, freed in finalizer
+    private long mNativeCanvas;
+
     /** @hide */
-    public long mNativeCanvas;
+    public long getNativeCanvas() {
+        return mNativeCanvas;
+    }
 
     // may be null
     private Bitmap mBitmap;
diff --git a/graphics/java/android/graphics/CanvasProperty.java b/graphics/java/android/graphics/CanvasProperty.java
new file mode 100644
index 0000000..be86060
--- /dev/null
+++ b/graphics/java/android/graphics/CanvasProperty.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.internal.util.VirtualRefBasePtr;
+
+/**
+ * TODO: Make public?
+ * @hide
+ */
+public final class CanvasProperty<T> {
+
+    private VirtualRefBasePtr mProperty;
+
+    public static CanvasProperty<Float> createFloat(float initialValue) {
+        return new CanvasProperty<Float>(nCreateFloat(initialValue));
+    }
+
+    public static CanvasProperty<Paint> createPaint(Paint initialValue) {
+        return new CanvasProperty<Paint>(nCreatePaint(initialValue.mNativePaint));
+    }
+
+    private CanvasProperty(long nativeContainer) {
+        mProperty = new VirtualRefBasePtr(nativeContainer);
+    }
+
+    /** @hide */
+    public long getNativeContainer() {
+        return mProperty.get();
+    }
+
+    private static native long nCreateFloat(float initialValue);
+    private static native long nCreatePaint(long initialValuePaintPtr);
+}
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index e08ed50..062acaf 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -253,4 +253,31 @@
         }
         return -1;
     }
+
+    /**
+     * Determine whether or not this is a public-visible {@code format}.
+     *
+     * <p>In particular, {@code @hide} formats will return {@code false}.</p>
+     *
+     * <p>Any other formats (including UNKNOWN) will return {@code false}.</p>
+     *
+     * @param format an integer format
+     * @return a boolean
+     *
+     * @hide
+     */
+    public static boolean isPublicFormat(int format) {
+        switch (format) {
+            case RGB_565:
+            case NV16:
+            case YUY2:
+            case YV12:
+            case NV21:
+            case YUV_420_888:
+            case RAW_SENSOR:
+                return true;
+        }
+
+        return false;
+    }
 }
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index 69089b1..6ff5f4f 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -164,12 +164,12 @@
     }
 
     void drawSoftware(Canvas canvas, RectF location, Paint paint) {
-        nativeDraw(canvas.mNativeCanvas, location, mBitmap.ni(), mNativeChunk,
+        nativeDraw(canvas.getNativeCanvas(), location, mBitmap.ni(), mNativeChunk,
                 paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity);
     }
 
     void drawSoftware(Canvas canvas, Rect location, Paint paint) {
-        nativeDraw(canvas.mNativeCanvas, location, mBitmap.ni(), mNativeChunk,
+        nativeDraw(canvas.getNativeCanvas(), location, mBitmap.ni(), mNativeChunk,
                 paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity);
     }
 
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index af8b9d9..bdef404 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -55,27 +55,6 @@
     /**
      * @hide
      */
-    public boolean hasShadow;
-    /**
-     * @hide
-     */
-    public float shadowDx;
-    /**
-     * @hide
-     */
-    public float shadowDy;
-    /**
-     * @hide
-     */
-    public float shadowRadius;
-    /**
-     * @hide
-     */
-    public int shadowColor;
-
-    /**
-     * @hide
-     */
     public  int         mBidiFlags = BIDI_DEFAULT_LTR;
     
     static final Style[] sStyleArray = {
@@ -492,12 +471,6 @@
         mCompatScaling = 1;
         mInvCompatScaling = 1;
 
-        hasShadow = false;
-        shadowDx = 0;
-        shadowDy = 0;
-        shadowRadius = 0;
-        shadowColor = 0;
-
         mBidiFlags = BIDI_DEFAULT_LTR;
         setTextLocale(Locale.getDefault());
         setElegantTextHeight(false);
@@ -538,12 +511,6 @@
         mCompatScaling = paint.mCompatScaling;
         mInvCompatScaling = paint.mInvCompatScaling;
 
-        hasShadow = paint.hasShadow;
-        shadowDx = paint.shadowDx;
-        shadowDy = paint.shadowDy;
-        shadowRadius = paint.shadowRadius;
-        shadowColor = paint.shadowColor;
-
         mBidiFlags = paint.mBidiFlags;
         mLocale = paint.mLocale;
     }
@@ -1135,22 +1102,24 @@
      * layer is removed.
      */
     public void setShadowLayer(float radius, float dx, float dy, int color) {
-        hasShadow = radius > 0.0f;
-        shadowRadius = radius;
-        shadowDx = dx;
-        shadowDy = dy;
-        shadowColor = color;
-        nSetShadowLayer(radius, dx, dy, color);
+      native_setShadowLayer(mNativePaint, radius, dx, dy, color);
     }
-    
-    private native void nSetShadowLayer(float radius, float dx, float dy, int color);
 
     /**
      * Clear the shadow layer.
      */
     public void clearShadowLayer() {
-        hasShadow = false;
-        nSetShadowLayer(0, 0, 0, 0);
+        setShadowLayer(0, 0, 0, 0);
+    }
+
+    /**
+     * Checks if the paint has a shadow layer attached
+     *
+     * @return true if the paint has a shadow layer attached and false otherwise
+     * @hide
+     */
+    public boolean hasShadowLayer() {
+      return native_hasShadowLayer(mNativePaint);
     }
 
     /**
@@ -2295,4 +2264,8 @@
     private static native void nativeGetCharArrayBounds(long nativePaint,
                                 char[] text, int index, int count, int bidiFlags, Rect bounds);
     private static native void finalizer(long nativePaint);
+
+    private static native void native_setShadowLayer(long native_object,
+            float radius, float dx, float dy, int color);
+    private static native boolean native_hasShadowLayer(long native_object);
 }
diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java
index 25188e0..a16c099 100644
--- a/graphics/java/android/graphics/Picture.java
+++ b/graphics/java/android/graphics/Picture.java
@@ -107,7 +107,7 @@
         if (mRecordingCanvas != null) {
             endRecording();
         }
-        nativeDraw(canvas.mNativeCanvas, mNativePicture);
+        nativeDraw(canvas.getNativeCanvas(), mNativePicture);
     }
 
     /**
diff --git a/graphics/java/android/graphics/PixelFormat.java b/graphics/java/android/graphics/PixelFormat.java
index d96d6d8..832b9c3 100644
--- a/graphics/java/android/graphics/PixelFormat.java
+++ b/graphics/java/android/graphics/PixelFormat.java
@@ -115,7 +115,7 @@
                 info.bytesPerPixel = 1;
                 break;
             default:
-                throw new IllegalArgumentException("unkonwon pixel format " + format);
+                throw new IllegalArgumentException("unknown pixel format " + format);
         }
     }
 
@@ -135,4 +135,29 @@
 
     public int  bytesPerPixel;
     public int  bitsPerPixel;
+
+    /**
+     * Determine whether or not this is a public-visible and non-deprecated {@code format}.
+     *
+     * <p>In particular, {@code @hide} formats will return {@code false}.</p>
+     *
+     * <p>Any other indirect formats (such as {@code TRANSPARENT} or {@code TRANSLUCENT})
+     * will return {@code false}.</p>
+     *
+     * @param format an integer format
+     * @return a boolean
+     *
+     * @hide
+     */
+    public static boolean isPublicFormat(int format) {
+        switch (format) {
+            case RGBA_8888:
+            case RGBX_8888:
+            case RGB_888:
+            case RGB_565:
+                return true;
+        }
+
+        return false;
+    }
 }
diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java
index 8b5609f..437d2f4 100644
--- a/graphics/java/android/graphics/Rect.java
+++ b/graphics/java/android/graphics/Rect.java
@@ -36,9 +36,21 @@
     public int right;
     public int bottom;
 
-    private static final Pattern FLATTENED_PATTERN = Pattern.compile(
+    /**
+     * A helper class for flattened rectange pattern recognition. A separate
+     * class to avoid an initialization dependency on a regular expression
+     * causing Rect to not be initializable with an ahead-of-time compilation
+     * scheme.
+     */
+    private static final class UnflattenHelper {
+        private static final Pattern FLATTENED_PATTERN = Pattern.compile(
             "(-?\\d+) (-?\\d+) (-?\\d+) (-?\\d+)");
 
+        static Matcher getMatcher(String str) {
+            return FLATTENED_PATTERN.matcher(str);
+        }
+    }
+
     /**
      * Create a new empty Rect. All coordinates are initialized to 0.
      */
@@ -152,7 +164,7 @@
      * or null if the string is not of that form.
      */
     public static Rect unflattenFromString(String str) {
-        Matcher matcher = FLATTENED_PATTERN.matcher(str);
+        Matcher matcher = UnflattenHelper.getMatcher(str);
         if (!matcher.matches()) {
             return null;
         }
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index d877502..0862cdd 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -18,6 +18,7 @@
 
 import java.lang.ref.WeakReference;
 
+import android.annotation.Nullable;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -62,9 +63,8 @@
  * #updateTexImage} should not be called directly from the callback.
  */
 public class SurfaceTexture {
-
-    private EventHandler mEventHandler;
-    private OnFrameAvailableListener mOnFrameAvailableListener;
+    private final Looper mCreatorLooper;
+    private Handler mOnFrameAvailableHandler;
 
     /**
      * These fields are used by native code, do not access or modify.
@@ -83,7 +83,8 @@
     /**
      * Exception thrown when a SurfaceTexture couldn't be created or resized.
      *
-     * @deprecated No longer thrown. {@link Surface.OutOfResourcesException} is used instead.
+     * @deprecated No longer thrown. {@link android.view.Surface.OutOfResourcesException}
+     * is used instead.
      */
     @SuppressWarnings("serial")
     @Deprecated
@@ -100,10 +101,10 @@
      *
      * @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
      *
-     * @throws OutOfResourcesException If the SurfaceTexture cannot be created.
+     * @throws Surface.OutOfResourcesException If the SurfaceTexture cannot be created.
      */
     public SurfaceTexture(int texName) {
-        init(texName, false);
+        this(texName, false);
     }
 
     /**
@@ -121,20 +122,59 @@
      * @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
      * @param singleBufferMode whether the SurfaceTexture will be in single buffered mode.
      *
-     * @throws throws OutOfResourcesException If the SurfaceTexture cannot be created.
+     * @throws Surface.OutOfResourcesException If the SurfaceTexture cannot be created.
      */
     public SurfaceTexture(int texName, boolean singleBufferMode) {
-        init(texName, singleBufferMode);
+        mCreatorLooper = Looper.myLooper();
+        nativeInit(texName, singleBufferMode, new WeakReference<SurfaceTexture>(this));
     }
 
     /**
      * Register a callback to be invoked when a new image frame becomes available to the
-     * SurfaceTexture.  Note that this callback may be called on an arbitrary thread, so it is not
+     * SurfaceTexture.
+     * <p>
+     * The callback may be called on an arbitrary thread, so it is not
      * safe to call {@link #updateTexImage} without first binding the OpenGL ES context to the
      * thread invoking the callback.
+     * </p>
+     *
+     * @param listener The listener to use, or null to remove the listener.
      */
-    public void setOnFrameAvailableListener(OnFrameAvailableListener l) {
-        mOnFrameAvailableListener = l;
+    public void setOnFrameAvailableListener(@Nullable OnFrameAvailableListener listener) {
+        setOnFrameAvailableListener(listener, null);
+    }
+
+    /**
+     * Register a callback to be invoked when a new image frame becomes available to the
+     * SurfaceTexture.
+     * <p>
+     * If a handler is specified, the callback will be invoked on that handler's thread.
+     * If no handler is specified, then the callback may be called on an arbitrary thread,
+     * so it is not safe to call {@link #updateTexImage} without first binding the OpenGL ES
+     * context to the thread invoking the callback.
+     * </p>
+     *
+     * @param listener The listener to use, or null to remove the listener.
+     * @param handler The handler on which the listener should be invoked, or null
+     * to use an arbitrary thread.
+     */
+    public void setOnFrameAvailableListener(@Nullable final OnFrameAvailableListener listener,
+            @Nullable Handler handler) {
+        if (listener != null) {
+            // Although we claim the thread is arbitrary, earlier implementation would
+            // prefer to send the callback on the creating looper or the main looper
+            // so we preserve this behavior here.
+            Looper looper = handler != null ? handler.getLooper() :
+                    mCreatorLooper != null ? mCreatorLooper : Looper.getMainLooper();
+            mOnFrameAvailableHandler = new Handler(looper, null, true /*async*/) {
+                @Override
+                public void handleMessage(Message msg) {
+                    listener.onFrameAvailable(SurfaceTexture.this);
+                }
+            };
+        } else {
+            mOnFrameAvailableHandler = null;
+        }
     }
 
     /**
@@ -285,49 +325,22 @@
         }
     }
 
-    private class EventHandler extends Handler {
-        public EventHandler(Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            if (mOnFrameAvailableListener != null) {
-                mOnFrameAvailableListener.onFrameAvailable(SurfaceTexture.this);
-            }
-        }
-    }
-
     /**
      * This method is invoked from native code only.
      */
     @SuppressWarnings({"UnusedDeclaration"})
-    private static void postEventFromNative(Object selfRef) {
-        WeakReference weakSelf = (WeakReference)selfRef;
-        SurfaceTexture st = (SurfaceTexture)weakSelf.get();
-        if (st == null) {
-            return;
-        }
-
-        if (st.mEventHandler != null) {
-            Message m = st.mEventHandler.obtainMessage();
-            st.mEventHandler.sendMessage(m);
+    private static void postEventFromNative(WeakReference<SurfaceTexture> weakSelf) {
+        SurfaceTexture st = weakSelf.get();
+        if (st != null) {
+            Handler handler = st.mOnFrameAvailableHandler;
+            if (handler != null) {
+                handler.sendEmptyMessage(0);
+            }
         }
     }
 
-    private void init(int texName, boolean singleBufferMode) throws Surface.OutOfResourcesException {
-        Looper looper;
-        if ((looper = Looper.myLooper()) != null) {
-            mEventHandler = new EventHandler(looper);
-        } else if ((looper = Looper.getMainLooper()) != null) {
-            mEventHandler = new EventHandler(looper);
-        } else {
-            mEventHandler = null;
-        }
-        nativeInit(texName, singleBufferMode, new WeakReference<SurfaceTexture>(this));
-    }
-
-    private native void nativeInit(int texName, boolean singleBufferMode, Object weakSelf)
+    private native void nativeInit(int texName, boolean singleBufferMode,
+            WeakReference<SurfaceTexture> weakSelf)
             throws Surface.OutOfResourcesException;
     private native void nativeFinalize();
     private native void nativeGetTransformMatrix(float[] mtx);
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
new file mode 100644
index 0000000..46e3401
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -0,0 +1,524 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.drawable;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.util.LongSparseLongArray;
+import android.util.SparseIntArray;
+import android.util.StateSet;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * Drawable containing a set of Drawable keyframes where the currently displayed
+ * keyframe is chosen based on the current state set. Animations between
+ * keyframes may optionally be defined using transition elements.
+ * <p>
+ * This drawable can be defined in an XML file with the <code>
+ * &lt;animated-selector></code> element. Each keyframe Drawable is defined in a
+ * nested <code>&lt;item></code> element. Transitions are defined in a nested
+ * <code>&lt;transition></code> element.
+ *
+ * @attr ref android.R.styleable#DrawableStates_state_focused
+ * @attr ref android.R.styleable#DrawableStates_state_window_focused
+ * @attr ref android.R.styleable#DrawableStates_state_enabled
+ * @attr ref android.R.styleable#DrawableStates_state_checkable
+ * @attr ref android.R.styleable#DrawableStates_state_checked
+ * @attr ref android.R.styleable#DrawableStates_state_selected
+ * @attr ref android.R.styleable#DrawableStates_state_activated
+ * @attr ref android.R.styleable#DrawableStates_state_active
+ * @attr ref android.R.styleable#DrawableStates_state_single
+ * @attr ref android.R.styleable#DrawableStates_state_first
+ * @attr ref android.R.styleable#DrawableStates_state_middle
+ * @attr ref android.R.styleable#DrawableStates_state_last
+ * @attr ref android.R.styleable#DrawableStates_state_pressed
+ */
+public class AnimatedStateListDrawable extends StateListDrawable {
+    private static final String ELEMENT_TRANSITION = "transition";
+    private static final String ELEMENT_ITEM = "item";
+
+    private AnimatedStateListState mState;
+
+    /** The currently running animation, if any. */
+    private ObjectAnimator mAnim;
+
+    /** Index to be set after the animation ends. */
+    private int mAnimToIndex = -1;
+
+    /** Index away from which we are animating. */
+    private int mAnimFromIndex = -1;
+
+    private boolean mMutated;
+
+    public AnimatedStateListDrawable() {
+        this(null, null);
+    }
+
+    /**
+     * Add a new drawable to the set of keyframes.
+     *
+     * @param stateSet An array of resource IDs to associate with the keyframe
+     * @param drawable The drawable to show when in the specified state
+     * @param id The unique identifier for the keyframe
+     */
+    public void addState(int[] stateSet, Drawable drawable, int id) {
+        if (drawable != null) {
+            mState.addStateSet(stateSet, drawable, id);
+            onStateChange(getState());
+        }
+    }
+
+    /**
+     * Adds a new transition between keyframes.
+     *
+     * @param fromId Unique identifier of the starting keyframe
+     * @param toId Unique identifier of the ending keyframe
+     * @param anim An AnimationDrawable to use as a transition
+     * @param reversible Whether the transition can be reversed
+     */
+    public void addTransition(int fromId, int toId, AnimationDrawable anim, boolean reversible) {
+        mState.addTransition(fromId, toId, anim, reversible);
+    }
+
+    @Override
+    public boolean isStateful() {
+        return true;
+    }
+
+    @Override
+    protected boolean onStateChange(int[] stateSet) {
+        final int keyframeIndex = mState.indexOfKeyframe(stateSet);
+        if (keyframeIndex == getCurrentIndex()) {
+            return false;
+        }
+
+        if (selectTransition(keyframeIndex)) {
+            return true;
+        }
+
+        if (selectDrawable(keyframeIndex)) {
+            return true;
+        }
+
+        return super.onStateChange(stateSet);
+    }
+
+    private boolean selectTransition(int toIndex) {
+        if (mAnim != null) {
+            if (toIndex == mAnimToIndex) {
+                // Already animating to that keyframe.
+                return true;
+            } else if (toIndex == mAnimFromIndex) {
+                // Reverse the current animation.
+                mAnim.reverse();
+                mAnimFromIndex = mAnimToIndex;
+                mAnimToIndex = toIndex;
+                return true;
+            }
+
+            // Changing animation, end the current animation.
+            mAnim.end();
+        }
+
+        final AnimatedStateListState state = mState;
+        final int fromIndex = getCurrentIndex();
+        final int fromId = state.getKeyframeIdAt(fromIndex);
+        final int toId = state.getKeyframeIdAt(toIndex);
+
+        if (toId == 0 || fromId == 0) {
+            // Missing a keyframe ID.
+            return false;
+        }
+
+        final int transitionIndex = state.indexOfTransition(fromId, toId);
+        if (transitionIndex < 0 || !selectDrawable(transitionIndex)) {
+            // Couldn't select a transition.
+            return false;
+        }
+
+        final Drawable d = getCurrent();
+        if (!(d instanceof AnimationDrawable)) {
+            // Transition isn't an animation.
+            return false;
+        }
+
+        final AnimationDrawable ad = (AnimationDrawable) d;
+        final boolean reversed = mState.isTransitionReversed(fromId, toId);
+        final int frameCount = ad.getNumberOfFrames();
+        final int fromFrame = reversed ? frameCount - 1 : 0;
+        final int toFrame = reversed ? 0 : frameCount - 1;
+
+        final FrameInterpolator interp = new FrameInterpolator(ad, reversed);
+        final ObjectAnimator anim = ObjectAnimator.ofInt(ad, "currentIndex", fromFrame, toFrame);
+        anim.setAutoCancel(true);
+        anim.setDuration(interp.getTotalDuration());
+        anim.addListener(mAnimListener);
+        anim.setInterpolator(interp);
+        anim.start();
+
+        mAnim = anim;
+        mAnimFromIndex = fromIndex;
+        mAnimToIndex = toIndex;
+        return true;
+    }
+
+    @Override
+    public void jumpToCurrentState() {
+        super.jumpToCurrentState();
+
+        if (mAnim != null) {
+            mAnim.end();
+        }
+    }
+
+    @Override
+    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+            throws XmlPullParserException, IOException {
+        final TypedArray a = r.obtainAttributes(attrs, R.styleable.AnimatedStateListDrawable);
+
+        super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedStateListDrawable_visible);
+
+        final StateListState stateListState = getStateListState();
+        stateListState.setVariablePadding(a.getBoolean(
+                R.styleable.AnimatedStateListDrawable_variablePadding, false));
+        stateListState.setConstantSize(a.getBoolean(
+                R.styleable.AnimatedStateListDrawable_constantSize, false));
+        stateListState.setEnterFadeDuration(a.getInt(
+                R.styleable.AnimatedStateListDrawable_enterFadeDuration, 0));
+        stateListState.setExitFadeDuration(a.getInt(
+                R.styleable.AnimatedStateListDrawable_exitFadeDuration, 0));
+
+        setDither(a.getBoolean(R.styleable.AnimatedStateListDrawable_dither, true));
+        setAutoMirrored(a.getBoolean(R.styleable.AnimatedStateListDrawable_autoMirrored, false));
+
+        a.recycle();
+
+        int type;
+
+        final int innerDepth = parser.getDepth() + 1;
+        int depth;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && ((depth = parser.getDepth()) >= innerDepth
+                || type != XmlPullParser.END_TAG)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            if (depth > innerDepth) {
+                continue;
+            }
+
+            if (parser.getName().equals(ELEMENT_ITEM)) {
+                parseItem(r, parser, attrs, theme);
+            } else if (parser.getName().equals(ELEMENT_TRANSITION)) {
+                parseTransition(r, parser, attrs, theme);
+            }
+        }
+
+        onStateChange(getState());
+    }
+
+    private int parseTransition(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+            throws XmlPullParserException, IOException {
+        int drawableRes = 0;
+        int fromId = 0;
+        int toId = 0;
+        boolean reversible = false;
+
+        final int numAttrs = attrs.getAttributeCount();
+        for (int i = 0; i < numAttrs; i++) {
+            final int stateResId = attrs.getAttributeNameResource(i);
+            switch (stateResId) {
+                case 0:
+                    break;
+                case R.attr.fromId:
+                    fromId = attrs.getAttributeResourceValue(i, 0);
+                    break;
+                case R.attr.toId:
+                    toId = attrs.getAttributeResourceValue(i, 0);
+                    break;
+                case R.attr.drawable:
+                    drawableRes = attrs.getAttributeResourceValue(i, 0);
+                    break;
+                case R.attr.reversible:
+                    reversible = attrs.getAttributeBooleanValue(i, false);
+                    break;
+            }
+        }
+
+        final Drawable dr;
+        if (drawableRes != 0) {
+            dr = r.getDrawable(drawableRes);
+        } else {
+            int type;
+            while ((type = parser.next()) == XmlPullParser.TEXT) {
+            }
+            if (type != XmlPullParser.START_TAG) {
+                throw new XmlPullParserException(
+                        parser.getPositionDescription()
+                                + ": <item> tag requires a 'drawable' attribute or "
+                                + "child tag defining a drawable");
+            }
+            dr = Drawable.createFromXmlInnerThemed(r, parser, attrs, theme);
+        }
+
+        final AnimationDrawable anim;
+        if (dr instanceof AnimationDrawable) {
+            anim = (AnimationDrawable) dr;
+        } else {
+            throw new XmlPullParserException(parser.getPositionDescription()
+                    + ": <transition> tag requires a 'drawable' attribute or "
+                    + "child tag defining a drawable of type <animation>");
+        }
+
+        return mState.addTransition(fromId, toId, anim, reversible);
+    }
+
+    private int parseItem(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+            throws XmlPullParserException, IOException {
+        int drawableRes = 0;
+        int keyframeId = 0;
+
+        int j = 0;
+        final int numAttrs = attrs.getAttributeCount();
+        int[] states = new int[numAttrs];
+        for (int i = 0; i < numAttrs; i++) {
+            final int stateResId = attrs.getAttributeNameResource(i);
+            switch (stateResId) {
+                case 0:
+                    break;
+                case R.attr.id:
+                    keyframeId = attrs.getAttributeResourceValue(i, 0);
+                    break;
+                case R.attr.drawable:
+                    drawableRes = attrs.getAttributeResourceValue(i, 0);
+                    break;
+                default:
+                    final boolean hasState = attrs.getAttributeBooleanValue(i, false);
+                    states[j++] = hasState ? stateResId : -stateResId;
+            }
+        }
+        states = StateSet.trimStateSet(states, j);
+
+        final Drawable dr;
+        if (drawableRes != 0) {
+            dr = r.getDrawable(drawableRes);
+        } else {
+            int type;
+            while ((type = parser.next()) == XmlPullParser.TEXT) {
+            }
+            if (type != XmlPullParser.START_TAG) {
+                throw new XmlPullParserException(
+                        parser.getPositionDescription()
+                                + ": <item> tag requires a 'drawable' attribute or "
+                                + "child tag defining a drawable");
+            }
+            dr = Drawable.createFromXmlInnerThemed(r, parser, attrs, theme);
+        }
+
+        return mState.addStateSet(states, dr, keyframeId);
+    }
+
+    @Override
+    public Drawable mutate() {
+        if (!mMutated) {
+            final AnimatedStateListState newState = new AnimatedStateListState(mState, this, null);
+            setConstantState(newState);
+            mMutated = true;
+        }
+
+        return this;
+    }
+
+    private final AnimatorListenerAdapter mAnimListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator anim) {
+            selectDrawable(mAnimToIndex);
+
+            mAnimToIndex = -1;
+            mAnimFromIndex = -1;
+            mAnim = null;
+        }
+    };
+
+    static class AnimatedStateListState extends StateListState {
+        private static final int REVERSE_SHIFT = 32;
+        private static final int REVERSE_MASK = 0x1;
+
+        final LongSparseLongArray mTransitions;
+        final SparseIntArray mStateIds;
+
+        AnimatedStateListState(AnimatedStateListState orig, AnimatedStateListDrawable owner,
+                Resources res) {
+            super(orig, owner, res);
+
+            if (orig != null) {
+                mTransitions = orig.mTransitions.clone();
+                mStateIds = orig.mStateIds.clone();
+            } else {
+                mTransitions = new LongSparseLongArray();
+                mStateIds = new SparseIntArray();
+            }
+        }
+
+        int addTransition(int fromId, int toId, AnimationDrawable anim, boolean reversible) {
+            final int pos = super.addChild(anim);
+            final long keyFromTo = generateTransitionKey(fromId, toId);
+            mTransitions.append(keyFromTo, pos);
+
+            if (reversible) {
+                final long keyToFrom = generateTransitionKey(toId, fromId);
+                mTransitions.append(keyToFrom, pos | (1L << REVERSE_SHIFT));
+            }
+
+            return addChild(anim);
+        }
+
+        int addStateSet(int[] stateSet, Drawable drawable, int id) {
+            final int index = super.addStateSet(stateSet, drawable);
+            mStateIds.put(index, id);
+            return index;
+        }
+
+        int indexOfKeyframe(int[] stateSet) {
+            final int index = super.indexOfStateSet(stateSet);
+            if (index >= 0) {
+                return index;
+            }
+
+            return super.indexOfStateSet(StateSet.WILD_CARD);
+        }
+
+        int getKeyframeIdAt(int index) {
+            return index < 0 ? 0 : mStateIds.get(index, 0);
+        }
+
+        int indexOfTransition(int fromId, int toId) {
+            final long keyFromTo = generateTransitionKey(fromId, toId);
+            return (int) mTransitions.get(keyFromTo, -1);
+        }
+
+        boolean isTransitionReversed(int fromId, int toId) {
+            final long keyFromTo = generateTransitionKey(fromId, toId);
+            return (mTransitions.get(keyFromTo, -1) >> REVERSE_SHIFT & REVERSE_MASK) == 1;
+        }
+
+        @Override
+        public Drawable newDrawable() {
+            return new AnimatedStateListDrawable(this, null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new AnimatedStateListDrawable(this, res);
+        }
+
+        private static long generateTransitionKey(int fromId, int toId) {
+            return (long) fromId << 32 | toId;
+        }
+    }
+
+    void setConstantState(AnimatedStateListState state) {
+        super.setConstantState(state);
+
+        mState = state;
+    }
+
+    private AnimatedStateListDrawable(AnimatedStateListState state, Resources res) {
+        super(null);
+
+        final AnimatedStateListState newState = new AnimatedStateListState(state, this, res);
+        setConstantState(newState);
+        onStateChange(getState());
+        jumpToCurrentState();
+    }
+
+    /**
+     * Interpolates between frames with respect to their individual durations.
+     */
+    private static class FrameInterpolator implements TimeInterpolator {
+        private int[] mFrameTimes;
+        private int mFrames;
+        private int mTotalDuration;
+
+        public FrameInterpolator(AnimationDrawable d, boolean reversed) {
+            updateFrames(d, reversed);
+        }
+
+        public int updateFrames(AnimationDrawable d, boolean reversed) {
+            final int N = d.getNumberOfFrames();
+            mFrames = N;
+
+            if (mFrameTimes == null || mFrameTimes.length < N) {
+                mFrameTimes = new int[N];
+            }
+
+            final int[] frameTimes = mFrameTimes;
+            int totalDuration = 0;
+            for (int i = 0; i < N; i++) {
+                final int duration = d.getDuration(reversed ? N - i - 1 : i);
+                frameTimes[i] = duration;
+                totalDuration += duration;
+            }
+
+            mTotalDuration = totalDuration;
+            return totalDuration;
+        }
+
+        public int getTotalDuration() {
+            return mTotalDuration;
+        }
+
+        @Override
+        public float getInterpolation(float input) {
+            final int elapsed = (int) (input * mTotalDuration + 0.5f);
+            final int N = mFrames;
+            final int[] frameTimes = mFrameTimes;
+
+            // Find the current frame and remaining time within that frame.
+            int remaining = elapsed;
+            int i = 0;
+            while (i < N && remaining >= frameTimes[i]) {
+                remaining -= frameTimes[i];
+                i++;
+            }
+
+            // Remaining time is relative of total duration.
+            final float frameElapsed;
+            if (i < N) {
+                frameElapsed = remaining / (float) mTotalDuration;
+            } else {
+                frameElapsed = 0;
+            }
+
+            return i / (float) N + frameElapsed;
+        }
+    }
+}
+
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 3f94e26..da4bc10 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -94,7 +94,7 @@
         boolean changed = super.setVisible(visible, restart);
         if (visible) {
             if (changed || restart) {
-                setFrame(0, true, true);
+                setFrame(0, true, mCurFrame >= 0);
             }
         } else {
             unscheduleSelf(this);
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index b9d5e19..b939636 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -1039,6 +1039,8 @@
         final String name = parser.getName();
         if (name.equals("selector")) {
             drawable = new StateListDrawable();
+        } else if (name.equals("animated-selector")) {
+            drawable = new AnimatedStateListDrawable();
         } else if (name.equals("level-list")) {
             drawable = new LevelListDrawable();
         } else if (name.equals("layer-list")) {
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 1f8b51d..08fc99d 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -359,6 +359,16 @@
                 mDrawableContainerState.getOpacity();
     }
 
+    /** @hide */
+    public void setCurrentIndex(int index) {
+        selectDrawable(index);
+    }
+
+    /** @hide */
+    public int getCurrentIndex() {
+        return mCurIndex;
+    }
+
     public boolean selectDrawable(int idx) {
         if (idx == mCurIndex) {
             return false;
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index e3f57e9..218a057 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -16,20 +16,22 @@
 
 package android.graphics.drawable;
 
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Paint.Style;
 import android.graphics.Rect;
-import android.util.MathUtils;
-import android.view.animation.AnimationUtils;
 import android.view.animation.DecelerateInterpolator;
 
 /**
  * Draws a Quantum Paper ripple.
  */
 class Ripple {
-    private static final TimeInterpolator INTERPOLATOR = new DecelerateInterpolator(2.0f);
+    private static final TimeInterpolator INTERPOLATOR = new DecelerateInterpolator();
 
     /** Starting radius for a ripple. */
     private static final int STARTING_RADIUS_DP = 16;
@@ -37,6 +39,9 @@
     /** Radius when finger is outside view bounds. */
     private static final int OUTSIDE_RADIUS_DP = 16;
 
+    /** Radius when finger is inside view bounds. */
+    private static final int INSIDE_RADIUS_DP = 96;
+
     /** Margin when constraining outside touches (fraction of outer radius). */
     private static final float OUTSIDE_MARGIN = 0.8f;
 
@@ -44,15 +49,53 @@
     private static final float OUTSIDE_RESISTANCE = 0.7f;
 
     /** Minimum alpha value during a pulse animation. */
-    private static final int PULSE_MIN_ALPHA = 128;
+    private static final float PULSE_MIN_ALPHA = 0.5f;
 
+    /** Duration for animating the trailing edge of the ripple. */
+    private static final int EXIT_DURATION = 600;
+
+    /** Duration for animating the leading edge of the ripple. */
+    private static final int ENTER_DURATION = 400;
+
+    /** Duration for animating the ripple alpha in and out. */
+    private static final int FADE_DURATION = 50;
+
+    /** Minimum elapsed time between start of enter and exit animations. */
+    private static final int EXIT_MIN_DELAY = 200;
+
+    /** Duration for animating between inside and outside touch. */
+    private static final int OUTSIDE_DURATION = 300;
+
+    /** Duration for animating pulses. */
+    private static final int PULSE_DURATION = 400;
+
+    /** Interval between pulses while inside and fully entered. */
+    private static final int PULSE_INTERVAL = 400;
+
+    /** Delay before pulses start. */
+    private static final int PULSE_DELAY = 500;
+
+    private final Drawable mOwner;
+
+    /** Bounds used for computing max radius and containment. */
     private final Rect mBounds;
-    private final Rect mPadding;
 
-    private RippleAnimator mAnimator;
+    /** Configured maximum ripple radius when the center is outside the bounds. */
+    private final int mMaxOutsideRadius;
 
-    private int mMinRadius;
-    private int mOutsideRadius;
+    /** Configured maximum ripple radius. */
+    private final int mMaxInsideRadius;
+
+    private ObjectAnimator mOuter;
+    private ObjectAnimator mInner;
+    private ObjectAnimator mAlpha;
+
+    /** Maximum ripple radius. */
+    private int mMaxRadius;
+
+    private float mOuterRadius;
+    private float mInnerRadius;
+    private float mAlphaMultiplier;
 
     /** Center x-coordinate. */
     private float mX;
@@ -61,46 +104,151 @@
     private float mY;
 
     /** Whether the center is within the parent bounds. */
-    private boolean mInside;
+    private boolean mInsideBounds;
 
     /** Whether to pulse this ripple. */
-    boolean mPulse;
-    
-    /** Enter state. A value in [0...1] or -1 if not set. */
-    float mEnterState = -1;
+    private boolean mPulseEnabled;
 
-    /** Exit state. A value in [0...1] or -1 if not set. */
-    float mExitState = -1;
+    /** Temporary hack since we can't check finished state of animator. */
+    private boolean mExitFinished;
 
-    /** Outside state. A value in [0...1] or -1 if not set. */
-    float mOutsideState = -1;
-
-    /** Pulse state. A value in [0...1] or -1 if not set. */
-    float mPulseState = -1;
+    /** Whether this ripple has ever moved. */
+    private boolean mHasMoved;
 
     /**
-     * Creates a new ripple with the specified parent bounds, padding, initial
-     * position, and screen density.
+     * Creates a new ripple.
      */
-    public Ripple(Rect bounds, Rect padding, float x, float y, float density, boolean pulse) {
+    public Ripple(Drawable owner, Rect bounds, float density, boolean pulseEnabled) {
+        mOwner = owner;
         mBounds = bounds;
-        mPadding = padding;
-        mInside = mBounds.contains((int) x, (int) y);
-        mPulse = pulse;
+        mPulseEnabled = pulseEnabled;
 
-        mX = x;
-        mY = y;
+        mOuterRadius = (int) (density * STARTING_RADIUS_DP + 0.5f);
+        mMaxOutsideRadius = (int) (density * OUTSIDE_RADIUS_DP + 0.5f);
+        mMaxInsideRadius = (int) (density * INSIDE_RADIUS_DP + 0.5f);
+        mMaxRadius = Math.min(mMaxInsideRadius, Math.max(bounds.width(), bounds.height()));
+    }
 
-        mMinRadius = (int) (density * STARTING_RADIUS_DP + 0.5f);
-        mOutsideRadius = (int) (density * OUTSIDE_RADIUS_DP + 0.5f);
+    public void setOuterRadius(float r) {
+        mOuterRadius = r;
+        invalidateSelf();
     }
-    
-    public void setMinRadius(int minRadius) {
-        mMinRadius = minRadius;
+
+    public float getOuterRadius() {
+        return mOuterRadius;
     }
-    
-    public void setOutsideRadius(int outsideRadius) {
-        mOutsideRadius = outsideRadius;
+
+    public void setInnerRadius(float r) {
+        mInnerRadius = r;
+        invalidateSelf();
+    }
+
+    public float getInnerRadius() {
+        return mInnerRadius;
+    }
+
+    public void setAlphaMultiplier(float a) {
+        mAlphaMultiplier = a;
+        invalidateSelf();
+    }
+
+    public float getAlphaMultiplier() {
+        return mAlphaMultiplier;
+    }
+
+    /**
+     * Returns whether this ripple has finished exiting.
+     */
+    public boolean isFinished() {
+        return mExitFinished;
+    }
+
+    /**
+     * Called when the bounds change.
+     */
+    public void onBoundsChanged() {
+        mMaxRadius = Math.min(mMaxInsideRadius, Math.max(mBounds.width(), mBounds.height()));
+
+        updateInsideBounds();
+    }
+
+    private void updateInsideBounds() {
+        final boolean insideBounds = mBounds.contains((int) (mX + 0.5f), (int) (mY + 0.5f));
+        if (mInsideBounds != insideBounds || !mHasMoved) {
+            mInsideBounds = insideBounds;
+            mHasMoved = true;
+
+            if (insideBounds) {
+                enter();
+            } else {
+                outside();
+            }
+        }
+    }
+
+    /**
+     * Draws the ripple using the specified paint.
+     */
+    public boolean draw(Canvas c, Paint p) {
+        final Rect bounds = mBounds;
+        final float outerRadius = mOuterRadius;
+        final float innerRadius = mInnerRadius;
+        final float alphaMultiplier = mAlphaMultiplier;
+
+        // Cache the paint alpha so we can restore it later.
+        final int paintAlpha = p.getAlpha();
+        final int alpha = (int) (paintAlpha * alphaMultiplier + 0.5f);
+
+        // Apply resistance effect when outside bounds.
+        final float x;
+        final float y;
+        if (mInsideBounds) {
+            x = mX;
+            y = mY;
+        } else {
+            // TODO: We need to do this outside of draw() so that our dirty
+            // bounds accurately reflect resistance.
+            x = looseConstrain(mX, bounds.left, bounds.right,
+                    mOuterRadius * OUTSIDE_MARGIN, OUTSIDE_RESISTANCE);
+            y = looseConstrain(mY, bounds.top, bounds.bottom,
+                    mOuterRadius * OUTSIDE_MARGIN, OUTSIDE_RESISTANCE);
+        }
+
+        final boolean hasContent;
+        if (alphaMultiplier <= 0 || innerRadius >= outerRadius) {
+            // Nothing to draw.
+            hasContent = false;
+        } else if (innerRadius > 0) {
+            // Draw a ring.
+            final float strokeWidth = outerRadius - innerRadius;
+            final float strokeRadius = innerRadius + strokeWidth / 2.0f;
+            p.setAlpha(alpha);
+            p.setStyle(Style.STROKE);
+            p.setStrokeWidth(strokeWidth);
+            c.drawCircle(x, y, strokeRadius, p);
+            hasContent = true;
+        } else if (outerRadius > 0) {
+            // Draw a circle.
+            p.setAlpha(alpha);
+            p.setStyle(Style.FILL);
+            c.drawCircle(x, y, outerRadius, p);
+            hasContent = true;
+        } else {
+            hasContent = false;
+        }
+
+        p.setAlpha(paintAlpha);
+        return hasContent;
+    }
+
+    /**
+     * Returns the maximum bounds for this ripple.
+     */
+    public void getBounds(Rect bounds) {
+        final int x = (int) mX;
+        final int y = (int) mY;
+        final int maxRadius = mMaxRadius;
+        bounds.set(x - maxRadius, y - maxRadius, x + maxRadius, y + maxRadius);
     }
 
     /**
@@ -110,117 +258,116 @@
         mX = x;
         mY = y;
 
-        final boolean inside = mBounds.contains((int) x, (int) y);
-        if (mInside != inside) {
-            if (mAnimator != null) {
-                mAnimator.outside();
-            }
-            mInside = inside;
+        updateInsideBounds();
+        invalidateSelf();
+    }
+
+    /**
+     * Starts the exit animation. If {@link #enter()} was called recently, the
+     * animation may be postponed.
+     */
+    public void exit() {
+        mExitFinished = false;
+
+        final ObjectAnimator inner = ObjectAnimator.ofFloat(this, "innerRadius", 0, mMaxRadius);
+        inner.setAutoCancel(true);
+        inner.setDuration(EXIT_DURATION);
+        inner.setInterpolator(INTERPOLATOR);
+        inner.addListener(mAnimationListener);
+
+        if (mOuter != null && mOuter.isStarted()) {
+            // If we haven't been running the enter animation for long enough,
+            // delay the exit animator.
+            final int elapsed = (int) (mOuter.getAnimatedFraction() * mOuter.getDuration());
+            final int delay = Math.max(0, EXIT_MIN_DELAY - elapsed);
+            inner.setStartDelay(delay);
+        }
+
+        inner.start();
+
+        final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 0);
+        alpha.setAutoCancel(true);
+        alpha.setDuration(EXIT_DURATION);
+        alpha.start();
+
+        mInner = inner;
+        mAlpha = alpha;
+    }
+
+    /**
+     * Cancel all animations.
+     */
+    public void cancel() {
+        if (mInner != null) {
+            mInner.cancel();
+        }
+
+        if (mOuter != null) {
+            mOuter.cancel();
+        }
+
+        if (mAlpha != null) {
+            mAlpha.cancel();
         }
     }
 
-    public void onBoundsChanged() {
-        final boolean inside = mBounds.contains((int) mX, (int) mY);
-        if (mInside != inside) {
-            if (mAnimator != null) {
-                mAnimator.outside();
-            }
-            mInside = inside;
-        }
+    private void invalidateSelf() {
+        mOwner.invalidateSelf();
     }
 
-    public RippleAnimator animate() {
-        if (mAnimator == null) {
-            mAnimator = new RippleAnimator(this);
-        }
-        return mAnimator;
-    }
+    /**
+     * Starts the enter animation.
+     */
+    private void enter() {
+        final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerRadius", mMaxRadius);
+        outer.setAutoCancel(true);
+        outer.setDuration(ENTER_DURATION);
+        outer.setInterpolator(INTERPOLATOR);
+        outer.start();
 
-    public boolean draw(Canvas c, Paint p) {
-        final Rect bounds = mBounds;
-        final Rect padding = mPadding;
-        final float dX = Math.max(mX - bounds.left, bounds.right - mX);
-        final float dY = Math.max(mY - bounds.top, bounds.bottom - mY);
-        final int maxRadius = (int) Math.ceil(Math.sqrt(dX * dX + dY * dY));
+        final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 1);
+        if (mPulseEnabled) {
+            alpha.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    final ObjectAnimator pulse = ObjectAnimator.ofFloat(
+                            this, "alphaMultiplier", 1, PULSE_MIN_ALPHA);
+                    pulse.setAutoCancel(true);
+                    pulse.setDuration(PULSE_DURATION + PULSE_INTERVAL);
+                    pulse.setRepeatCount(ObjectAnimator.INFINITE);
+                    pulse.setRepeatMode(ObjectAnimator.REVERSE);
+                    pulse.setStartDelay(PULSE_DELAY);
+                    pulse.start();
 
-        final float enterState = mEnterState;
-        final float exitState = mExitState;
-        final float outsideState = mOutsideState;
-        final float pulseState = mPulseState;
-        final float insideRadius = MathUtils.lerp(mMinRadius, maxRadius, enterState);
-        final float outerRadius = MathUtils.lerp(mOutsideRadius, insideRadius,
-                mInside ? outsideState : 1 - outsideState);
-
-        // Apply resistance effect when outside bounds.
-        final float x = looseConstrain(mX, bounds.left + padding.left, bounds.right - padding.right,
-                outerRadius * OUTSIDE_MARGIN, OUTSIDE_RESISTANCE);
-        final float y = looseConstrain(mY, bounds.top + padding.top, bounds.bottom - padding.bottom,
-                outerRadius * OUTSIDE_MARGIN, OUTSIDE_RESISTANCE);
-
-        // Compute maximum alpha, taking pulse into account when active.
-        final int maxAlpha;
-        if (pulseState < 0 || pulseState >= 1) {
-            maxAlpha = 255;
-        } else {
-            final float pulseAlpha;
-            if (pulseState > 0.5) {
-                // Pulsing in to max alpha.
-                pulseAlpha = MathUtils.lerp(PULSE_MIN_ALPHA, 255, (pulseState - .5f) * 2);
-            } else {
-                // Pulsing out to min alpha.
-                pulseAlpha = MathUtils.lerp(255, PULSE_MIN_ALPHA, pulseState * 2f);
-            }
-
-            if (exitState > 0) {
-                // Animating exit, interpolate pulse with exit state.
-                maxAlpha = (int) (MathUtils.lerp(255, pulseAlpha, exitState) + 0.5f);
-            } else if (mInside) {
-                // No animation, no need to interpolate.
-                maxAlpha = (int) (pulseAlpha + 0.5f);
-            } else {
-                // Animating inside, interpolate pulse with inside state.
-                maxAlpha = (int) (MathUtils.lerp(pulseAlpha, 255, outsideState) + 0.5f);
-            }
-        }
-
-        if (maxAlpha > 0) {
-            if (exitState <= 0) {
-                // Exit state isn't showing, so we can simplify to a solid
-                // circle.
-                if (outerRadius > 0) {
-                    p.setAlpha(maxAlpha);
-                    p.setStyle(Style.FILL);
-                    c.drawCircle(x, y, outerRadius, p);
-                    return true;
+                    mAlpha = pulse;
                 }
-            } else {
-                // Both states are showing, so we need a circular stroke.
-                final float innerRadius = MathUtils.lerp(0, outerRadius, exitState);
-                final float strokeWidth = outerRadius - innerRadius;
-                if (strokeWidth > 0) {
-                    final float strokeRadius = innerRadius + strokeWidth / 2f;
-                    final int alpha = (int) (MathUtils.lerp(maxAlpha, 0, exitState) + 0.5f);
-                    if (alpha > 0) {
-                        p.setAlpha(alpha);
-                        p.setStyle(Style.STROKE);
-                        p.setStrokeWidth(strokeWidth);
-                        c.drawCircle(x, y, strokeRadius, p);
-                        return true;
-                    }
-                }
-            }
+            });
         }
+        alpha.setAutoCancel(true);
+        alpha.setDuration(FADE_DURATION);
+        alpha.start();
 
-        return false;
+        mOuter = outer;
+        mAlpha = alpha;
     }
 
-    public void getBounds(Rect bounds) {
-        final int x = (int) mX;
-        final int y = (int) mY;
-        final int dX = Math.max(x, mBounds.right - x);
-        final int dY = Math.max(x, mBounds.bottom - y);
-        final int maxRadius = (int) Math.ceil(Math.sqrt(dX * dX + dY * dY));
-        bounds.set(x - maxRadius, y - maxRadius, x + maxRadius, y + maxRadius);
+    /**
+     * Starts the outside transition animation.
+     */
+    private void outside() {
+        final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerRadius", mMaxOutsideRadius);
+        outer.setAutoCancel(true);
+        outer.setDuration(OUTSIDE_DURATION);
+        outer.setInterpolator(INTERPOLATOR);
+        outer.start();
+
+        final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 1);
+        alpha.setAutoCancel(true);
+        alpha.setDuration(FADE_DURATION);
+        alpha.start();
+
+        mOuter = outer;
+        mAlpha = alpha;
     }
 
     /**
@@ -229,6 +376,7 @@
      */
     private static float looseConstrain(float value, float min, float max, float margin,
             float factor) {
+        // TODO: Can we use actual spring physics here?
         if (value < min) {
             return min - Math.min(margin, (float) Math.pow(min - value, factor));
         } else if (value > max) {
@@ -237,96 +385,16 @@
             return value;
         }
     }
-    
-    public static class RippleAnimator {
-        /** Duration for animating the trailing edge of the ripple. */
-        private static final int EXIT_DURATION = 600;
 
-        /** Duration for animating the leading edge of the ripple. */
-        private static final int ENTER_DURATION = 400;
-
-        /** Minimum elapsed time between start of enter and exit animations. */
-        private static final int EXIT_MIN_DELAY = 200;
-
-        /** Duration for animating between inside and outside touch. */
-        private static final int OUTSIDE_DURATION = 300;
-
-        /** Duration for animating pulses. */
-        private static final int PULSE_DURATION = 400;
-
-        /** Interval between pulses while inside and fully entered. */
-        private static final int PULSE_INTERVAL = 400;
-
-        /** Delay before pulses start. */
-        private static final int PULSE_DELAY = 500;
-
-        /** The target ripple being animated. */
-        private final Ripple mTarget;
-
-        /** When the ripple started appearing. */
-        private long mEnterTime = -1;
-
-        /** When the ripple started vanishing. */
-        private long mExitTime = -1;
-
-        /** When the ripple last transitioned between inside and outside touch. */
-        private long mOutsideTime = -1;
-
-        public RippleAnimator(Ripple target) {
-            mTarget = target;
-        }
-
-        /**
-         * Starts the enter animation.
-         */
-        public void enter() {
-            mEnterTime = AnimationUtils.currentAnimationTimeMillis();
-        }
-
-        /**
-         * Starts the exit animation. If {@link #enter()} was called recently, the
-         * animation may be postponed.
-         */
-        public void exit() {
-            final long minTime = mEnterTime + EXIT_MIN_DELAY;
-            mExitTime = Math.max(minTime, AnimationUtils.currentAnimationTimeMillis());
-        }
-
-        /**
-         * Starts the outside transition animation.
-         */
-        public void outside() {
-            mOutsideTime = AnimationUtils.currentAnimationTimeMillis();
-        }
-
-        /**
-         * Returns whether this ripple is currently animating.
-         */
-        public boolean isRunning() {
-            final long currentTime = AnimationUtils.currentAnimationTimeMillis();
-            return mEnterTime >= 0 && mEnterTime <= currentTime
-                    && (mExitTime < 0 || currentTime <= mExitTime + EXIT_DURATION);
-        }
-
-        public void update() {
-            // Track three states:
-            // - Enter: touch begins, affects outer radius
-            // - Outside: touch moves outside bounds, affects maximum outer radius
-            // - Exit: touch ends, affects inner radius
-            final long currentTime = AnimationUtils.currentAnimationTimeMillis();
-            mTarget.mEnterState = mEnterTime < 0 ? 0 : INTERPOLATOR.getInterpolation(
-                    MathUtils.constrain((currentTime - mEnterTime) / (float) ENTER_DURATION, 0, 1));
-            mTarget.mExitState = mExitTime < 0 ? 0 : INTERPOLATOR.getInterpolation(
-                    MathUtils.constrain((currentTime - mExitTime) / (float) EXIT_DURATION, 0, 1));
-            mTarget.mOutsideState = mOutsideTime < 0 ? 1 : INTERPOLATOR.getInterpolation(
-                    MathUtils.constrain((currentTime - mOutsideTime) / (float) OUTSIDE_DURATION, 0, 1));
-
-            // Pulse is a little more complicated.
-            if (mTarget.mPulse) {
-                final long pulseTime = (currentTime - mEnterTime - ENTER_DURATION - PULSE_DELAY);
-                mTarget.mPulseState = pulseTime < 0 ? -1
-                        : (pulseTime % (PULSE_INTERVAL + PULSE_DURATION)) / (float) PULSE_DURATION;
+    private final AnimatorListener mAnimationListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            if (animation == mInner) {
+                mExitFinished = true;
+                mOuterRadius = 0;
+                mInnerRadius = 0;
+                mAlphaMultiplier = 1;
             }
         }
-    }
+    };
 }
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 61b1b85..99ab4dd 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -237,7 +237,7 @@
         paint.setAlpha(modulateAlpha(prevAlpha, state.mAlpha));
 
         // only draw shape if it may affect output
-        if (paint.getAlpha() != 0 || paint.getXfermode() != null || paint.hasShadow) {
+        if (paint.getAlpha() != 0 || paint.getXfermode() != null || paint.hasShadowLayer()) {
             final boolean clearColorFilter;
             if (mTintFilter != null && paint.getColorFilter() == null) {
                 paint.setColorFilter(mTintFilter);
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index 271af2b..f22a063 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -55,8 +55,9 @@
  * @attr ref android.R.styleable#DrawableStates_state_pressed
  */
 public class StateListDrawable extends DrawableContainer {
+    private static final String TAG = StateListDrawable.class.getSimpleName();
+
     private static final boolean DEBUG = false;
-    private static final String TAG = "StateListDrawable";
 
     /**
      * To be proper, we should have a getter for dither (and alpha, etc.)
@@ -69,7 +70,8 @@
      * to improve the quality at negligible cost.
      */
     private static final boolean DEFAULT_DITHER = true;
-    private final StateListState mStateListState;
+
+    private StateListState mStateListState;
     private boolean mMutated;
 
     public StateListDrawable() {
@@ -274,7 +276,7 @@
         mStateListState.setLayoutDirection(layoutDirection);
     }
 
-    static final class StateListState extends DrawableContainerState {
+    static class StateListState extends DrawableContainerState {
         int[][] mStateSets;
 
         StateListState(StateListState orig, StateListDrawable owner, Resources res) {
@@ -293,7 +295,7 @@
             return pos;
         }
 
-        private int indexOfStateSet(int[] stateSet) {
+        int indexOfStateSet(int[] stateSet) {
             final int[][] stateSets = mStateSets;
             final int N = getChildCount();
             for (int i = 0; i < N; i++) {
@@ -323,11 +325,26 @@
         }
     }
 
+    void setConstantState(StateListState state) {
+        super.setConstantState(state);
+
+        mStateListState = state;
+    }
+
     private StateListDrawable(StateListState state, Resources res) {
-        StateListState as = new StateListState(state, this, res);
-        mStateListState = as;
-        setConstantState(as);
+        final StateListState newState = new StateListState(state, this, res);
+        setConstantState(newState);
         onStateChange(getState());
     }
+
+    /**
+     * This constructor exists so subclasses can avoid calling the default
+     * constructor and setting up a StateListDrawable-specific constant state.
+     */
+    StateListDrawable(StateListState state) {
+        if (state != null) {
+            setConstantState(state);
+        }
+    }
 }
 
diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
index 0e8831f..0097183 100644
--- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -27,8 +27,6 @@
 import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
-import android.graphics.drawable.Ripple.RippleAnimator;
-import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -40,7 +38,6 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
-import java.util.Arrays;
 
 /**
  * Documentation pending.
@@ -54,7 +51,6 @@
     private static final int MAX_RIPPLES = 10;
 
     private final Rect mTempRect = new Rect();
-    private final Rect mPaddingRect = new Rect();
 
     /** Current ripple effect bounds, used to constrain ripple effects. */
     private final Rect mHotspotBounds = new Rect();
@@ -68,14 +64,11 @@
     private final TouchFeedbackState mState;
 
     /** Lazily-created map of touch hotspot IDs to ripples. */
-    private SparseArray<Ripple> mTouchedRipples;
+    private SparseArray<Ripple> mRipples;
 
     /** Lazily-created array of actively animating ripples. */
-    private Ripple[] mActiveRipples;
-    private int mActiveRipplesCount = 0;
-
-    /** Lazily-created runnable for scheduling invalidation. */
-    private Runnable mAnimationRunnable;
+    private Ripple[] mAnimatingRipples;
+    private int mAnimatingRipplesCount = 0;
 
     /** Paint used to control appearance of ripples. */
     private Paint mRipplePaint;
@@ -86,9 +79,6 @@
     /** Target density of the display into which ripples are drawn. */
     private float mDensity = 1.0f;
 
-    /** Whether the animation runnable has been posted. */
-    private boolean mAnimating;
-
     /** Whether bounds are being overridden. */
     private boolean mOverrideBounds;
 
@@ -154,28 +144,19 @@
     private void onHotspotBoundsChange() {
         final int x = mHotspotBounds.centerX();
         final int y = mHotspotBounds.centerY();
-        final int N = mActiveRipplesCount;
+        final int N = mAnimatingRipplesCount;
         for (int i = 0; i < N; i++) {
             if (mState.mPinned) {
-                mActiveRipples[i].move(x, y);
+                mAnimatingRipples[i].move(x, y);
             }
-            mActiveRipples[i].onBoundsChanged();
+            mAnimatingRipples[i].onBoundsChanged();
         }
     }
 
     @Override
     public boolean setVisible(boolean visible, boolean restart) {
         if (!visible) {
-            if (mTouchedRipples != null) {
-                mTouchedRipples.clear();
-            }
-
-            if (mActiveRipplesCount > 0) {
-                Arrays.fill(mActiveRipples, null);
-                mActiveRipplesCount = 0;
-                mAnimating = false;
-                unscheduleSelf(mAnimationRunnable);
-            }
+            clearHotspots();
         }
 
         return super.setVisible(visible, restart);
@@ -348,21 +329,18 @@
 
     @Override
     public void setHotspot(int id, float x, float y) {
-        if (mTouchedRipples == null) {
-            mTouchedRipples = new SparseArray<Ripple>();
-            mActiveRipples = new Ripple[MAX_RIPPLES];
+        if (mRipples == null) {
+            mRipples = new SparseArray<Ripple>();
+            mAnimatingRipples = new Ripple[MAX_RIPPLES];
         }
 
-        if (mActiveRipplesCount >= MAX_RIPPLES) {
+        if (mAnimatingRipplesCount >= MAX_RIPPLES) {
             Log.e(LOG_TAG, "Max ripple count exceeded", new RuntimeException());
             return;
         }
 
-        final Ripple ripple = mTouchedRipples.get(id);
+        final Ripple ripple = mRipples.get(id);
         if (ripple == null) {
-            final Rect padding = mPaddingRect;
-            getPadding(padding);
-
             final Rect bounds = mHotspotBounds;
             if (mState.mPinned) {
                 x = bounds.exactCenterX();
@@ -371,11 +349,11 @@
 
             // TODO: Clean this up in the API.
             final boolean pulse = (id != R.attr.state_focused);
-            final Ripple newRipple = new Ripple(bounds, padding, x, y, mDensity, pulse);
-            newRipple.animate().enter();
+            final Ripple newRipple = new Ripple(this, bounds, mDensity, pulse);
+            newRipple.move(x, y);
 
-            mActiveRipples[mActiveRipplesCount++] = newRipple;
-            mTouchedRipples.put(id, newRipple);
+            mAnimatingRipples[mAnimatingRipplesCount++] = newRipple;
+            mRipples.put(id, newRipple);
         } else if (mState.mPinned) {
             final Rect bounds = mHotspotBounds;
             x = bounds.exactCenterX();
@@ -384,41 +362,37 @@
         } else {
             ripple.move(x, y);
         }
-
-        scheduleAnimation();
     }
 
     @Override
     public void removeHotspot(int id) {
-        if (mTouchedRipples == null) {
+        if (mRipples == null) {
             return;
         }
 
-        final Ripple ripple = mTouchedRipples.get(id);
+        final Ripple ripple = mRipples.get(id);
         if (ripple != null) {
-            ripple.animate().exit();
+            ripple.exit();
 
-            mTouchedRipples.remove(id);
-            scheduleAnimation();
+            mRipples.remove(id);
         }
     }
 
     @Override
     public void clearHotspots() {
-        if (mTouchedRipples == null) {
-            return;
+        if (mRipples != null) {
+            mRipples.clear();
         }
 
-        final int n = mTouchedRipples.size();
-        for (int i = 0; i < n; i++) {
-            // TODO: Use a fast exit, maybe just fade out?
-            mTouchedRipples.valueAt(i).animate().exit();
+        final int count = mAnimatingRipplesCount;
+        final Ripple[] ripples = mAnimatingRipples;
+        for (int i = 0; i < count; i++) {
+            ripples[i].cancel();
+            ripples[i] = null;
         }
 
-        if (n > 0) {
-            mTouchedRipples.clear();
-            scheduleAnimation();
-        }
+        mAnimatingRipplesCount = 0;
+        invalidateSelf();
     }
 
     /**
@@ -431,30 +405,6 @@
         onHotspotBoundsChange();
     }
 
-    /**
-     * Schedules the next animation, if necessary.
-     */
-    private void scheduleAnimation() {
-        if (mActiveRipplesCount == 0) {
-            mAnimating = false;
-        } else if (!mAnimating) {
-            mAnimating = true;
-
-            if (mAnimationRunnable == null) {
-                mAnimationRunnable = new Runnable() {
-                    @Override
-                    public void run() {
-                        mAnimating = false;
-                        scheduleAnimation();
-                        invalidateSelf();
-                    }
-                };
-            }
-
-            scheduleSelf(mAnimationRunnable, SystemClock.uptimeMillis() + 1000 / 60);
-        }
-    }
-
     @Override
     public void draw(Canvas canvas) {
         final int N = mLayerState.mNum;
@@ -501,12 +451,12 @@
     }
 
     private int drawRippleLayer(Canvas canvas, Rect bounds, boolean maskOnly) {
-        final int ripplesCount = mActiveRipplesCount;
-        if (ripplesCount == 0) {
+        final int count = mAnimatingRipplesCount;
+        if (count == 0) {
             return -1;
         }
 
-        final Ripple[] activeRipples = mActiveRipples;
+        final Ripple[] ripples = mAnimatingRipples;
         final boolean projected = isProjected();
         final Rect layerBounds = projected ? getDirtyBounds() : bounds;
 
@@ -529,17 +479,15 @@
 
         boolean drewRipples = false;
         int restoreToCount = -1;
-        int activeRipplesCount = 0;
+        int animatingCount = 0;
 
-        // Draw ripples.
-        for (int i = 0; i < ripplesCount; i++) {
-            final Ripple ripple = activeRipples[i];
-            final RippleAnimator animator = ripple.animate();
-            animator.update();
+        // Draw ripples and update the animating ripples array.
+        for (int i = 0; i < count; i++) {
+            final Ripple ripple = ripples[i];
 
-            // Mark and skip inactive ripples.
-            if (!animator.isRunning()) {
-                activeRipples[i] = null;
+            // Mark and skip finished ripples.
+            if (ripple.isFinished()) {
+                ripples[i] = null;
                 continue;
             }
 
@@ -565,11 +513,11 @@
 
             drewRipples |= ripple.draw(canvas, ripplePaint);
 
-            activeRipples[activeRipplesCount] = activeRipples[i];
-            activeRipplesCount++;
+            ripples[animatingCount] = ripples[i];
+            animatingCount++;
         }
 
-        mActiveRipplesCount = activeRipplesCount;
+        mAnimatingRipplesCount = animatingCount;
 
         // If we created a layer with no content, merge it immediately.
         if (restoreToCount >= 0 && !drewRipples) {
@@ -596,8 +544,8 @@
         drawingBounds.setEmpty();
 
         final Rect rippleBounds = mTempRect;
-        final Ripple[] activeRipples = mActiveRipples;
-        final int N = mActiveRipplesCount;
+        final Ripple[] activeRipples = mAnimatingRipples;
+        final int N = mAnimatingRipplesCount;
         for (int i = 0; i < N; i++) {
             activeRipples[i].getBounds(rippleBounds);
             drawingBounds.union(rippleBounds);
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 0992717..2da8615 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -14,8 +14,6 @@
 
 package android.graphics.drawable;
 
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
@@ -31,9 +29,6 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Xml;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
 
 import com.android.internal.R;
 
@@ -46,18 +41,15 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.HashSet;
 
 /**
  * This lets you create a drawable based on an XML vector graphic It can be
  * defined in an XML file with the <code>&lt;vector></code> element.
  * <p/>
- * The vector drawable has 6 elements:
+ * The vector drawable has the following elements:
  * <p/>
  * <dl>
  * <dt><code>&lt;vector></code></dt>
- * <dd>The attribute <code>android:trigger</code> defines a state change that
- * will drive the animation</dd>
  * <dd>The attribute <code>android:versionCode</code> defines the version of
  * VectorDrawable</dd>
  * <dt><code>&lt;size></code></dt>
@@ -67,16 +59,15 @@
  * <dd>Used to defined the size of the virtual canvas the paths are drawn on.
  * The size is defined using the attributes <code>android:viewportHeight</code>
  * <code>android:viewportWidth</code></dd>
- * <dt><code>&lt;group></code></dt>
- * <dd>Defines a "key frame" in the animation if there is only one group the
- * drawable is static 2D image that has no animation.</dd>
  * <dt><code>&lt;path></code></dt>
- * <dd>Defines paths to be drawn. The path elements must be within a group
+ * <dd>Defines paths to be drawn. Multiple paths can be defined in one xml file.
+ * The paths are drawn in the order of their definition order.
  * <dl>
  * <dt><code>android:name</code>
  * <dd>Defines the name of the path.</dd></dt>
  * <dt><code>android:pathData</code>
- * <dd>Defines path string.</dd></dt>
+ * <dd>Defines path string. This is using exactly same format as "d" attribute
+ * in the SVG's path data</dd></dt>
  * <dt><code>android:fill</code>
  * <dd>Defines the color to fill the path (none if not present).</dd></dt>
  * <dt><code>android:stroke</code>
@@ -109,48 +100,6 @@
  * <dd>Sets the lineJoin for a stroked path: miter,round,bevel</dd></dt>
  * <dt><code>android:strokeMiterLimit</code>
  * <dd>Sets the Miter limit for a stroked path</dd></dt>
- * <dt><code>android:state_pressed</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_focused</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_selected</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_window_focused</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_enabled</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_activated</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_accelerated</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_hovered</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_checked</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_checkable</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * </dl>
- * </dd>
- * <dt><code>&lt;animation></code></dt>
- * <dd>Used to customize the transition between two paths
- * <dl>
- * <dt><code>android:sequence</code>
- * <dd>Configures this animation sequence between the named paths.</dd></dt>
- * <dt><code>android:limitTo</code>
- * <dd>Limits an animation to only interpolate the selected variable unlimited,
- * path, rotation, trimPathStart, trimPathEnd, trimPathOffset</dd></dt>
- * <dt><code>android:repeatCount</code>
- * <dd>Number of times to loop this aspect of the animation</dd></dt>
- * <dt><code>android:durations</code>
- * <dd>The duration of each step in the animation in milliseconds Must contain
- * the number of named paths - 1</dd></dt>
- * <dt><code>android:startDelay</code>
- * <dd></dd></dt>
- * <dt><code>android:repeatStyle</code>
- * <dd>when repeating how does it repeat back and forth or a to b: forward,
- * inAndOut</dd></dt>
- * <dt><code>android:animate</code>
- * <dd>linear, accelerate, decelerate, easing</dd></dt>
  * </dl>
  * </dd>
  */
@@ -159,10 +108,7 @@
 
     private static final String SHAPE_SIZE = "size";
     private static final String SHAPE_VIEWPORT = "viewport";
-    private static final String SHAPE_GROUP = "group";
     private static final String SHAPE_PATH = "path";
-    private static final String SHAPE_TRANSITION = "transition";
-    private static final String SHAPE_ANIMATION = "animation";
     private static final String SHAPE_VECTOR = "vector";
 
     private static final int LINECAP_BUTT = 0;
@@ -173,37 +119,20 @@
     private static final int LINEJOIN_ROUND = 1;
     private static final int LINEJOIN_BEVEL = 2;
 
-    private static final int DEFAULT_DURATION = 1000;
-    private static final long DEFAULT_INFINITE_DURATION = 60 * 60 * 1000;
-
     private final VectorDrawableState mVectorState;
 
     private int mAlpha = 0xFF;
 
     public VectorDrawable() {
         mVectorState = new VectorDrawableState(null);
-        mVectorState.mBasicAnimator = ObjectAnimator.ofFloat(this, "AnimationFraction", 0, 0);
-
-        setDuration(DEFAULT_DURATION);
     }
 
     private VectorDrawable(VectorDrawableState state, Resources res, Theme theme) {
         mVectorState = new VectorDrawableState(state);
-        mVectorState.mBasicAnimator = ObjectAnimator.ofFloat(this, "AnimationFraction", 0, 0);
 
         if (theme != null && canApplyTheme()) {
             applyTheme(theme);
         }
-
-        long duration = mVectorState.mVAnimatedPath.getTotalAnimationDuration();
-        if (duration == -1) {
-            // If duration is infinite, set to 1 hour.
-            // TODO: Define correct approach for infinite.
-            duration = DEFAULT_INFINITE_DURATION;
-            mVectorState.mBasicAnimator.setFloatValues(0, duration / 1000);
-            mVectorState.mBasicAnimator.setInterpolator(new LinearInterpolator());
-        }
-        setDuration(duration);
     }
 
     @Override
@@ -212,123 +141,11 @@
     }
 
     @Override
-    public void jumpToCurrentState() {
-        stop();
-    }
-
-    /**
-     * Starts the animation.
-     */
-    public void start() {
-        mVectorState.mBasicAnimator.start();
-    }
-
-    /**
-     * Stops the animation and moves to the end state.
-     */
-    public void stop() {
-        mVectorState.mBasicAnimator.end();
-    }
-
-    /**
-     * Returns the current completion value for the animation.
-     *
-     * @return the current point on the animation, typically between 0 and 1
-     */
-    public float geAnimationFraction() {
-        return mVectorState.mVAnimatedPath.getValue();
-    }
-
-    /**
-     * Set the current completion value for the animation.
-     *
-     * @param value the point along the animation, typically between 0 and 1
-     */
-    public void setAnimationFraction(float value) {
-        mVectorState.mVAnimatedPath.setAnimationFraction(value);
-        invalidateSelf();
-    }
-
-    /**
-     * set the amount of time the animation will take
-     *
-     * @param duration amount of time in milliseconds
-     */
-    public void setDuration(long duration) {
-        mVectorState.mBasicAnimator.setDuration(duration);
-    }
-
-    /**
-     * Defines what this animation should do when it reaches the end. This
-     * setting is applied only when the repeat count is either greater than 0 or
-     * {@link ValueAnimator#INFINITE}.
-     *
-     * @param mode the animation mode, either {@link ValueAnimator#RESTART} or
-     *            {@link ValueAnimator#REVERSE}
-     */
-    public void setRepeatMode(int mode) {
-        mVectorState.mBasicAnimator.setRepeatMode(mode);
-    }
-
-    /**
-     * Sets animation to repeat
-     *
-     * @param repeat True if this drawable repeats its animation
-     */
-    public void setRepeatCount(int repeat) {
-        mVectorState.mBasicAnimator.setRepeatCount(repeat);
-    }
-
-    /**
-     * @return the animation repeat count, either a value greater than 0 or
-     *         {@link ValueAnimator#INFINITE}
-     */
-    public int getRepeatCount() {
-        return mVectorState.mBasicAnimator.getRepeatCount();
-    }
-
-    @Override
-    public boolean isStateful() {
-        return true;
-    }
-
-    @Override
-    protected boolean onStateChange(int[] state) {
-        super.onStateChange(state);
-
-        mVectorState.mVAnimatedPath.setState(state);
-
-        final int direction = mVectorState.mVAnimatedPath.getTrigger(state);
-        if (direction > 0) {
-            animateForward();
-        } else if (direction < 0) {
-            animateBackward();
-        }
-
-        invalidateSelf();
-        return true;
-    }
-
-    private void animateForward() {
-        if (!mVectorState.mBasicAnimator.isStarted()) {
-            mVectorState.mBasicAnimator.setFloatValues(0, 1);
-            start();
-        }
-    }
-
-    private void animateBackward() {
-        if (!mVectorState.mBasicAnimator.isStarted()) {
-            mVectorState.mBasicAnimator.setFloatValues(1, 0);
-            start();
-        }
-    }
-
-    @Override
     public void draw(Canvas canvas) {
         final int saveCount = canvas.save();
         final Rect bounds = getBounds();
         canvas.translate(bounds.left, bounds.top);
-        mVectorState.mVAnimatedPath.draw(canvas, bounds.width(), bounds.height());
+        mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height());
         canvas.restoreToCount(saveCount);
     }
 
@@ -381,12 +198,12 @@
 
     @Override
     public int getIntrinsicWidth() {
-        return (int) mVectorState.mVAnimatedPath.mBaseWidth;
+        return (int) mVectorState.mVPathRenderer.mBaseWidth;
     }
 
     @Override
     public int getIntrinsicHeight() {
-        return (int) mVectorState.mVAnimatedPath.mBaseHeight;
+        return (int) mVectorState.mVPathRenderer.mBaseHeight;
     }
 
     @Override
@@ -402,8 +219,8 @@
     @Override
     public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
             throws XmlPullParserException, IOException {
-        final VAnimatedPath p = inflateInternal(res, parser, attrs, theme);
-        setAnimatedPath(p);
+        final VPathRenderer p = inflateInternal(res, parser, attrs, theme);
+        setPathRenderer(p);
     }
 
     @Override
@@ -416,7 +233,7 @@
         super.applyTheme(t);
 
         final VectorDrawableState state = mVectorState;
-        final VAnimatedPath path = state.mVAnimatedPath;
+        final VPathRenderer path = state.mVPathRenderer;
         if (path != null && path.canApplyTheme()) {
             path.applyTheme(t);
         }
@@ -432,7 +249,6 @@
 
             final VectorDrawable drawable = new VectorDrawable();
             drawable.inflate(resources, xpp, attrs);
-            drawable.setAnimationFraction(0);
 
             return drawable;
         } catch (XmlPullParserException e) {
@@ -443,16 +259,15 @@
         return null;
     }
 
-    private VAnimatedPath inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
+    private VPathRenderer inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
             Theme theme) throws XmlPullParserException, IOException {
-        final VAnimatedPath animatedPath = new VAnimatedPath();
+        final VPathRenderer pathRenderer = new VPathRenderer();
 
         boolean noSizeTag = true;
         boolean noViewportTag = true;
-        boolean noGroupTag = true;
         boolean noPathTag = true;
 
-        VGroup currentGroup = null;
+        VGroup currentGroup = new VGroup();
 
         int eventType = parser.getEventType();
         while (eventType != XmlPullParser.END_DOCUMENT) {
@@ -463,23 +278,14 @@
                     path.inflate(res, attrs, theme);
                     currentGroup.add(path);
                     noPathTag = false;
-                } else if (SHAPE_ANIMATION.equals(tagName)) {
-                    final VAnimation anim = new VAnimation();
-                    anim.inflate(animatedPath.mGroupList, res, attrs, theme);
-                    animatedPath.addAnimation(anim);
                 } else if (SHAPE_SIZE.equals(tagName)) {
-                    animatedPath.parseSize(res, attrs);
+                    pathRenderer.parseSize(res, attrs);
                     noSizeTag = false;
                 } else if (SHAPE_VIEWPORT.equals(tagName)) {
-                    animatedPath.parseViewport(res, attrs);
+                    pathRenderer.parseViewport(res, attrs);
                     noViewportTag = false;
-                } else if (SHAPE_GROUP.equals(tagName)) {
-                    currentGroup = new VGroup();
-                    animatedPath.mGroupList.add(currentGroup);
-                    noGroupTag = false;
                 } else if (SHAPE_VECTOR.equals(tagName)) {
                     final TypedArray a = res.obtainAttributes(attrs, R.styleable.VectorDrawable);
-                    animatedPath.setTrigger(a.getInteger(R.styleable.VectorDrawable_trigger, 0));
 
                     // Parsing the version information.
                     // Right now, we only support version "1".
@@ -498,7 +304,7 @@
             eventType = parser.next();
         }
 
-        if (noSizeTag || noViewportTag || noGroupTag || noPathTag) {
+        if (noSizeTag || noViewportTag || noPathTag) {
             final StringBuffer tag = new StringBuffer();
 
             if (noSizeTag) {
@@ -512,13 +318,6 @@
                 tag.append(SHAPE_SIZE);
             }
 
-            if (noGroupTag) {
-                if (tag.length() > 0) {
-                    tag.append(" & ");
-                }
-                tag.append(SHAPE_GROUP);
-            }
-
             if (noPathTag) {
                 if (tag.length() > 0) {
                     tag.append(" or ");
@@ -529,49 +328,25 @@
             throw new XmlPullParserException("no " + tag + " defined");
         }
 
+        pathRenderer.mCurrentGroup = currentGroup;
         // post parse cleanup
-        animatedPath.parseFinish();
-        return animatedPath;
+        pathRenderer.parseFinish();
+        return pathRenderer;
     }
 
-    private void setAnimatedPath(VAnimatedPath animatedPath) {
-        mVectorState.mVAnimatedPath = animatedPath;
-
-        long duration = mVectorState.mVAnimatedPath.getTotalAnimationDuration();
-        if (duration == -1) { // if it set to infinite set to 1 hour
-            duration = DEFAULT_INFINITE_DURATION; // TODO define correct
-                                                  // approach for infinite
-            mVectorState.mBasicAnimator.setFloatValues(0, duration / 1000);
-            mVectorState.mBasicAnimator.setInterpolator(new LinearInterpolator());
-        }
-
-        setDuration(duration);
-        setAnimationFraction(0);
-    }
-
-    @Override
-    public boolean setVisible(boolean visible, boolean restart) {
-        boolean changed = super.setVisible(visible, restart);
-        if (visible) {
-            if (changed || restart) {
-                setAnimationFraction(0);
-            }
-        } else {
-            stop();
-        }
-        return changed;
+    private void setPathRenderer(VPathRenderer pathRenderer) {
+        mVectorState.mVPathRenderer = pathRenderer;
     }
 
     private static class VectorDrawableState extends ConstantState {
         int mChangingConfigurations;
-        ValueAnimator mBasicAnimator;
-        VAnimatedPath mVAnimatedPath;
+        VPathRenderer mVPathRenderer;
         Rect mPadding;
 
         public VectorDrawableState(VectorDrawableState copy) {
             if (copy != null) {
                 mChangingConfigurations = copy.mChangingConfigurations;
-                mVAnimatedPath = new VAnimatedPath(copy.mVAnimatedPath);
+                mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
                 mPadding = new Rect(copy.mPadding);
             }
         }
@@ -597,164 +372,60 @@
         }
     }
 
-    private static class VAnimatedPath {
-        private static final int [] TRIGGER_MAP = {
-                0,
-                R.attr.state_pressed,
-                R.attr.state_focused,
-                R.attr.state_hovered,
-                R.attr.state_selected,
-                R.attr.state_checkable,
-                R.attr.state_checked,
-                R.attr.state_activated,
-                R.attr.state_focused
-        };
-
+    private static class VPathRenderer {
         private final Path mPath = new Path();
         private final Path mRenderPath = new Path();
         private final Matrix mMatrix = new Matrix();
 
-        private ArrayList<VAnimation> mCurrentAnimList;
         private VPath[] mCurrentPaths;
         private Paint mStrokePaint;
         private Paint mFillPaint;
         private PathMeasure mPathMeasure;
 
-        private int[] mCurrentState = new int[0];
-        private float mAnimationValue;
-        private long mTotalDuration;
-        private int mTrigger;
-        private boolean mTriggerState;
-
-        final ArrayList<VGroup> mGroupList = new ArrayList<VGroup>();
+        private VGroup mCurrentGroup = new VGroup();
 
         float mBaseWidth = 1;
         float mBaseHeight = 1;
         float mViewportWidth;
         float mViewportHeight;
 
-        public VAnimatedPath() {
+        public VPathRenderer() {
         }
 
-        public VAnimatedPath(VAnimatedPath copy) {
-            mCurrentAnimList = new ArrayList<VAnimation>(copy.mCurrentAnimList);
-            mGroupList.addAll(copy.mGroupList);
+        public VPathRenderer(VPathRenderer copy) {
+            mCurrentGroup = copy.mCurrentGroup;
             if (copy.mCurrentPaths != null) {
                 mCurrentPaths = new VPath[copy.mCurrentPaths.length];
                 for (int i = 0; i < mCurrentPaths.length; i++) {
                     mCurrentPaths[i] = new VPath(copy.mCurrentPaths[i]);
                 }
             }
-            mAnimationValue = copy.mAnimationValue; // time goes from 0 to 1
 
             mBaseWidth = copy.mBaseWidth;
             mBaseHeight = copy.mBaseHeight;
             mViewportWidth = copy.mViewportHeight;
             mViewportHeight = copy.mViewportHeight;
-            mTotalDuration = copy.mTotalDuration;
-            mTrigger = copy.mTrigger;
-            mCurrentState = new int[0];
         }
 
         public boolean canApplyTheme() {
-            final ArrayList<VGroup> groups = mGroupList;
-            for (int i = groups.size() - 1; i >= 0; i--) {
-                final ArrayList<VPath> paths = groups.get(i).mVGList;
-                for (int j = paths.size() - 1; j >= 0; j--) {
-                    final VPath path = paths.get(j);
-                    if (path.canApplyTheme()) {
-                        return true;
-                    }
-                }
-            }
-
-            final ArrayList<VAnimation> anims = mCurrentAnimList;
-            for (int i = anims.size() - 1; i >= 0; i--) {
-                final VAnimation anim = anims.get(i);
-                if (anim.canApplyTheme()) {
+            final ArrayList<VPath> paths = mCurrentGroup.mVGList;
+            for (int j = paths.size() - 1; j >= 0; j--) {
+                final VPath path = paths.get(j);
+                if (path.canApplyTheme()) {
                     return true;
                 }
             }
-
             return false;
         }
 
         public void applyTheme(Theme t) {
-            final ArrayList<VGroup> groups = mGroupList;
-            for (int i = groups.size() - 1; i >= 0; i--) {
-                final ArrayList<VPath> paths = groups.get(i).mVGList;
-                for (int j = paths.size() - 1; j >= 0; j--) {
-                    final VPath path = paths.get(j);
-                    if (path.canApplyTheme()) {
-                        path.applyTheme(t);
-                    }
+            final ArrayList<VPath> paths = mCurrentGroup.mVGList;
+            for (int j = paths.size() - 1; j >= 0; j--) {
+                final VPath path = paths.get(j);
+                if (path.canApplyTheme()) {
+                    path.applyTheme(t);
                 }
             }
-
-            final ArrayList<VAnimation> anims = mCurrentAnimList;
-            for (int i = anims.size() - 1; i >= 0; i--) {
-                final VAnimation anim = anims.get(i);
-                if (anim.canApplyTheme()) {
-                    anim.applyTheme(t);
-                }
-            }
-        }
-
-        public void setTrigger(int trigger){
-            mTrigger = VAnimatedPath.getStateForTrigger(trigger);
-        }
-
-        public long getTotalAnimationDuration() {
-            mTotalDuration = 0;
-            int size = mCurrentAnimList.size();
-            for (int i = 0; i < size; i++) {
-                VAnimation vAnimation = mCurrentAnimList.get(i);
-                long t = vAnimation.getTotalDuration();
-                if (t == -1) {
-                    mTotalDuration = -1;
-                    return -1;
-                }
-                mTotalDuration = Math.max(mTotalDuration, t);
-            }
-
-            return mTotalDuration;
-        }
-
-        public float getValue() {
-            return mAnimationValue;
-        }
-
-        /**
-         * @param value the point along the animations to show typically between 0.0f and 1.0f
-         * @return true if you need to keep repeating
-         */
-        public boolean setAnimationFraction(float value) {
-            getTotalAnimationDuration();
-
-            long animationTime = (long) (value * mTotalDuration);
-
-            final int len = mCurrentPaths.length;
-            for (int i = 0; i < len; i++) {
-                animationTime =
-                        (long) ((mTotalDuration == -1) ? value * 1000 : mTotalDuration * value);
-
-                final VPath path = mCurrentPaths[i];
-                final int size = mCurrentAnimList.size();
-                for (int j = 0; j < size; j++) {
-                    final VAnimation vAnimation = mCurrentAnimList.get(j);
-                    if (vAnimation.doesAdjustPath(path)) {
-                        mCurrentPaths[i] =  vAnimation.getPathAtTime(animationTime, path);
-                    }
-                }
-            }
-
-            mAnimationValue = value;
-
-            if (mTotalDuration == -1) {
-                return true;
-            } else {
-                return animationTime < mTotalDuration;
-            }
         }
 
         public void draw(Canvas canvas, int w, int h) {
@@ -764,7 +435,7 @@
             }
 
             for (int i = 0; i < mCurrentPaths.length; i++) {
-                if (mCurrentPaths[i] != null && mCurrentPaths[i].isVisible(mCurrentState)) {
+                if (mCurrentPaths[i] != null) {
                     drawPath(mCurrentPaths[i], canvas, w, h);
                 }
             }
@@ -846,69 +517,17 @@
         }
 
         /**
-         * Ensure there is at least one animation for every path in group (linking them by names)
-         * Build the "current" path based on the first group
+         * Build the "current" path based on the current group
          * TODO: improve memory use & performance or move to C++
          */
         public void parseFinish() {
-            final HashMap<String, VAnimation> newAnimations = new HashMap<String, VAnimation>();
-            for (VGroup group : mGroupList) {
-                for (VPath vPath : group.getPaths()) {
-                    if (!vPath.mAnimated) {
-                        VAnimation ap = null;
-
-                        if (!newAnimations.containsKey(vPath.getID())) {
-                            newAnimations.put(vPath.getID(), ap = new VAnimation());
-                        } else {
-                            ap = newAnimations.get(vPath.getID());
-                        }
-
-                        ap.addPath(vPath);
-                        vPath.mAnimated = true;
-                    }
-                }
-            }
-
-            if (mCurrentAnimList == null) {
-                mCurrentAnimList = new ArrayList<VectorDrawable.VAnimation>();
-            }
-            mCurrentAnimList.addAll(newAnimations.values());
-
-            final Collection<VPath> paths = mGroupList.get(0).getPaths();
+            final Collection<VPath> paths = mCurrentGroup.getPaths();
             mCurrentPaths = paths.toArray(new VPath[paths.size()]);
             for (int i = 0; i < mCurrentPaths.length; i++) {
                 mCurrentPaths[i] = new VPath(mCurrentPaths[i]);
             }
         }
 
-        public void setState(int[] state) {
-            mCurrentState = Arrays.copyOf(state, state.length);
-        }
-
-        int getTrigger(int []state){
-            if (mTrigger == 0) return 0;
-            for (int i = 0; i < state.length; i++) {
-                if (state[i] == mTrigger){
-                    if (mTriggerState)
-                        return 0;
-                    mTriggerState = true;
-                    return 1;
-                }
-            }
-            if (mTriggerState) {
-                mTriggerState = false;
-                return -1;
-            }
-            return 0;
-        }
-
-        public void addAnimation(VAnimation anim) {
-            if (mCurrentAnimList == null) {
-                mCurrentAnimList = new ArrayList<VectorDrawable.VAnimation>();
-            }
-            mCurrentAnimList.add(anim);
-        }
-
         private void parseViewport(Resources r, AttributeSet attrs)
                 throws XmlPullParserException {
             final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport);
@@ -933,329 +552,6 @@
             a.recycle();
         }
 
-        private static final int getStateForTrigger(int trigger) {
-            return TRIGGER_MAP[trigger];
-        }
-    }
-
-    private static class VAnimation {
-        private static final String SEPARATOR = ",";
-
-        private static final int DIRECTION_FORWARD = 0;
-        private static final int DIRECTION_IN_AND_OUT = 1;
-
-        public enum Style {
-            INTERPOLATE, CROSSFADE, WIPE
-        }
-
-        private final HashSet<String> mSeqMap = new HashSet<String>();
-
-        private Interpolator mAnimInterpolator = new AccelerateDecelerateInterpolator();
-        private VPath[] mPaths = new VPath[0];
-        private long[] mDuration = { DEFAULT_DURATION };
-
-        private int[] mThemeAttrs;
-        private Style mStyle;
-        private int mLimitProperty = 0;
-        private long mStartOffset;
-        private long mRepeat = 1;
-        private long mWipeDirection;
-        private int mMode = DIRECTION_FORWARD;
-        private int mInterpolatorType;
-        private String mId;
-
-        public VAnimation() {
-            // Empty constructor.
-        }
-
-        public void inflate(ArrayList<VGroup> groups, Resources r, AttributeSet attrs, Theme theme)
-                throws XmlPullParserException {
-            String value;
-            String[] sp;
-            int name;
-
-            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableAnimation);
-            final int[] themeAttrs = a.extractThemeAttrs();
-            mThemeAttrs = themeAttrs;
-
-            value = a.getString(R.styleable.VectorDrawableAnimation_sequence);
-            if (value != null) {
-                sp = value.split(SEPARATOR);
-                final VectorDrawable.VPath[] paths = new VectorDrawable.VPath[sp.length];
-
-                for (int j = 0; j < sp.length; j++) {
-                    mSeqMap.add(sp[j].trim());
-
-                    final VectorDrawable.VPath path = groups.get(j).get(sp[j]);
-                    if (path == null) {
-                        throw new XmlPullParserException(a.getPositionDescription()
-                                + " missing path with name: " + sp[j]);
-                    }
-
-                    path.mAnimated = true;
-                    paths[j] = path;
-                }
-
-                setPaths(paths);
-            }
-
-            name = R.styleable.VectorDrawableAnimation_durations;
-            value = a.getString(name);
-            if (value != null) {
-                long totalDuration = 0;
-                sp = value.split(SEPARATOR);
-
-                final long[] dur = new long[sp.length];
-                for (int j = 0; j < dur.length; j++) {
-                    dur[j] = Long.parseLong(sp[j]);
-                    totalDuration +=  dur[j];
-                }
-
-                if (totalDuration == 0){
-                    throw new XmlPullParserException(a.getPositionDescription()
-                            + " total duration must not be zero");
-                }
-
-                setDuration(dur);
-            }
-
-            setLimitProperty(a.getInt(R.styleable.VectorDrawableAnimation_limitTo, 0));
-            setRepeat(a.getInt(R.styleable.VectorDrawableAnimation_repeatCount, 1));
-            setStartOffset(a.getInt(R.styleable.VectorDrawableAnimation_startDelay, 0));
-            setMode(a.getInt(R.styleable.VectorDrawableAnimation_repeatStyle, 0));
-
-            fixMissingParameters();
-
-            a.recycle();
-        }
-
-        public boolean canApplyTheme() {
-            return mThemeAttrs != null;
-        }
-
-        public void applyTheme(Theme t) {
-            // TODO: Apply theme.
-        }
-
-        public boolean doesAdjustPath(VPath path) {
-            return mSeqMap.contains(path.getID());
-        }
-
-        public String getId() {
-            if (mId == null) {
-                mId = mPaths[0].getID();
-                for (int i = 1; i < mPaths.length; i++) {
-                    mId += mPaths[i].getID();
-                }
-            }
-            return mId;
-        }
-
-        public String getPathName() {
-            return mPaths[0].getID();
-        }
-
-        public Style getStyle() {
-            return mStyle;
-        }
-
-        public void setStyle(Style style) {
-            mStyle = style;
-        }
-
-        public int getLimitProperty() {
-            return mLimitProperty;
-        }
-
-        public void setLimitProperty(int limitProperty) {
-            mLimitProperty = limitProperty;
-        }
-
-        public long[] getDuration() {
-            return mDuration;
-        }
-
-        public void setDuration(long[] duration) {
-            mDuration = duration;
-        }
-
-        public long getRepeat() {
-            return mRepeat;
-        }
-
-        public void setRepeat(long repeat) {
-            mRepeat = repeat;
-        }
-
-        public long getStartOffset() {
-            return mStartOffset;
-        }
-
-        public void setStartOffset(long startOffset) {
-            mStartOffset = startOffset;
-        }
-
-        public long getWipeDirection() {
-            return mWipeDirection;
-        }
-
-        public void setWipeDirection(long wipeDirection) {
-            mWipeDirection = wipeDirection;
-        }
-
-        public int getMode() {
-            return mMode;
-        }
-
-        public void setMode(int mode) {
-            mMode = mode;
-        }
-
-        public int getInterpolator() {
-            return mInterpolatorType;
-        }
-
-        public void setInterpolator(int interpolator) {
-            mInterpolatorType = interpolator;
-        }
-
-        /**
-         * compute the total time in milliseconds
-         *
-         * @return the total time in milliseconds the animation will take
-         */
-        public long getTotalDuration() {
-            long total = mStartOffset;
-            if (getRepeat() == -1) {
-                return -1;
-            }
-            for (int i = 0; i < mDuration.length; i++) {
-                if (mRepeat > 1) {
-                    total += mDuration[i] * mRepeat;
-                } else {
-                    total += mDuration[i];
-                }
-            }
-            return total;
-        }
-
-        public void setPaths(VPath[] paths) {
-            mPaths = paths;
-        }
-
-        public void addPath(VPath path) {
-            mPaths = Arrays.copyOf(mPaths, mPaths.length + 1);
-            mPaths[mPaths.length - 1] = path;
-        }
-
-        public boolean containsPath(String pathid) {
-            for (int i = 0; i < mPaths.length; i++) {
-                if (mPaths[i].getID().equals(pathid)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        public void interpolate(VPath p1, VPath p2, float time, VPath dest) {
-            VPath.interpolate(time, p1, p2, dest, mLimitProperty);
-        }
-
-        public VPath getPathAtTime(long milliseconds, VPath dest) {
-            if (mPaths.length == 1) {
-                dest.copyFrom(mPaths[0]);
-                return dest;
-            }
-            long point = milliseconds - mStartOffset;
-            if (point < 0) {
-                point = 0;
-            }
-            float time = 0;
-            long sum = mDuration[0];
-            for (int i = 1; i < mDuration.length; i++) {
-                sum += mDuration[i];
-            }
-
-            if (mRepeat > 1) {
-                time = point / (float) (sum * mRepeat);
-                time = mAnimInterpolator.getInterpolation(time);
-
-                if (mMode == DIRECTION_IN_AND_OUT) {
-                    point = ((long) (time * sum * 2 * mRepeat)) % (sum * 2);
-                    if (point > sum) {
-                        point = sum * 2 - point;
-                    }
-                } else {
-                    point = ((long) (time * sum * mRepeat)) % sum;
-                }
-            } else if (mRepeat == 1) {
-                time = point / (float) (sum * mRepeat);
-                time = mAnimInterpolator.getInterpolation(time);
-                if (mMode == DIRECTION_IN_AND_OUT) {
-                    point = ((long) (time * sum * 2 * mRepeat));
-                    if (point > sum) {
-                        point = sum * 2 - point;
-                    }
-                } else {
-                    point = Math.min(((long) (time * sum * mRepeat)), sum);
-                }
-
-            } else { // repeat = -1
-                if (mMode == DIRECTION_IN_AND_OUT) {
-                    point = point % (sum * 2);
-                    if (point > sum) {
-                        point = sum * 2 - point;
-                    }
-                    time = point / (float) sum;
-                } else {
-                    point = point % sum;
-                    time = point / (float) sum;
-                }
-            }
-
-            int transition = 0;
-            while (point > mDuration[transition]) {
-                point -= mDuration[transition++];
-            }
-            if (mPaths.length > (transition + 1)) {
-                if (mPaths[transition].getID() != dest.getID()) {
-                    dest.copyFrom(mPaths[transition]);
-                }
-                interpolate(mPaths[transition], mPaths[transition + 1],
-                        point / (float) mDuration[transition], dest);
-            } else {
-                interpolate(mPaths[transition], mPaths[transition], 0, dest);
-            }
-            return dest;
-        }
-
-        void fixMissingParameters() {
-            // fix missing points
-            float rotation = Float.NaN;
-            float rotationY = Float.NaN;
-            float rotationX = Float.NaN;
-            for (int i = 0; i < mPaths.length; i++) {
-                if (mPaths[i].mPivotX > 0) {
-                    rotationX = mPaths[i].mPivotX;
-                }
-                if (mPaths[i].mPivotY > 0) {
-                    rotationY = mPaths[i].mPivotY;
-                }
-                if (mPaths[i].mRotate > 0) {
-                    rotation = mPaths[i].mRotate;
-                }
-            }
-            if (rotation > 0) {
-                for (int i = 0; i < mPaths.length; i++) {
-                    if (mPaths[i].mPivotX == 0) {
-                        mPaths[i].mPivotX = rotationX;
-                    }
-                    if (mPaths[i].mPivotY == 0) {
-                        mPaths[i].mPivotY = rotationY;
-                    }
-                }
-            }
-        }
     }
 
     private static class VGroup {
@@ -1268,10 +564,6 @@
             mVGList.add(path);
          }
 
-        public VPath get(String name) {
-            return mVGPathMap.get(name);
-        }
-
         /**
          * Must return in order of adding
          * @return ordered list of paths
@@ -1280,23 +572,9 @@
             return mVGList;
         }
 
-        public int size() {
-            return mVGPathMap.size();
-        }
     }
 
     private static class VPath {
-        private static final int LIMIT_ALL = 0;
-        private static final int LIMIT_PATH = 1;
-        private static final int LIMIT_ROTATE = 2;
-        private static final int LIMIT_TRIM_PATH_START = 3;
-        private static final int LIMIT_TRIM_PATH_OFFSET = 5;
-        private static final int LIMIT_TRIM_PATH_END = 4;
-
-        private static final int STATE_UNDEFINED=0;
-        private static final int STATE_TRUE=1;
-        private static final int STATE_FALSE=2;
-
         private static final int MAX_STATES = 10;
 
         private int[] mThemeAttrs;
@@ -1317,7 +595,6 @@
         float mTrimPathEnd = 1;
         float mTrimPathOffset = 0;
 
-        boolean mAnimated = false;
         boolean mClip = false;
         Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
         Paint.Join mStrokeLineJoin = Paint.Join.MITER;
@@ -1328,7 +605,6 @@
         private int[] mCheckState = new int[MAX_STATES];
         private boolean[] mCheckValue = new boolean[MAX_STATES];
         private int mNumberOfStates = 0;
-        private int mNumberOfTrue = 0;
 
         public VPath() {
             // Empty constructor.
@@ -1338,38 +614,6 @@
             copyFrom(p);
         }
 
-        public void addStateFilter(int state, boolean condition) {
-            int k = 0;
-            while (k < mNumberOfStates) {
-                if (mCheckState[mNumberOfStates] == state)
-                    break;
-                k++;
-            }
-            mCheckState[k] = state;
-            mCheckValue[k] = condition;
-            if (k==mNumberOfStates){
-                mNumberOfStates++;
-            }
-            if (condition) {
-                mNumberOfTrue++;
-            }
-        }
-
-        private int getState(int state){
-            for (int i = 0; i < mNumberOfStates; i++) {
-                if (mCheckState[mNumberOfStates] == state){
-                    return (mCheckValue[i])?STATE_TRUE:STATE_FALSE;
-                }
-            }
-            return STATE_UNDEFINED;
-        }
-        /**
-         * @return the name of the path
-         */
-        public String getName() {
-            return mId;
-        }
-
         public void toPath(Path path) {
             path.reset();
             if (mNode != null) {
@@ -1494,27 +738,6 @@
                         R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
             }
 
-            // TODO: Consider replacing this with existing state attributes.
-            final int[] states = {
-                    R.styleable.VectorDrawablePath_state_activated,
-                    R.styleable.VectorDrawablePath_state_checkable,
-                    R.styleable.VectorDrawablePath_state_checked,
-                    R.styleable.VectorDrawablePath_state_enabled,
-                    R.styleable.VectorDrawablePath_state_focused,
-                    R.styleable.VectorDrawablePath_state_hovered,
-                    R.styleable.VectorDrawablePath_state_pressed,
-                    R.styleable.VectorDrawablePath_state_selected,
-                    R.styleable.VectorDrawablePath_state_window_focused
-            };
-
-            final int N = states.length;
-            for (int i = 0; i < N; i++) {
-                final int state = states[i];
-                if (a.hasValue(state)) {
-                    addStateFilter(state, a.getBoolean(state, false));
-                }
-            }
-
             updateColorAlphas();
 
             a.recycle();
@@ -1682,7 +905,6 @@
             mRotate = p1.mRotate;
             mPivotX = p1.mPivotX;
             mPivotY = p1.mPivotY;
-            mAnimated = p1.mAnimated;
             mTrimPathStart = p1.mTrimPathStart;
             mTrimPathEnd = p1.mTrimPathEnd;
             mTrimPathOffset = p1.mTrimPathOffset;
@@ -1697,118 +919,6 @@
 
             mFillRule = p1.mFillRule;
         }
-
-        public static VPath interpolate(float t, VPath p1, VPath p2, VPath returnPath, int limit) {
-            if (limit == LIMIT_ALL || limit == LIMIT_PATH) {
-                if (returnPath.mNode == null || returnPath.mNode.length != p1.mNode.length) {
-                    returnPath.mNode = new VNode[p1.mNode.length];
-                }
-                for (int i = 0; i < returnPath.mNode.length; i++) {
-                    if (returnPath.mNode[i] == null) {
-                        returnPath.mNode[i] = new VNode(p1.mNode[i], p2.mNode[i], t);
-                    } else {
-                        returnPath.mNode[i].interpolate(p1.mNode[i], p2.mNode[i], t);
-                    }
-                }
-            }
-            float t1 = 1 - t;
-            switch (limit) {
-                case LIMIT_ALL:
-                    returnPath.mRotate = t1 * p1.mRotate + t * p2.mRotate;
-                    returnPath.mPivotX = t1 * p1.mPivotX + t * p2.mPivotX;
-                    returnPath.mPivotY = t1 * p1.mPivotY + t * p2.mPivotY;
-                    returnPath.mClip = p1.mClip | p2.mClip;
-
-                    returnPath.mTrimPathStart = t1 * p1.mTrimPathStart + t * p2.mTrimPathStart;
-                    returnPath.mTrimPathEnd = t1 * p1.mTrimPathEnd + t * p2.mTrimPathEnd;
-                    returnPath.mTrimPathOffset = t1 * p1.mTrimPathOffset + t * p2.mTrimPathOffset;
-                    returnPath.mStrokeMiterlimit =
-                            t1 * p1.mStrokeMiterlimit + t * p2.mStrokeMiterlimit;
-                    returnPath.mStrokeLineCap = p1.mStrokeLineCap;
-                    if (returnPath.mStrokeLineCap == null) {
-                        returnPath.mStrokeLineCap = p2.mStrokeLineCap;
-                    }
-                    returnPath.mStrokeLineJoin = p1.mStrokeLineJoin;
-                    if (returnPath.mStrokeLineJoin == null) {
-                        returnPath.mStrokeLineJoin = p2.mStrokeLineJoin;
-                    }
-                    returnPath.mFillRule = p1.mFillRule;
-
-                    returnPath.mStrokeColor = rgbInterpolate(t, p1.mStrokeColor, p2.mStrokeColor);
-                    returnPath.mFillColor = rgbInterpolate(t, p1.mFillColor, p2.mFillColor);
-                    returnPath.mStrokeWidth = t1 * p1.mStrokeWidth + t * p2.mStrokeWidth;
-                    returnPath.mNumberOfStates = p1.mNumberOfStates;
-                    for (int i = 0; i < returnPath.mNumberOfStates; i++) {
-                        returnPath.mCheckState[i] = p1.mCheckState[i];
-                        returnPath.mCheckValue[i] = p1.mCheckValue[i];
-                    }
-                    for (int i = 0; i < p2.mNumberOfStates; i++) {
-                        returnPath.addStateFilter(p2.mCheckState[i], p2.mCheckValue[i]);
-                    }
-
-                    int count = 0;
-                    for (int i = 0; i < returnPath.mNumberOfStates; i++) {
-                        if (returnPath.mCheckValue[i]) {
-                            count++;
-                        }
-                    }
-                    returnPath.mNumberOfTrue = count;
-                    break;
-                case LIMIT_ROTATE:
-                    returnPath.mRotate = t1 * p1.mRotate + t * p2.mRotate;
-                    break;
-                case LIMIT_TRIM_PATH_END:
-                    returnPath.mTrimPathEnd = t1 * p1.mTrimPathEnd + t * p2.mTrimPathEnd;
-                    break;
-                case LIMIT_TRIM_PATH_OFFSET:
-                    returnPath.mTrimPathOffset = t1 * p1.mTrimPathOffset + t * p2.mTrimPathOffset;
-                    break;
-                case LIMIT_TRIM_PATH_START:
-                    returnPath.mTrimPathStart = t1 * p1.mTrimPathStart + t * p2.mTrimPathStart;
-                    break;
-            }
-            return returnPath;
-        }
-
-        private static int rgbInterpolate(float fraction, int startColor, int endColor) {
-            if (startColor == endColor) {
-                return startColor;
-            } else if (startColor == 0) {
-                return endColor;
-            } else if (endColor == 0) {
-                return startColor;
-            }
-
-            final int startA = (startColor >> 24) & 0xff;
-            final int startR = (startColor >> 16) & 0xff;
-            final int startG = (startColor >> 8) & 0xff;
-            final int startB = startColor & 0xff;
-
-            final int endA = (endColor >> 24) & 0xff;
-            final int endR = (endColor >> 16) & 0xff;
-            final int endG = (endColor >> 8) & 0xff;
-            final int endB = endColor & 0xff;
-
-            return ((startA + (int)(fraction * (endA - startA))) << 24) |
-                    ((startR + (int)(fraction * (endR - startR))) << 16) |
-                    ((startG + (int)(fraction * (endG - startG))) << 8) |
-                    ((startB + (int)(fraction * (endB - startB))));
-        }
-
-        public boolean isVisible(int[] state) {
-            int match = 0;
-            for (int i = 0; i < state.length; i++) {
-                int v = getState(state[i]);
-                if (v != STATE_UNDEFINED) {
-                    if (v==STATE_TRUE) {
-                        match++;
-                    } else {
-                        return false;
-                    }
-                }
-            }
-            return match == mNumberOfTrue;
-        }
     }
 
     private static class VNode {
@@ -1825,25 +935,6 @@
             mParams = Arrays.copyOf(n.mParams, n.mParams.length);
         }
 
-        public VNode(VNode n1, VNode n2, float t) {
-            mType = n1.mType;
-            mParams = new float[n1.mParams.length];
-            interpolate(n1, n2, t);
-        }
-
-        private boolean match(VNode n) {
-            if (n.mType != mType) {
-                return false;
-            }
-            return (mParams.length == n.mParams.length);
-        }
-
-        public void interpolate(VNode n1, VNode n2, float t) {
-            for (int i = 0; i < n1.mParams.length; i++) {
-                mParams[i] = n1.mParams[i] * (1 - t) + n2.mParams[i] * t;
-            }
-        }
-
         public static void createPath(VNode[] node, Path path) {
             float[] current = new float[4];
             char previousCommand = 'm';
@@ -1899,7 +990,6 @@
                     break;
             }
             for (int k = 0; k < val.length; k += incr) {
-                // TODO: build test to prove all permutations work
                 switch (cmd) {
                     case 'm': // moveto - Start a new sub-path (relative)
                         path.rMoveTo(val[k + 0], val[k + 1]);
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 098753b..7d4da01 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -102,7 +102,7 @@
     if (headerSize >= minSize) {
         if (headerSize <= size) {
             if (((headerSize|size)&0x3) == 0) {
-                if ((ssize_t)size <= (dataEnd-((const uint8_t*)chunk))) {
+                if ((size_t)size <= (size_t)(dataEnd-((const uint8_t*)chunk))) {
                     return NO_ERROR;
                 }
                 ALOGW("%s data size 0x%x extends beyond resource end %p.",
@@ -2452,15 +2452,19 @@
 
     if (mcc != 0) {
         if (res.size() > 0) res.append("-");
-        res.appendFormat("%dmcc", dtohs(mcc));
+        res.appendFormat("mcc%d", dtohs(mcc));
     }
     if (mnc != 0) {
         if (res.size() > 0) res.append("-");
-        res.appendFormat("%dmnc", dtohs(mnc));
+        res.appendFormat("mnc%d", dtohs(mnc));
     }
+
     char localeStr[RESTABLE_MAX_LOCALE_LEN];
     getBcp47Locale(localeStr);
-    res.append(localeStr);
+    if (strlen(localeStr) > 0) {
+        if (res.size() > 0) res.append("-");
+        res.append(localeStr);
+    }
 
     if ((screenLayout&MASK_LAYOUTDIR) != 0) {
         if (res.size() > 0) res.append("-");
@@ -2627,6 +2631,20 @@
                 break;
         }
     }
+    if ((inputFlags&MASK_KEYSHIDDEN) != 0) {
+        if (res.size() > 0) res.append("-");
+        switch (inputFlags&MASK_KEYSHIDDEN) {
+            case ResTable_config::KEYSHIDDEN_NO:
+                res.append("keysexposed");
+                break;
+            case ResTable_config::KEYSHIDDEN_YES:
+                res.append("keyshidden");
+                break;
+            case ResTable_config::KEYSHIDDEN_SOFT:
+                res.append("keyssoft");
+                break;
+        }
+    }
     if (keyboard != KEYBOARD_ANY) {
         if (res.size() > 0) res.append("-");
         switch (keyboard) {
@@ -2644,17 +2662,18 @@
                 break;
         }
     }
-    if ((inputFlags&MASK_KEYSHIDDEN) != 0) {
+    if ((inputFlags&MASK_NAVHIDDEN) != 0) {
         if (res.size() > 0) res.append("-");
-        switch (inputFlags&MASK_KEYSHIDDEN) {
-            case ResTable_config::KEYSHIDDEN_NO:
-                res.append("keysexposed");
+        switch (inputFlags&MASK_NAVHIDDEN) {
+            case ResTable_config::NAVHIDDEN_NO:
+                res.append("navexposed");
                 break;
-            case ResTable_config::KEYSHIDDEN_YES:
-                res.append("keyshidden");
+            case ResTable_config::NAVHIDDEN_YES:
+                res.append("navhidden");
                 break;
-            case ResTable_config::KEYSHIDDEN_SOFT:
-                res.append("keyssoft");
+            default:
+                res.appendFormat("inputFlagsNavHidden=%d",
+                        dtohs(inputFlags&MASK_NAVHIDDEN));
                 break;
         }
     }
@@ -2678,21 +2697,6 @@
                 break;
         }
     }
-    if ((inputFlags&MASK_NAVHIDDEN) != 0) {
-        if (res.size() > 0) res.append("-");
-        switch (inputFlags&MASK_NAVHIDDEN) {
-            case ResTable_config::NAVHIDDEN_NO:
-                res.append("navsexposed");
-                break;
-            case ResTable_config::NAVHIDDEN_YES:
-                res.append("navhidden");
-                break;
-            default:
-                res.appendFormat("inputFlagsNavHidden=%d",
-                        dtohs(inputFlags&MASK_NAVHIDDEN));
-                break;
-        }
-    }
     if (screenSize != 0) {
         if (res.size() > 0) res.append("-");
         res.appendFormat("%dx%d", dtohs(screenWidth), dtohs(screenHeight));
@@ -5503,7 +5507,25 @@
         if (package == NULL) {
             return (mError=NO_MEMORY);
         }
-        
+
+        if (idmap_id == 0) {
+            err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
+                                           header->dataEnd-(base+dtohl(pkg->typeStrings)));
+            if (err != NO_ERROR) {
+                delete group;
+                delete package;
+                return (mError=err);
+            }
+
+            err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings),
+                                          header->dataEnd-(base+dtohl(pkg->keyStrings)));
+            if (err != NO_ERROR) {
+                delete group;
+                delete package;
+                return (mError=err);
+            }
+        }
+
         if (id == 0) {
             // This is a library so assign an ID
             id = mNextPackageId++;
@@ -5521,21 +5543,6 @@
                 return (mError=NO_MEMORY);
             }
 
-            err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
-                                           header->dataEnd-(base+dtohl(pkg->typeStrings)));
-            if (err != NO_ERROR) {
-                delete group;
-                delete package;
-                return (mError=err);
-            }
-            err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings),
-                                          header->dataEnd-(base+dtohl(pkg->keyStrings)));
-            if (err != NO_ERROR) {
-                delete group;
-                delete package;
-                return (mError=err);
-            }
-
             //printf("Adding new package id %d at index %d\n", id, idx);
             err = mPackageGroups.add(group);
             if (err < NO_ERROR) {
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index d324439..2cadf09 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -6,6 +6,7 @@
 ifeq ($(USE_OPENGL_RENDERER),true)
 	LOCAL_SRC_FILES := \
 		utils/Blur.cpp \
+		utils/GLUtils.cpp \
 		utils/SortedListImpl.cpp \
 		thread/TaskManager.cpp \
 		font/CacheTexture.cpp \
@@ -53,13 +54,14 @@
 		TextureCache.cpp \
 		TextDropShadowCache.cpp
 
-	# RenderThread stuff
+# RenderThread stuff
 	LOCAL_SRC_FILES += \
 		renderthread/CanvasContext.cpp \
 		renderthread/DrawFrameTask.cpp \
 		renderthread/RenderProxy.cpp \
 		renderthread/RenderTask.cpp \
-		renderthread/RenderThread.cpp
+		renderthread/RenderThread.cpp \
+		renderthread/TimeLord.cpp
 
 	intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,)
 
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index ee16586..a033f86 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -20,130 +20,13 @@
 
 #include <set>
 
+#include "RenderNode.h"
 #include "RenderProperties.h"
 
 namespace android {
 namespace uirenderer {
 
 /************************************************************
- *  Private header
- ************************************************************/
-
-typedef void (RenderProperties::*SetFloatProperty)(float value);
-typedef float (RenderProperties::*GetFloatProperty)() const;
-
-struct PropertyAccessors {
-    GetFloatProperty getter;
-    SetFloatProperty setter;
-};
-
-// Maps RenderProperty enum to accessors
-static const PropertyAccessors PROPERTY_ACCESSOR_LUT[] = {
-    {&RenderProperties::getTranslationX, &RenderProperties::setTranslationX },
-    {&RenderProperties::getTranslationY, &RenderProperties::setTranslationY },
-    {&RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ },
-    {&RenderProperties::getScaleX, &RenderProperties::setScaleX },
-    {&RenderProperties::getScaleY, &RenderProperties::setScaleY },
-    {&RenderProperties::getRotation, &RenderProperties::setRotation },
-    {&RenderProperties::getRotationX, &RenderProperties::setRotationX },
-    {&RenderProperties::getRotationY, &RenderProperties::setRotationY },
-    {&RenderProperties::getX, &RenderProperties::setX },
-    {&RenderProperties::getY, &RenderProperties::setY },
-    {&RenderProperties::getZ, &RenderProperties::setZ },
-    {&RenderProperties::getAlpha, &RenderProperties::setAlpha },
-};
-
-// Helper class to contain generic animator helpers
-class BaseAnimator {
-public:
-    BaseAnimator();
-    virtual ~BaseAnimator();
-
-    void setInterpolator(Interpolator* interpolator);
-    void setDuration(nsecs_t durationInMs);
-
-    bool isFinished() { return mPlayState == FINISHED; }
-
-protected:
-    // This is the main animation entrypoint that subclasses should call
-    // to generate the onAnimation* lifecycle events
-    // Returns true if the animation has finished, false otherwise
-    bool animateFrame(nsecs_t frameTime);
-
-    // Called when PlayState switches from PENDING to RUNNING
-    virtual void onAnimationStarted() {}
-    virtual void onAnimationUpdated(float fraction) = 0;
-    virtual void onAnimationFinished() {}
-
-private:
-    enum PlayState {
-        PENDING,
-        RUNNING,
-        FINISHED,
-    };
-
-    Interpolator* mInterpolator;
-    PlayState mPlayState;
-    long mStartTime;
-    long mDuration;
-};
-
-// Hide the base classes & private bits from the exported RenderPropertyAnimator
-// in this Impl class so that subclasses of RenderPropertyAnimator don't require
-// knowledge of the inner guts but only the public virtual methods.
-// Animates a single property
-class RenderPropertyAnimatorImpl : public BaseAnimator {
-public:
-    RenderPropertyAnimatorImpl(GetFloatProperty getter, SetFloatProperty setter,
-            RenderPropertyAnimator::DeltaValueType deltaType, float delta);
-    ~RenderPropertyAnimatorImpl();
-
-    bool animate(RenderProperties* target, TreeInfo& info);
-
-protected:
-    virtual void onAnimationStarted();
-    virtual void onAnimationUpdated(float fraction);
-
-private:
-    // mTarget is only valid inside animate()
-    RenderProperties* mTarget;
-    GetFloatProperty mGetter;
-    SetFloatProperty mSetter;
-
-    RenderPropertyAnimator::DeltaValueType mDeltaValueType;
-    float mDeltaValue;
-    float mFromValue;
-};
-
-RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property,
-        DeltaValueType deltaType, float deltaValue) {
-    PropertyAccessors pa = PROPERTY_ACCESSOR_LUT[property];
-    mImpl = new RenderPropertyAnimatorImpl(pa.getter, pa.setter, deltaType, deltaValue);
-}
-
-RenderPropertyAnimator::~RenderPropertyAnimator() {
-    delete mImpl;
-    mImpl = NULL;
-}
-
-void RenderPropertyAnimator::setInterpolator(Interpolator* interpolator) {
-    mImpl->setInterpolator(interpolator);
-}
-
-void RenderPropertyAnimator::setDuration(nsecs_t durationInMs) {
-    mImpl->setDuration(durationInMs);
-}
-
-bool RenderPropertyAnimator::isFinished() {
-    return mImpl->isFinished();
-}
-
-bool RenderPropertyAnimator::animate(RenderProperties* target, TreeInfo& info) {
-    return mImpl->animate(target, info);
-}
-
-
-/************************************************************
  *  Base animator
  ************************************************************/
 
@@ -168,10 +51,10 @@
     mDuration = duration;
 }
 
-bool BaseAnimator::animateFrame(nsecs_t frameTime) {
+bool BaseAnimator::animateFrame(TreeInfo& info) {
     if (mPlayState == PENDING) {
         mPlayState = RUNNING;
-        mStartTime = frameTime;
+        mStartTime = info.frameTimeMs;
         // No interpolator was set, use the default
         if (!mInterpolator) {
             setInterpolator(Interpolator::createDefaultInterpolator());
@@ -181,7 +64,7 @@
 
     float fraction = 1.0f;
     if (mPlayState == RUNNING) {
-        fraction = mDuration > 0 ? (float)(frameTime - mStartTime) / mDuration : 1.0f;
+        fraction = mDuration > 0 ? (float)(info.frameTimeMs - mStartTime) / mDuration : 1.0f;
         if (fraction >= 1.0f) {
             fraction = 1.0f;
             mPlayState = FINISHED;
@@ -192,48 +75,145 @@
 
     if (mPlayState == FINISHED) {
         onAnimationFinished();
+        callOnFinishedListener(info);
         return true;
     }
     return false;
 }
 
+void BaseAnimator::callOnFinishedListener(TreeInfo& info) {
+    if (mListener.get()) {
+        if (!info.animationHook) {
+            mListener->onAnimationFinished(this);
+        } else {
+            info.animationHook->callOnFinished(this, mListener.get());
+        }
+    }
+}
+
+/************************************************************
+ *  BaseRenderNodeAnimator
+ ************************************************************/
+
+BaseRenderNodeAnimator::BaseRenderNodeAnimator(
+                BaseRenderNodeAnimator::DeltaValueType deltaType, float delta)
+        : mTarget(0)
+        , mDeltaValueType(deltaType)
+        , mDeltaValue(delta)
+        , mFromValue(-1) {
+}
+
+bool BaseRenderNodeAnimator::animate(RenderNode* target, TreeInfo& info) {
+    mTarget = target;
+    bool finished = animateFrame(info);
+    mTarget = NULL;
+    return finished;
+}
+
+void BaseRenderNodeAnimator::onAnimationStarted() {
+    mFromValue = getValue();
+
+    if (mDeltaValueType == BaseRenderNodeAnimator::ABSOLUTE) {
+        mDeltaValue = (mDeltaValue - mFromValue);
+        mDeltaValueType = BaseRenderNodeAnimator::DELTA;
+    }
+}
+
+void BaseRenderNodeAnimator::onAnimationUpdated(float fraction) {
+    float value = mFromValue + (mDeltaValue * fraction);
+    setValue(value);
+}
+
 /************************************************************
  *  RenderPropertyAnimator
  ************************************************************/
 
-RenderPropertyAnimatorImpl::RenderPropertyAnimatorImpl(
-                GetFloatProperty getter, SetFloatProperty setter,
-                RenderPropertyAnimator::DeltaValueType deltaType, float delta)
-        : mTarget(0)
-        , mGetter(getter)
-        , mSetter(setter)
-        , mDeltaValueType(deltaType)
-        , mDeltaValue(delta)
-        , mFromValue(-1) {
+// Maps RenderProperty enum to accessors
+const RenderPropertyAnimator::PropertyAccessors RenderPropertyAnimator::PROPERTY_ACCESSOR_LUT[] = {
+    {&RenderProperties::getTranslationX, &RenderProperties::setTranslationX },
+    {&RenderProperties::getTranslationY, &RenderProperties::setTranslationY },
+    {&RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ },
+    {&RenderProperties::getScaleX, &RenderProperties::setScaleX },
+    {&RenderProperties::getScaleY, &RenderProperties::setScaleY },
+    {&RenderProperties::getRotation, &RenderProperties::setRotation },
+    {&RenderProperties::getRotationX, &RenderProperties::setRotationX },
+    {&RenderProperties::getRotationY, &RenderProperties::setRotationY },
+    {&RenderProperties::getX, &RenderProperties::setX },
+    {&RenderProperties::getY, &RenderProperties::setY },
+    {&RenderProperties::getZ, &RenderProperties::setZ },
+    {&RenderProperties::getAlpha, &RenderProperties::setAlpha },
+};
+
+RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property,
+                DeltaValueType deltaType, float deltaValue)
+        : BaseRenderNodeAnimator(deltaType, deltaValue)
+        , mPropertyAccess(PROPERTY_ACCESSOR_LUT[property]) {
 }
 
-RenderPropertyAnimatorImpl::~RenderPropertyAnimatorImpl() {
+float RenderPropertyAnimator::getValue() const {
+    return (target()->animatorProperties().*mPropertyAccess.getter)();
 }
 
-bool RenderPropertyAnimatorImpl::animate(RenderProperties* target, TreeInfo& info) {
-    mTarget = target;
-    bool finished = animateFrame(info.frameTimeMs);
-    mTarget = NULL;
-    return finished;
+void RenderPropertyAnimator::setValue(float value) {
+    (target()->animatorProperties().*mPropertyAccess.setter)(value);
 }
 
-void RenderPropertyAnimatorImpl::onAnimationStarted() {
-    mFromValue = (mTarget->*mGetter)();
+/************************************************************
+ *  CanvasPropertyPrimitiveAnimator
+ ************************************************************/
 
-    if (mDeltaValueType == RenderPropertyAnimator::ABSOLUTE) {
-        mDeltaValue = (mDeltaValue - mFromValue);
-        mDeltaValueType = RenderPropertyAnimator::DELTA;
+CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(
+                CanvasPropertyPrimitive* property, DeltaValueType deltaType, float deltaValue)
+        : BaseRenderNodeAnimator(deltaType, deltaValue)
+        , mProperty(property) {
+}
+
+float CanvasPropertyPrimitiveAnimator::getValue() const {
+    return mProperty->value;
+}
+
+void CanvasPropertyPrimitiveAnimator::setValue(float value) {
+    mProperty->value = value;
+}
+
+/************************************************************
+ *  CanvasPropertySkPaintAnimator
+ ************************************************************/
+
+CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(
+                CanvasPropertyPaint* property, PaintField field,
+                DeltaValueType deltaType, float deltaValue)
+        : BaseRenderNodeAnimator(deltaType, deltaValue)
+        , mProperty(property)
+        , mField(field) {
+}
+
+float CanvasPropertyPaintAnimator::getValue() const {
+    switch (mField) {
+    case STROKE_WIDTH:
+        return mProperty->value.getStrokeWidth();
+    case ALPHA:
+        return mProperty->value.getAlpha();
     }
+    LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
+    return -1;
 }
 
-void RenderPropertyAnimatorImpl::onAnimationUpdated(float fraction) {
-    float value = mFromValue + (mDeltaValue * fraction);
-    (mTarget->*mSetter)(value);
+static uint8_t to_uint8(float value) {
+    int c = (int) (value + .5f);
+    return static_cast<uint8_t>( c < 0 ? 0 : c > 255 ? 255 : c );
+}
+
+void CanvasPropertyPaintAnimator::setValue(float value) {
+    switch (mField) {
+    case STROKE_WIDTH:
+        mProperty->value.setStrokeWidth(value);
+        return;
+    case ALPHA:
+        mProperty->value.setAlpha(to_uint8(value));
+        return;
+    }
+    LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
 }
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index 1c8361b..52a1807 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -17,18 +17,73 @@
 #define ANIMATOR_H
 
 #include <cutils/compiler.h>
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
 
+#include "CanvasProperty.h"
 #include "Interpolator.h"
 #include "TreeInfo.h"
-#include "utils/VirtualLightRefBase.h"
+#include "utils/Macros.h"
 
 namespace android {
 namespace uirenderer {
 
+class RenderNode;
 class RenderProperties;
-class RenderPropertyAnimatorImpl;
 
-class RenderPropertyAnimator : public VirtualLightRefBase {
+class AnimationListener : public VirtualLightRefBase {
+public:
+    ANDROID_API virtual void onAnimationFinished(BaseAnimator*) = 0;
+protected:
+    ANDROID_API virtual ~AnimationListener() {}
+};
+
+// Helper class to contain generic animator helpers
+class BaseAnimator : public VirtualLightRefBase {
+    PREVENT_COPY_AND_ASSIGN(BaseAnimator);
+public:
+
+    ANDROID_API void setInterpolator(Interpolator* interpolator);
+    ANDROID_API void setDuration(nsecs_t durationInMs);
+    ANDROID_API nsecs_t duration() { return mDuration; }
+    ANDROID_API void setListener(AnimationListener* listener) {
+        mListener = listener;
+    }
+
+    bool isFinished() { return mPlayState == FINISHED; }
+
+protected:
+    BaseAnimator();
+    virtual ~BaseAnimator();
+
+    // This is the main animation entrypoint that subclasses should call
+    // to generate the onAnimation* lifecycle events
+    // Returns true if the animation has finished, false otherwise
+    bool animateFrame(TreeInfo& info);
+
+    // Called when PlayState switches from PENDING to RUNNING
+    virtual void onAnimationStarted() {}
+    virtual void onAnimationUpdated(float fraction) = 0;
+    virtual void onAnimationFinished() {}
+
+private:
+    void callOnFinishedListener(TreeInfo& info);
+
+    enum PlayState {
+        PENDING,
+        RUNNING,
+        FINISHED,
+    };
+
+    Interpolator* mInterpolator;
+    PlayState mPlayState;
+    long mStartTime;
+    long mDuration;
+
+   sp<AnimationListener> mListener;
+};
+
+class BaseRenderNodeAnimator : public BaseAnimator {
 public:
     // Since the UI thread doesn't necessarily know what the current values
     // actually are and thus can't do the calculations, this is used to inform
@@ -43,6 +98,29 @@
         DELTA,
     };
 
+    bool animate(RenderNode* target, TreeInfo& info);
+
+protected:
+    BaseRenderNodeAnimator(DeltaValueType deltaType, float deltaValue);
+
+    RenderNode* target() const { return mTarget; }
+    virtual float getValue() const = 0;
+    virtual void setValue(float value) = 0;
+
+private:
+    virtual void onAnimationStarted();
+    virtual void onAnimationUpdated(float fraction);
+
+    // mTarget is only valid inside animate()
+    RenderNode* mTarget;
+
+    BaseRenderNodeAnimator::DeltaValueType mDeltaValueType;
+    float mDeltaValue;
+    float mFromValue;
+};
+
+class RenderPropertyAnimator : public BaseRenderNodeAnimator {
+public:
     enum RenderProperty {
         TRANSLATION_X = 0,
         TRANSLATION_Y,
@@ -58,19 +136,53 @@
         ALPHA,
     };
 
-    ANDROID_API void setInterpolator(Interpolator* interpolator);
-    ANDROID_API void setDuration(nsecs_t durationInMs);
-    ANDROID_API bool isFinished();
-
-    bool animate(RenderProperties* target, TreeInfo& info);
+    ANDROID_API RenderPropertyAnimator(RenderProperty property,
+                DeltaValueType deltaType, float deltaValue);
 
 protected:
-    ANDROID_API RenderPropertyAnimator(RenderProperty property, DeltaValueType deltaType,
-            float deltaValue);
-    ANDROID_API virtual ~RenderPropertyAnimator();
+    ANDROID_API virtual float getValue() const;
+    ANDROID_API virtual void setValue(float value);
 
 private:
-    RenderPropertyAnimatorImpl* mImpl;
+    typedef void (RenderProperties::*SetFloatProperty)(float value);
+    typedef float (RenderProperties::*GetFloatProperty)() const;
+
+    struct PropertyAccessors {
+        GetFloatProperty getter;
+        SetFloatProperty setter;
+    };
+
+    PropertyAccessors mPropertyAccess;
+
+    static const PropertyAccessors PROPERTY_ACCESSOR_LUT[];
+};
+
+class CanvasPropertyPrimitiveAnimator : public BaseRenderNodeAnimator {
+public:
+    ANDROID_API CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive* property,
+            DeltaValueType deltaType, float deltaValue);
+protected:
+    ANDROID_API virtual float getValue() const;
+    ANDROID_API virtual void setValue(float value);
+private:
+    sp<CanvasPropertyPrimitive> mProperty;
+};
+
+class CanvasPropertyPaintAnimator : public BaseRenderNodeAnimator {
+public:
+    enum PaintField {
+        STROKE_WIDTH = 0,
+        ALPHA,
+    };
+
+    ANDROID_API CanvasPropertyPaintAnimator(CanvasPropertyPaint* property,
+            PaintField field, DeltaValueType deltaType, float deltaValue);
+protected:
+    ANDROID_API virtual float getValue() const;
+    ANDROID_API virtual void setValue(float value);
+private:
+    sp<CanvasPropertyPaint> mProperty;
+    PaintField mField;
 };
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index df2123b..43223ec 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -691,9 +691,10 @@
     propertyAmbientShadowStrength = 25;
     propertySpotShadowStrength = 25;
 
-    propertyLightPosXScale = 0.5f;
-    propertyLightPosYScale = 0.0f;
-    propertyLightPosZScale = 1.0f;
+    propertyLightDiameter = -1.0f;
+    propertyLightPosY = -1.0f;
+    propertyLightPosZ = -1.0f;
+    propertyAmbientRatio = -1.0f;
 }
 
 void Caches::setTempProperty(const char* name, const char* value) {
@@ -706,17 +707,21 @@
         propertySpotShadowStrength = atoi(value);
         ALOGD("spot shadow strength = 0x%x out of 0xff", propertySpotShadowStrength);
         return;
-    } else if (!strcmp(name, "lightPosXScale")) {
-        propertyLightPosXScale = fmin(fmax(atof(value), 0.0), 1.0);
-        ALOGD("lightPos X Scale = %.2f", propertyLightPosXScale);
+    } else if (!strcmp(name, "ambientRatio")) {
+        propertyAmbientRatio = fmin(fmax(atof(value), 0.0), 10.0);
+        ALOGD("ambientRatio = %.2f", propertyAmbientRatio);
         return;
-    }  else if (!strcmp(name, "lightPosYScale")) {
-        propertyLightPosYScale = fmin(fmax(atof(value), 0.0), 1.0);
-        ALOGD("lightPos Y Scale = %.2f", propertyLightPosXScale);
+    } else if (!strcmp(name, "lightDiameter")) {
+        propertyLightDiameter = fmin(fmax(atof(value), 0.0), 3000.0);
+        ALOGD("lightDiameter = %.2f", propertyLightDiameter);
         return;
-    }  else if (!strcmp(name, "lightPosZScale")) {
-        propertyLightPosZScale = fmin(fmax(atof(value), 0.0), 1.0);
-        ALOGD("lightPos Z Scale = %.2f", propertyLightPosXScale);
+    }  else if (!strcmp(name, "lightPosY")) {
+        propertyLightPosY = fmin(fmax(atof(value), 0.0), 3000.0);
+        ALOGD("lightPos Y = %.2f", propertyLightPosY);
+        return;
+    }  else if (!strcmp(name, "lightPosZ")) {
+        propertyLightPosZ = fmin(fmax(atof(value), 0.0), 3000.0);
+        ALOGD("lightPos Z = %.2f", propertyLightPosZ);
         return;
     }
     ALOGD("    failed");
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index ba3ccaf..2e2ee15 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -352,13 +352,10 @@
     void initTempProperties();
     void setTempProperty(const char* name, const char* value);
 
-    // These scaling factors range from 0 to 1, to scale the light position
-    // within the bound of (screenwidth, screenheight, max(screenwidth, screenheight));
-    // The default scale is (0.5, 0, 1) which put the light at
-    // (screenwidth / 2, 0, max(screenwidth, screenheight)).
-    float propertyLightPosXScale;
-    float propertyLightPosYScale;
-    float propertyLightPosZScale;
+    float propertyLightDiameter;
+    float propertyLightPosY;
+    float propertyLightPosZ;
+    float propertyAmbientRatio;
     int propertyAmbientShadowStrength;
     int propertySpotShadowStrength;
 
diff --git a/libs/hwui/CanvasProperty.h b/libs/hwui/CanvasProperty.h
new file mode 100644
index 0000000..6074394
--- /dev/null
+++ b/libs/hwui/CanvasProperty.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef CANVASPROPERTY_H
+#define CANVASPROPERTY_H
+
+#include <utils/RefBase.h>
+
+#include "utils/Macros.h"
+
+#include <SkPaint.h>
+
+namespace android {
+namespace uirenderer {
+
+class CanvasPropertyPrimitive : public VirtualLightRefBase {
+    PREVENT_COPY_AND_ASSIGN(CanvasPropertyPrimitive);
+public:
+    CanvasPropertyPrimitive(float initialValue) : value(initialValue) {}
+
+    float value;
+};
+
+class CanvasPropertyPaint : public VirtualLightRefBase {
+    PREVENT_COPY_AND_ASSIGN(CanvasPropertyPaint);
+public:
+    CanvasPropertyPaint(const SkPaint& initialValue) : value(initialValue) {}
+
+    SkPaint value;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* CANVASPROPERTY_H */
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index 3d58964..45b6624 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -190,7 +190,7 @@
 
         // Overlapping other operations is only allowed for text without shadow. For other ops,
         // multiDraw isn't guaranteed to overdraw correctly
-        if (!isTextBatch || state->mDrawModifiers.mHasShadow) {
+        if (!isTextBatch || op->hasTextShadow()) {
             if (intersects(state->mBounds)) return false;
         }
         const DeferredDisplayState* lhs = state;
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index fe70d13..b2ead5b 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -41,7 +41,6 @@
 #include "Matrix.h"
 #include "DeferredDisplayList.h"
 #include "RenderProperties.h"
-#include "utils/VirtualLightRefBase.h"
 
 class SkBitmap;
 class SkPaint;
@@ -140,6 +139,14 @@
     void addChild(DrawDisplayListOp* childOp);
     const Vector<DrawDisplayListOp*>& children() { return mChildren; }
 
+    void refProperty(CanvasPropertyPrimitive* prop) {
+        mReferenceHolders.push(prop);
+    }
+
+    void refProperty(CanvasPropertyPaint* prop) {
+        mReferenceHolders.push(prop);
+    }
+
 private:
     Vector< sp<VirtualLightRefBase> > mReferenceHolders;
 
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 6dfb918..f1d70eb 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -183,6 +183,10 @@
         return OpenGLRenderer::getAlphaDirect(mPaint);
     }
 
+    virtual bool hasTextShadow() const {
+        return false;
+    }
+
     inline float strokeWidthOutset() {
         // since anything AA stroke with less than 1.0 pixel width is drawn with an alpha-reduced
         // 1.0 stroke, treat 1.0 as minimum.
@@ -244,11 +248,11 @@
 
     bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) {
         localBounds.set(mLocalBounds);
-        if (drawModifiers.mHasShadow) {
-            // TODO: inspect paint's looper directly
+        OpenGLRenderer::TextShadow textShadow;
+        if (OpenGLRenderer::getTextShadow(mPaint, &textShadow)) {
             Rect shadow(mLocalBounds);
-            shadow.translate(drawModifiers.mShadowDx, drawModifiers.mShadowDy);
-            shadow.outset(drawModifiers.mShadowRadius);
+            shadow.translate(textShadow.dx, textShadow.dx);
+            shadow.outset(textShadow.radius);
             localBounds.unionWith(shadow);
         }
         return true;
@@ -619,41 +623,6 @@
     SkiaShader* mShader;
 };
 
-class ResetShadowOp : public StateOp {
-public:
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
-        renderer.resetShadow();
-    }
-
-    virtual void output(int level, uint32_t logFlags) const {
-        OP_LOGS("ResetShadow");
-    }
-
-    virtual const char* name() { return "ResetShadow"; }
-};
-
-class SetupShadowOp : public StateOp {
-public:
-    SetupShadowOp(float radius, float dx, float dy, int color)
-            : mRadius(radius), mDx(dx), mDy(dy), mColor(color) {}
-
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
-        renderer.setupShadow(mRadius, mDx, mDy, mColor);
-    }
-
-    virtual void output(int level, uint32_t logFlags) const {
-        OP_LOG("SetupShadow, radius %f, %f, %f, color %#x", mRadius, mDx, mDy, mColor);
-    }
-
-    virtual const char* name() { return "SetupShadow"; }
-
-private:
-    float mRadius;
-    float mDx;
-    float mDy;
-    int mColor;
-};
-
 class ResetPaintFilterOp : public StateOp {
 public:
     virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
@@ -1198,6 +1167,27 @@
     float mRadius;
 };
 
+class DrawCirclePropsOp : public DrawOp {
+public:
+    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 output(int level, uint32_t logFlags) const {
+        OP_LOG("Draw Circle Props x %p, y %p, r %p", mX, mY, mRadius);
+    }
+
+    virtual const char* name() { return "DrawCircleProps"; }
+
+private:
+    float* mX;
+    float* mY;
+    float* mRadius;
+};
+
 class DrawOvalOp : public DrawStrokableOp {
 public:
     DrawOvalOp(float left, float top, float right, float bottom, const SkPaint* paint)
@@ -1330,6 +1320,10 @@
         OP_LOG("Draw some text, %d bytes", mBytesCount);
     }
 
+    virtual bool hasTextShadow() const {
+        return OpenGLRenderer::hasTextShadow(mPaint);
+    }
+
     virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
             const DeferredDisplayState& state) {
         const SkPaint* paint = getPaint(renderer);
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index e36d975..a4bce3a 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -57,9 +57,6 @@
 }
 
 void DisplayListRenderer::setViewport(int width, int height) {
-    // TODO: DisplayListRenderer shouldn't have a projection matrix, as it should never be used
-    mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1);
-
     initializeViewport(width, height);
 }
 
@@ -299,6 +296,17 @@
     return DrawGlInfo::kStatusDone;
 }
 
+status_t DisplayListRenderer::drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
+        CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) {
+    mDisplayListData->refProperty(x);
+    mDisplayListData->refProperty(y);
+    mDisplayListData->refProperty(radius);
+    mDisplayListData->refProperty(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);
@@ -399,16 +407,6 @@
     addStateOp(new (alloc()) SetupShaderOp(shader));
 }
 
-void DisplayListRenderer::resetShadow() {
-    addStateOp(new (alloc()) ResetShadowOp());
-    OpenGLRenderer::resetShadow();
-}
-
-void DisplayListRenderer::setupShadow(float radius, float dx, float dy, int color) {
-    addStateOp(new (alloc()) SetupShadowOp(radius, dx, dy, color));
-    OpenGLRenderer::setupShadow(radius, dx, dy, color);
-}
-
 void DisplayListRenderer::resetPaintFilter() {
     addStateOp(new (alloc()) ResetPaintFilterOp());
 }
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 04c5a73..185179a 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -102,9 +102,6 @@
     virtual void resetShader();
     virtual void setupShader(SkiaShader* shader);
 
-    virtual void resetShadow();
-    virtual void setupShadow(float radius, float dx, float dy, int color);
-
     virtual void resetPaintFilter();
     virtual void setupPaintFilter(int clearBits, int setBits);
 
@@ -135,6 +132,8 @@
     virtual status_t 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 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,
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index b52003c..647c281 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -737,30 +737,34 @@
             // a null path is OK because there are no custom kernels used
             // hence nothing gets cached by RS
             if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
+                mRs.clear();
                 ALOGE("blur RS failed to init");
+            } else {
+                mRsElement = RSC::Element::A_8(mRs);
+                mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
             }
-
-            mRsElement = RSC::Element::A_8(mRs);
-            mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
         }
+        if (mRs != 0) {
+            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,
+                    RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
+                    *image);
+            RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
+                    RS_ALLOCATION_MIPMAP_NONE,
+                    RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
+                    outImage);
 
-        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, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
-                *image);
-        RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
-                RS_ALLOCATION_MIPMAP_NONE, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
-                outImage);
+            mRsScript->setRadius(radius);
+            mRsScript->setInput(ain);
+            mRsScript->forEach(aout);
 
-        mRsScript->setRadius(radius);
-        mRsScript->setInput(ain);
-        mRsScript->forEach(aout);
+            // replace the original image's pointer, avoiding a copy back to the original buffer
+            free(*image);
+            *image = outImage;
 
-        // replace the original image's pointer, avoiding a copy back to the original buffer
-        free(*image);
-        *image = outImage;
-
-        return;
+            return;
+        }
     }
 #endif
 
diff --git a/libs/hwui/Interpolator.cpp b/libs/hwui/Interpolator.cpp
index 004ddf5..1f84b86 100644
--- a/libs/hwui/Interpolator.cpp
+++ b/libs/hwui/Interpolator.cpp
@@ -13,9 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+#define LOG_TAG "Interpolator"
+
 #include "Interpolator.h"
 
-#include <math.h>
+#include <cmath>
+#include <cutils/log.h>
+
+#include "utils/MathUtils.h"
 
 namespace android {
 namespace uirenderer {
@@ -28,5 +34,90 @@
     return (float)(cosf((input + 1) * M_PI) / 2.0f) + 0.5f;
 }
 
+float AccelerateInterpolator::interpolate(float input) {
+    if (mFactor == 1.0f) {
+        return input * input;
+    } else {
+        return pow(input, mDoubleFactor);
+    }
+}
+
+float AnticipateInterpolator::interpolate(float t) {
+    return t * t * ((mTension + 1) * t - mTension);
+}
+
+static float a(float t, float s) {
+    return t * t * ((s + 1) * t - s);
+}
+
+static float o(float t, float s) {
+    return t * t * ((s + 1) * t + s);
+}
+
+float AnticipateOvershootInterpolator::interpolate(float t) {
+    if (t < 0.5f) return 0.5f * a(t * 2.0f, mTension);
+    else return 0.5f * (o(t * 2.0f - 2.0f, mTension) + 2.0f);
+}
+
+static float bounce(float t) {
+    return t * t * 8.0f;
+}
+
+float BounceInterpolator::interpolate(float t) {
+    t *= 1.1226f;
+    if (t < 0.3535f) return bounce(t);
+    else if (t < 0.7408f) return bounce(t - 0.54719f) + 0.7f;
+    else if (t < 0.9644f) return bounce(t - 0.8526f) + 0.9f;
+    else return bounce(t - 1.0435f) + 0.95f;
+}
+
+float CycleInterpolator::interpolate(float input) {
+    return sinf(2 * mCycles * M_PI * input);
+}
+
+float DecelerateInterpolator::interpolate(float input) {
+    float result;
+    if (mFactor == 1.0f) {
+        result = 1.0f - (1.0f - input) * (1.0f - input);
+    } else {
+        result = 1.0f - pow((1.0f - input), 2 * mFactor);
+    }
+    return result;
+}
+
+float OvershootInterpolator::interpolate(float t) {
+    t -= 1.0f;
+    return t * t * ((mTension + 1) * t + mTension) + 1.0f;
+}
+
+LUTInterpolator::LUTInterpolator(float* values, size_t size) {
+    mValues = values;
+    mSize = size;
+}
+
+LUTInterpolator::~LUTInterpolator() {
+    delete mValues;
+    mValues = 0;
+}
+
+float LUTInterpolator::interpolate(float input) {
+    float lutpos = input * mSize;
+    if (lutpos >= (mSize - 1)) {
+        return mValues[mSize - 1];
+    }
+
+    float ipart, weight;
+    weight = modff(lutpos, &ipart);
+
+    int i1 = (int) ipart;
+    int i2 = MathUtils::min(i1 + 1, mSize - 1);
+
+    float v1 = mValues[i1];
+    float v2 = mValues[i2];
+
+    return MathUtils::lerp(v1, v2, weight);
+}
+
+
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/Interpolator.h b/libs/hwui/Interpolator.h
index 2cfb60c..dfa0a85 100644
--- a/libs/hwui/Interpolator.h
+++ b/libs/hwui/Interpolator.h
@@ -16,6 +16,10 @@
 #ifndef INTERPOLATOR_H
 #define INTERPOLATOR_H
 
+#include <stddef.h>
+
+#include <cutils/compiler.h>
+
 namespace android {
 namespace uirenderer {
 
@@ -31,12 +35,80 @@
     Interpolator() {}
 };
 
-class AccelerateDecelerateInterpolator : public Interpolator {
+class ANDROID_API AccelerateDecelerateInterpolator : public Interpolator {
 public:
-    AccelerateDecelerateInterpolator() {}
-    virtual ~AccelerateDecelerateInterpolator() {}
+    virtual float interpolate(float input);
+};
+
+class ANDROID_API AccelerateInterpolator : public Interpolator {
+public:
+    AccelerateInterpolator(float factor) : mFactor(factor), mDoubleFactor(factor*2) {}
+    virtual float interpolate(float input);
+private:
+    const float mFactor;
+    const float mDoubleFactor;
+};
+
+class ANDROID_API AnticipateInterpolator : public Interpolator {
+public:
+    AnticipateInterpolator(float tension) : mTension(tension) {}
+    virtual float interpolate(float input);
+private:
+    const float mTension;
+};
+
+class ANDROID_API AnticipateOvershootInterpolator : public Interpolator {
+public:
+    AnticipateOvershootInterpolator(float tension) : mTension(tension) {}
+    virtual float interpolate(float input);
+private:
+    const float mTension;
+};
+
+class ANDROID_API BounceInterpolator : public Interpolator {
+public:
+    virtual float interpolate(float input);
+};
+
+class ANDROID_API CycleInterpolator : public Interpolator {
+public:
+    CycleInterpolator(float cycles) : mCycles(cycles) {}
+    virtual float interpolate(float input);
+private:
+    const float mCycles;
+};
+
+class ANDROID_API DecelerateInterpolator : public Interpolator {
+public:
+    DecelerateInterpolator(float factor) : mFactor(factor) {}
+    virtual float interpolate(float input);
+private:
+    const float mFactor;
+};
+
+class ANDROID_API LinearInterpolator : public Interpolator {
+public:
+    virtual float interpolate(float input) { return input; }
+};
+
+class ANDROID_API OvershootInterpolator : public Interpolator {
+public:
+    OvershootInterpolator(float tension) : mTension(tension) {}
+    virtual float interpolate(float input);
+private:
+    const float mTension;
+};
+
+class ANDROID_API LUTInterpolator : public Interpolator {
+public:
+    LUTInterpolator(float* values, size_t size);
+    ~LUTInterpolator();
 
     virtual float interpolate(float input);
+
+private:
+    float* mValues;
+    size_t mSize;
 };
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 9606e58..de2fcf4 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -214,7 +214,7 @@
     DeferStateStruct deferredState(*deferredList, *renderer,
             RenderNode::kReplayFlag_ClipChildren);
 
-    renderer->initViewport(width, height);
+    renderer->initializeViewport(width, height);
     renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
             dirtyRect.right, dirtyRect.bottom, !isBlend());
 
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index e0ac2ba..c82197c 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -40,7 +40,7 @@
 }
 
 void LayerRenderer::setViewport(int width, int height) {
-    initViewport(width, height);
+    initializeViewport(width, height);
 }
 
 status_t LayerRenderer::prepareDirty(float left, float top, float right, float bottom,
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index f06106b..2268386 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -482,8 +482,8 @@
     sy = copysignf(sqrtf(len), data[mat4::kScaleY]);
 }
 
-void Matrix4::dump() const {
-    ALOGD("Matrix4[simple=%d, type=0x%x", isSimple(), getType());
+void Matrix4::dump(const char* label) const {
+    ALOGD("%s[simple=%d, type=0x%x", label ? label : "Matrix4", isSimple(), getType());
     ALOGD("  %f %f %f %f", data[kScaleX], data[kSkewX], data[8], data[kTranslateX]);
     ALOGD("  %f %f %f %f", data[kSkewY], data[kScaleY], data[9], data[kTranslateY]);
     ALOGD("  %f %f %f %f", data[2], data[6], data[kScaleZ], data[kTranslateZ]);
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 26cb05f..e33a001 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -209,7 +209,7 @@
 
     void decomposeScale(float& sx, float& sy) const;
 
-    void dump() const;
+    void dump(const char* label = NULL) const;
 
     static const Matrix4& identity();
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 4569152..4df97e6 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -37,6 +37,7 @@
 #include "PathTessellator.h"
 #include "Properties.h"
 #include "ShadowTessellator.h"
+#include "utils/GLUtils.h"
 #include "Vector.h"
 #include "VertexBuffer.h"
 
@@ -161,7 +162,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::setViewport(int width, int height) {
-    initViewport(width, height);
+    initializeViewport(width, height);
 
     glDisable(GL_DITHER);
     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -169,12 +170,6 @@
     glEnableVertexAttribArray(Program::kBindingPosition);
 }
 
-void OpenGLRenderer::initViewport(int width, int height) {
-    mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1);
-
-    initializeViewport(width, height);
-}
-
 void OpenGLRenderer::setupFrameState(float left, float top,
         float right, float bottom, bool opaque) {
     mCaches.clearGarbage();
@@ -243,7 +238,7 @@
 status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
     if (!opaque || mCountOverdraw) {
         mCaches.enableScissor();
-        mCaches.setScissor(left, currentSnapshot()->height - bottom, right - left, bottom - top);
+        mCaches.setScissor(left, getViewportHeight() - bottom, right - left, bottom - top);
         glClear(GL_COLOR_BUFFER_BIT);
         return DrawGlInfo::kStatusDrew;
     }
@@ -269,7 +264,7 @@
             clip = &(snapshot->layer->clipRect);
         }
 
-        startTiling(*clip, snapshot->height, opaque);
+        startTiling(*clip, getViewportHeight(), opaque);
     }
 }
 
@@ -296,24 +291,7 @@
 
     if (!suppressErrorChecks()) {
 #if DEBUG_OPENGL
-        GLenum status = GL_NO_ERROR;
-        while ((status = glGetError()) != GL_NO_ERROR) {
-            ALOGD("GL error from OpenGLRenderer: 0x%x", status);
-            switch (status) {
-                case GL_INVALID_ENUM:
-                    ALOGE("  GL_INVALID_ENUM");
-                    break;
-                case GL_INVALID_VALUE:
-                    ALOGE("  GL_INVALID_VALUE");
-                    break;
-                case GL_INVALID_OPERATION:
-                    ALOGE("  GL_INVALID_OPERATION");
-                    break;
-                case GL_OUT_OF_MEMORY:
-                    ALOGE("  Out of memory!");
-                    break;
-            }
-        }
+        GLUtils::dumpGLErrors();
 #endif
 
 #if DEBUG_MEMORY_USAGE
@@ -349,7 +327,7 @@
 
 void OpenGLRenderer::resume() {
     const Snapshot* snapshot = currentSnapshot();
-    glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
+    glViewport(0, 0, getViewportWidth(), getViewportHeight());
     glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
     debugOverdraw(true, false);
 
@@ -370,58 +348,17 @@
 }
 
 void OpenGLRenderer::resumeAfterLayer() {
-    const Snapshot* snapshot = currentSnapshot();
-    glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
-    glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
+    glViewport(0, 0, getViewportWidth(), getViewportHeight());
+    glBindFramebuffer(GL_FRAMEBUFFER, currentSnapshot()->fbo);
     debugOverdraw(true, false);
 
     mCaches.resetScissor();
     dirtyClip();
 }
 
-void OpenGLRenderer::detachFunctor(Functor* functor) {
-    mFunctors.remove(functor);
-}
-
-void OpenGLRenderer::attachFunctor(Functor* functor) {
-    mFunctors.add(functor);
-}
-
-status_t OpenGLRenderer::invokeFunctors(Rect& dirty) {
-    status_t result = DrawGlInfo::kStatusDone;
-    size_t count = mFunctors.size();
-
-    if (count > 0) {
-        interrupt();
-        SortedVector<Functor*> functors(mFunctors);
-        mFunctors.clear();
-
-        DrawGlInfo info;
-        info.clipLeft = 0;
-        info.clipTop = 0;
-        info.clipRight = 0;
-        info.clipBottom = 0;
-        info.isLayer = false;
-        info.width = 0;
-        info.height = 0;
-        memset(info.transform, 0, sizeof(float) * 16);
-
-        for (size_t i = 0; i < count; i++) {
-            Functor* f = functors.itemAt(i);
-            result |= (*f)(DrawGlInfo::kModeProcess, &info);
-        }
-        resume();
-    }
-
-    return result;
-}
-
 status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
     if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
 
-    detachFunctor(functor);
-
-
     Rect clip(*currentClipRect());
     clip.snapToPixelBoundaries();
 
@@ -437,8 +374,8 @@
     info.clipRight = clip.right;
     info.clipBottom = clip.bottom;
     info.isLayer = hasLayer();
-    info.width = currentSnapshot()->viewport.getWidth();
-    info.height = currentSnapshot()->height;
+    info.width = getViewportWidth();
+    info.height = getViewportHeight();
     currentTransform()->copyTo(&info.transform[0]);
 
     bool dirtyClip = mDirtyClip;
@@ -493,7 +430,7 @@
         const Rect* clip = &mTilingClip;
 
         mCaches.enableScissor();
-        mCaches.setScissor(clip->left, firstSnapshot()->height - clip->bottom,
+        mCaches.setScissor(clip->left, firstSnapshot()->getViewportHeight() - clip->bottom,
                 clip->right - clip->left, clip->bottom - clip->top);
 
         // 1x overdraw
@@ -677,14 +614,12 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
-    bool restoreOrtho = removed.flags & Snapshot::kFlagDirtyOrtho;
+    bool restoreViewport = removed.flags & Snapshot::kFlagIsFboLayer;
     bool restoreClip = removed.flags & Snapshot::kFlagClipSet;
     bool restoreLayer = removed.flags & Snapshot::kFlagIsLayer;
 
-    if (restoreOrtho) {
-        const Rect& r = restored.viewport;
-        glViewport(r.left, r.top, r.right, r.bottom);
-        mViewProjMatrix.load(removed.orthoMatrix); // TODO: should ortho be stored in 'restored'?
+    if (restoreViewport) {
+        glViewport(0, 0, getViewportWidth(), getViewportHeight());
     }
 
     if (restoreClip) {
@@ -727,7 +662,7 @@
         // When the layer is not an FBO, we may use glCopyTexImage so we
         // need to make sure the layer does not extend outside the bounds
         // of the framebuffer
-        if (!bounds.intersect(currentSnapshot()->previous->viewport)) {
+        if (!bounds.intersect(Rect(0, 0, getViewportWidth(), getViewportHeight()))) {
             bounds.setEmpty();
         } else if (fboLayer) {
             clip.set(bounds);
@@ -775,7 +710,7 @@
         if (!currentSnapshot()->isIgnored()) {
             mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
             mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
-            mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
+            mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
         }
     }
 
@@ -887,8 +822,9 @@
                 layer->setEmpty(false);
             }
 
-            glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left,
-                    mSnapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
+            glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
+                    bounds.left, getViewportHeight() - bounds.bottom,
+                    bounds.getWidth(), bounds.getHeight());
 
             // Enqueue the buffer coordinates to clear the corresponding region later
             mLayers.push(new Rect(bounds));
@@ -903,14 +839,11 @@
     layer->setFbo(mCaches.fboCache.get());
 
     mSnapshot->region = &mSnapshot->layer->region;
-    mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer |
-            Snapshot::kFlagDirtyOrtho;
+    mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
     mSnapshot->fbo = layer->getFbo();
     mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
     mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
-    mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
-    mSnapshot->height = bounds.getHeight();
-    mSnapshot->orthoMatrix.load(mViewProjMatrix);
+    mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
 
     endTiling();
     debugOverdraw(false, false);
@@ -940,8 +873,6 @@
     // Change the ortho projection
     glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
 
-    // TODO: determine best way to support 3d drawing within HW layers
-    mViewProjMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
 
     return true;
 }
@@ -1476,7 +1407,7 @@
     Rect clip(*currentClipRect());
     clip.snapToPixelBoundaries();
 
-    if (mCaches.setScissor(clip.left, currentSnapshot()->height - clip.bottom,
+    if (mCaches.setScissor(clip.left, getViewportHeight() - clip.bottom,
             clip.getWidth(), clip.getHeight())) {
         mDirtyClip = false;
     }
@@ -1745,18 +1676,20 @@
 
 void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset,
         float left, float top, float right, float bottom, bool ignoreTransform) {
-    mModelView.loadTranslate(left, top, 0.0f);
+    mModelViewMatrix.loadTranslate(left, top, 0.0f);
     if (mode == kModelViewMode_TranslateAndScale) {
-        mModelView.scale(right - left, bottom - top, 1.0f);
+        mModelViewMatrix.scale(right - left, bottom - top, 1.0f);
     }
 
     bool dirty = right - left > 0.0f && bottom - top > 0.0f;
-    if (!ignoreTransform) {
-        mCaches.currentProgram->set(mViewProjMatrix, mModelView, *currentTransform(), offset);
-        if (dirty && mTrackDirtyRegions) dirtyLayer(left, top, right, bottom, *currentTransform());
-    } else {
-        mCaches.currentProgram->set(mViewProjMatrix, mModelView, mat4::identity(), offset);
-        if (dirty && mTrackDirtyRegions) dirtyLayer(left, top, right, bottom);
+    const Matrix4& transformMatrix = ignoreTransform ? Matrix4::identity() : *currentTransform();
+    mCaches.currentProgram->set(mSnapshot->getOrthoMatrix(), mModelViewMatrix, transformMatrix, offset);
+    if (dirty && mTrackDirtyRegions) {
+        if (!ignoreTransform) {
+            dirtyLayer(left, top, right, bottom, *currentTransform());
+        } else {
+            dirtyLayer(left, top, right, bottom);
+        }
     }
 }
 
@@ -1780,11 +1713,11 @@
             // compensate.
             mat4 modelViewWithoutTransform;
             modelViewWithoutTransform.loadInverse(*currentTransform());
-            modelViewWithoutTransform.multiply(mModelView);
-            mModelView.load(modelViewWithoutTransform);
+            modelViewWithoutTransform.multiply(mModelViewMatrix);
+            mModelViewMatrix.load(modelViewWithoutTransform);
         }
         mDrawModifiers.mShader->setupProgram(mCaches.currentProgram,
-                mModelView, *mSnapshot, &mTextureUnit);
+                mModelViewMatrix, *mSnapshot, &mTextureUnit);
     }
 }
 
@@ -2694,28 +2627,32 @@
         FontRenderer& fontRenderer, int alpha, float x, float y) {
     mCaches.activeTexture(0);
 
+    TextShadow textShadow;
+    if (!getTextShadow(paint, &textShadow)) {
+        LOG_ALWAYS_FATAL("failed to query shadow attributes");
+    }
+
     // NOTE: The drop shadow will not perform gamma correction
     //       if shader-based correction is enabled
     mCaches.dropShadowCache.setFontRenderer(fontRenderer);
     const ShadowTexture* shadow = mCaches.dropShadowCache.get(
-            paint, text, bytesCount, count, mDrawModifiers.mShadowRadius, positions);
+            paint, text, bytesCount, count, textShadow.radius, positions);
     // If the drop shadow exceeds the max texture size or couldn't be
     // allocated, skip drawing
     if (!shadow) return;
     const AutoTexture autoCleanup(shadow);
 
-    const float sx = x - shadow->left + mDrawModifiers.mShadowDx;
-    const float sy = y - shadow->top + mDrawModifiers.mShadowDy;
+    const float sx = x - shadow->left + textShadow.dx;
+    const float sy = y - shadow->top + textShadow.dy;
 
-    const int shadowAlpha = ((mDrawModifiers.mShadowColor >> 24) & 0xFF) * mSnapshot->alpha;
-    int shadowColor = mDrawModifiers.mShadowColor;
+    const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * mSnapshot->alpha;
     if (mDrawModifiers.mShader) {
-        shadowColor = 0xffffffff;
+        textShadow.color = SK_ColorWHITE;
     }
 
     setupDraw();
     setupDrawWithTexture(true);
-    setupDrawAlpha8Color(shadowColor, shadowAlpha < 255 ? shadowAlpha : alpha);
+    setupDrawAlpha8Color(textShadow.color, shadowAlpha < 255 ? shadowAlpha : alpha);
     setupDrawColorFilter(getColorFilter(paint));
     setupDrawShader();
     setupDrawBlending(paint, true);
@@ -2732,7 +2669,7 @@
 }
 
 bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
-    float alpha = (mDrawModifiers.mHasShadow ? 1.0f : paint->getAlpha()) * mSnapshot->alpha;
+    float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * mSnapshot->alpha;
     return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
 }
 
@@ -2764,7 +2701,7 @@
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
 
-    if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
+    if (CC_UNLIKELY(hasTextShadow(paint))) {
         drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
                 alpha, 0.0f, 0.0f);
     }
@@ -2841,7 +2778,7 @@
 
     FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
 
-    if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
+    if (CC_UNLIKELY(hasTextShadow(paint))) {
         fontRenderer.setFont(paint, mat4::identity());
         drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
                 alpha, oldX, oldY);
@@ -3062,22 +2999,6 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-// Drop shadow
-///////////////////////////////////////////////////////////////////////////////
-
-void OpenGLRenderer::resetShadow() {
-    mDrawModifiers.mHasShadow = false;
-}
-
-void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) {
-    mDrawModifiers.mHasShadow = true;
-    mDrawModifiers.mShadowRadius = radius;
-    mDrawModifiers.mShadowDx = dx;
-    mDrawModifiers.mShadowDy = dy;
-    mDrawModifiers.mShadowColor = color;
-}
-
-///////////////////////////////////////////////////////////////////////////////
 // Draw filters
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -3291,10 +3212,8 @@
     if (mCaches.propertySpotShadowStrength > 0) {
         paint.setARGB(casterAlpha * mCaches.propertySpotShadowStrength, 0, 0, 0);
         VertexBuffer spotShadowVertexBuffer;
-        Vector3 lightPosScale(mCaches.propertyLightPosXScale,
-                mCaches.propertyLightPosYScale, mCaches.propertyLightPosZScale);
         VertexBufferMode vertexBufferMode = ShadowTessellator::tessellateSpotShadow(
-                isCasterOpaque, casterPolygon, casterVertexCount, lightPosScale,
+                isCasterOpaque, casterPolygon, casterVertexCount,
                 *currentTransform(), getWidth(), getHeight(), casterBounds, localClip,
                 spotShadowVertexBuffer);
         drawVertexBuffer(vertexBufferMode, spotShadowVertexBuffer, &paint);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index b49d1e1..b58b817 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -29,6 +29,7 @@
 #include <SkShader.h>
 #include <SkXfermode.h>
 
+#include <utils/Blur.h>
 #include <utils/Functor.h>
 #include <utils/RefBase.h>
 #include <utils/SortedVector.h>
@@ -49,6 +50,7 @@
 #include "UvMapper.h"
 #include "Vertex.h"
 #include "Caches.h"
+#include "CanvasProperty.h"
 
 namespace android {
 namespace uirenderer {
@@ -71,13 +73,6 @@
     SkiaShader* mShader;
     float mOverrideLayerAlpha;
 
-    // Drop shadow
-    bool mHasShadow;
-    float mShadowRadius;
-    float mShadowDx;
-    float mShadowDy;
-    int mShadowColor;
-
     // Draw filters
     bool mHasDrawFilter;
     int mPaintFilterClearBits;
@@ -150,9 +145,6 @@
         return mCountOverdraw ? mOverdraw : 0.0f;
     }
 
-    ANDROID_API status_t invokeFunctors(Rect& dirty);
-    ANDROID_API void detachFunctor(Functor* functor);
-    ANDROID_API void attachFunctor(Functor* functor);
     virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty);
 
     ANDROID_API void pushLayerUpdate(Layer* layer);
@@ -200,6 +192,12 @@
     virtual status_t 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 drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
+            CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) {
+        // TODO: Remove once android_view_GLES20Canvas uses DisplayListRenderer
+        // directly
+        return drawCircle(x->value, y->value, radius->value, &paint->value);
+    }
     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,
@@ -222,9 +220,6 @@
     virtual void resetShader();
     virtual void setupShader(SkiaShader* shader);
 
-    virtual void resetShadow();
-    virtual void setupShadow(float radius, float dx, float dy, int color);
-
     virtual void resetPaintFilter();
     virtual void setupPaintFilter(int clearBits, int setBits);
 
@@ -259,8 +254,8 @@
         return mSnapshot->clipRegion->isEmpty();
     }
 
-    int getViewportWidth() { return currentSnapshot()->viewport.getWidth(); }
-    int getViewportHeight() { return currentSnapshot()->viewport.getHeight(); }
+    int getViewportWidth() { return currentSnapshot()->getViewportWidth(); }
+    int getViewportHeight() { return currentSnapshot()->getViewportHeight(); }
 
     /**
      * Scales the alpha on the current snapshot. This alpha value will be modulated
@@ -312,6 +307,31 @@
         return paint->getAlpha();
     }
 
+    struct TextShadow {
+        SkScalar radius;
+        float dx;
+        float dy;
+        SkColor color;
+    };
+
+    static inline bool getTextShadow(const SkPaint* paint, TextShadow* textShadow) {
+        SkDrawLooper::BlurShadowRec blur;
+        if (paint && paint->getLooper() && paint->getLooper()->asABlurShadow(&blur)) {
+            if (textShadow) {
+                textShadow->radius = Blur::convertSigmaToRadius(blur.fSigma);
+                textShadow->dx = blur.fOffset.fX;
+                textShadow->dy = blur.fOffset.fY;
+                textShadow->color = blur.fColor;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    static inline bool hasTextShadow(const SkPaint* paint) {
+        return getTextShadow(paint, NULL);
+    }
+
     /**
      * Return the best transform to use to rasterize text given a full
      * transform matrix.
@@ -334,12 +354,6 @@
 
 protected:
     /**
-     * Computes the projection matrix, initialize the first snapshot
-     * and stores the dimensions of the render target.
-     */
-    void initViewport(int width, int height);
-
-    /**
      * Perform the setup specific to a frame. This method does not
      * issue any OpenGL commands.
      */
@@ -910,24 +924,21 @@
      */
     Texture* getTexture(const SkBitmap* bitmap);
 
-    // Matrix used for view/projection in shaders
-    mat4 mViewProjMatrix;
-
     /**
      * Model-view matrix used to position/size objects
      *
      * Stores operation-local modifications to the draw matrix that aren't incorporated into the
      * currentTransform().
      *
-     * If generated with kModelViewMode_Translate, the mModelView will reflect an x/y offset,
+     * If generated with kModelViewMode_Translate, mModelViewMatrix will reflect an x/y offset,
      * e.g. the offset in drawLayer(). If generated with kModelViewMode_TranslateAndScale,
-     * mModelView will reflect a translation and scale, e.g. the translation and scale required to
-     * make VBO 0 (a rect of (0,0,1,1)) scaled to match the x,y offset, and width/height of a
-     * bitmap.
+     * mModelViewMatrix will reflect a translation and scale, e.g. the translation and scale
+     * required to make VBO 0 (a rect of (0,0,1,1)) scaled to match the x,y offset, and width/height
+     * of a bitmap.
      *
      * Used as input to SkiaShader transformation.
      */
-    mat4 mModelView;
+    mat4 mModelViewMatrix;
 
     // State used to define the clipping region
     Rect mTilingClip;
@@ -952,8 +963,6 @@
 
     // List of rectangles to clear after saveLayer() is invoked
     Vector<Rect*> mLayers;
-    // List of functors to invoke after a frame is drawn
-    SortedVector<Functor*> mFunctors;
     // List of layers to update at the beginning of a frame
     Vector<Layer*> mLayerUpdates;
 
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 92964a8..f38d8b7 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -175,6 +175,10 @@
         bottom += dy;
     }
 
+    void inset(float delta) {
+        outset(-delta);
+    }
+
     void outset(float delta) {
         left -= delta;
         top -= delta;
@@ -230,8 +234,8 @@
         bottom = ceilf(bottom);
     }
 
-    void dump() const {
-        ALOGD("Rect[l=%f t=%f r=%f b=%f]", left, top, right, bottom);
+    void dump(const char* label) const {
+        ALOGD("%s[l=%f t=%f r=%f b=%f]", label ? label : "Rect", left, top, right, bottom);
     }
 
 private:
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index dcd6bda..fba482d 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -109,7 +109,7 @@
     prepareSubTree(info, mDisplayListData);
 }
 
-static bool is_finished(const sp<RenderPropertyAnimator>& animator) {
+static bool is_finished(const sp<BaseRenderNodeAnimator>& animator) {
     return animator->isFinished();
 }
 
@@ -119,8 +119,8 @@
         mProperties = mStagingProperties;
     }
     if (mNeedsAnimatorsSync) {
-        mAnimators.reserve(mStagingAnimators.size());
-        std::vector< sp<RenderPropertyAnimator> >::iterator it;
+        mAnimators.resize(mStagingAnimators.size());
+        std::vector< sp<BaseRenderNodeAnimator> >::iterator it;
         // hint: this means copy_if_not()
         it = std::remove_copy_if(mStagingAnimators.begin(), mStagingAnimators.end(),
                 mAnimators.begin(), is_finished);
@@ -141,36 +141,32 @@
 
 class AnimateFunctor {
 public:
-    AnimateFunctor(RenderProperties* target, TreeInfo& info)
+    AnimateFunctor(RenderNode* target, TreeInfo& info)
             : mTarget(target), mInfo(info) {}
 
-    bool operator() (sp<RenderPropertyAnimator>& animator) {
-        bool finished = animator->animate(mTarget, mInfo);
-        if (finished && mInfo.animationListener) {
-            mInfo.animationListener->onAnimationFinished(animator);
-        }
-        return finished;
+    bool operator() (sp<BaseRenderNodeAnimator>& animator) {
+        return animator->animate(mTarget, mInfo);
     }
 private:
-    RenderProperties* mTarget;
+    RenderNode* mTarget;
     TreeInfo& mInfo;
 };
 
 void RenderNode::evaluateAnimations(TreeInfo& info) {
     if (!mAnimators.size()) return;
 
-    AnimateFunctor functor(&mProperties, info);
-    std::vector< sp<RenderPropertyAnimator> >::iterator newEnd;
+    AnimateFunctor functor(this, info);
+    std::vector< sp<BaseRenderNodeAnimator> >::iterator newEnd;
     newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
     mAnimators.erase(newEnd, mAnimators.end());
     mProperties.updateMatrix();
-    info.hasAnimations |= mAnimators.size();
+    info.out.hasAnimations |= mAnimators.size();
 }
 
 void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
     if (subtree) {
         TextureCache& cache = Caches::getInstance().textureCache;
-        info.hasFunctors |= subtree->functorCount;
+        info.out.hasFunctors |= subtree->functorCount;
         // TODO: Fix ownedBitmapResources to not require disabling prepareTextures
         // and thus falling out of async drawing path.
         if (subtree->ownedBitmapResources.size()) {
@@ -242,9 +238,8 @@
     }
 
     if (CC_UNLIKELY(properties().hasClippingPath())) {
-        // TODO: optimize for round rect/circle clipping
-        const SkPath* path = properties().getClippingPath();
-        ClipPathOp* op = new (handler.allocator()) ClipPathOp(path, SkRegion::kIntersect_Op);
+        ClipPathOp* op = new (handler.allocator()) ClipPathOp(
+                properties().getClippingPath(), properties().getClippingPathOp());
         handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
     }
 }
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 294f436..bc62ee1 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -45,7 +45,6 @@
 #include "DisplayList.h"
 #include "RenderProperties.h"
 #include "TreeInfo.h"
-#include "utils/VirtualLightRefBase.h"
 
 class SkBitmap;
 class SkPaint;
@@ -128,6 +127,10 @@
         return mProperties;
     }
 
+    RenderProperties& animatorProperties() {
+        return mProperties;
+    }
+
     const RenderProperties& stagingProperties() {
         return mStagingProperties;
     }
@@ -148,13 +151,13 @@
     ANDROID_API virtual void prepareTree(TreeInfo& info);
 
     // UI thread only!
-    ANDROID_API void addAnimator(const sp<RenderPropertyAnimator>& animator) {
+    ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
         mStagingAnimators.insert(animator);
         mNeedsAnimatorsSync = true;
     }
 
     // UI thread only!
-    ANDROID_API void removeAnimator(const sp<RenderPropertyAnimator>& animator) {
+    ANDROID_API void removeAnimator(const sp<BaseRenderNodeAnimator>& animator) {
         mStagingAnimators.erase(animator);
         mNeedsAnimatorsSync = true;
     }
@@ -233,8 +236,8 @@
     DisplayListData* mStagingDisplayListData;
 
     bool mNeedsAnimatorsSync;
-    std::set< sp<RenderPropertyAnimator> > mStagingAnimators;
-    std::vector< sp<RenderPropertyAnimator> > mAnimators;
+    std::set< sp<BaseRenderNodeAnimator> > mStagingAnimators;
+    std::vector< sp<BaseRenderNodeAnimator> > mAnimators;
 
     /**
      * Draw time state - these properties are only set and used during rendering
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 99de1fc..5f7d4e3 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -50,14 +50,11 @@
 }
 
 RenderProperties::ComputedFields::ComputedFields()
-        : mTransformMatrix(NULL)
-        , mClipPath(NULL)
-        , mClipPathOp(SkRegion::kIntersect_Op) {
+        : mTransformMatrix(NULL) {
 }
 
 RenderProperties::ComputedFields::~ComputedFields() {
     delete mTransformMatrix;
-    delete mClipPath;
 }
 
 RenderProperties::RenderProperties()
@@ -77,9 +74,6 @@
         setAnimationMatrix(other.getAnimationMatrix());
         setCameraDistance(other.getCameraDistance());
 
-        // Update the computed clip path
-        updateClipPath();
-
         // Force recalculation of the matrix, since other's dirty bit may be clear
         mPrimitiveFields.mMatrixOrPivotDirty = true;
         updateMatrix();
@@ -166,39 +160,5 @@
     }
 }
 
-void RenderProperties::updateClipPath() {
-    const SkPath* outlineClipPath = mPrimitiveFields.mOutline.willClip()
-            ? mPrimitiveFields.mOutline.getPath() : NULL;
-    const SkPath* revealClipPath = mPrimitiveFields.mRevealClip.getPath();
-
-    if (!outlineClipPath && !revealClipPath) {
-        // mComputedFields.mClipPath doesn't need to be updated, since it won't be used
-        return;
-    }
-
-    if (mComputedFields.mClipPath == NULL) {
-        mComputedFields.mClipPath = new SkPath();
-    }
-    SkPath* clipPath = mComputedFields.mClipPath;
-    mComputedFields.mClipPathOp = SkRegion::kIntersect_Op;
-
-    if (outlineClipPath && revealClipPath) {
-        SkPathOp op = kIntersect_PathOp;
-        if (mPrimitiveFields.mRevealClip.isInverseClip()) {
-            op = kDifference_PathOp; // apply difference step in the Op below, instead of draw time
-        }
-
-        Op(*outlineClipPath, *revealClipPath, op, clipPath);
-    } else if (outlineClipPath) {
-        *clipPath = *outlineClipPath;
-    } else {
-        *clipPath = *revealClipPath;
-        if (mPrimitiveFields.mRevealClip.isInverseClip()) {
-            // apply difference step at draw time
-            mComputedFields.mClipPathOp = SkRegion::kDifference_Op;
-        }
-    }
-}
-
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 6fc8bce..c0e3ce7 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -437,19 +437,17 @@
 
     ANDROID_API void updateMatrix();
 
-    ANDROID_API void updateClipPath();
-
-    // signals that mComputedFields.mClipPath is up to date, and should be used for clipping
     bool hasClippingPath() const {
-        return mPrimitiveFields.mOutline.willClip() || mPrimitiveFields.mRevealClip.willClip();
+        return mPrimitiveFields.mRevealClip.willClip();
     }
 
     const SkPath* getClippingPath() const {
-        return hasClippingPath() ? mComputedFields.mClipPath : NULL;
+        return mPrimitiveFields.mRevealClip.getPath();
     }
 
     SkRegion::Op getClippingPathOp() const {
-        return mComputedFields.mClipPathOp;
+        return mPrimitiveFields.mRevealClip.isInverseClip()
+                ? SkRegion::kDifference_Op : SkRegion::kIntersect_Op;
     }
 
     Outline& mutableOutline() {
@@ -505,8 +503,6 @@
         SkMatrix* mTransformMatrix;
 
         Sk3DView mTransformCamera;
-        SkPath* mClipPath; // TODO: remove this, create new ops for efficient/special case clipping
-        SkRegion::Op mClipPathOp;
     } mComputedFields;
 };
 
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
index 3209a53..57db816 100644
--- a/libs/hwui/Renderer.h
+++ b/libs/hwui/Renderer.h
@@ -178,9 +178,6 @@
     virtual void resetShader() = 0;
     virtual void setupShader(SkiaShader* shader) = 0;
 
-    virtual void resetShadow() = 0;
-    virtual void setupShadow(float radius, float dx, float dy, int color) = 0;
-
     virtual void resetPaintFilter() = 0;
     virtual void setupPaintFilter(int clearBits, int setBits) = 0;
 
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index ee60a63..55b82e4 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -22,6 +22,7 @@
 #include <utils/Trace.h>
 
 #include "AmbientShadow.h"
+#include "Caches.h"
 #include "ShadowTessellator.h"
 #include "SpotShadow.h"
 
@@ -41,9 +42,14 @@
 
     // A bunch of parameters to tweak the shadow.
     // TODO: Allow some of these changable by debug settings or APIs.
-    const float heightFactor = 1.0f / 128;
+    float heightFactor = 1.0f / 128;
     const float geomFactor = 64;
 
+    Caches& caches = Caches::getInstance();
+    if (CC_UNLIKELY(caches.propertyAmbientRatio > 0.0f)) {
+        heightFactor *= caches.propertyAmbientRatio;
+    }
+
     Rect ambientShadowBounds(casterBounds);
     ambientShadowBounds.outset(maxZ * geomFactor * heightFactor);
 
@@ -62,16 +68,26 @@
 
 VertexBufferMode ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque,
         const Vector3* casterPolygon, int casterVertexCount,
-        const Vector3& lightPosScale, const mat4& receiverTransform,
+        const mat4& receiverTransform,
         int screenWidth, int screenHeight, const Rect& casterBounds,
         const Rect& localClip, VertexBuffer& shadowVertexBuffer) {
     ATRACE_CALL();
 
+    Caches& caches = Caches::getInstance();
+
     // A bunch of parameters to tweak the shadow.
     // TODO: Allow some of these changable by debug settings or APIs.
     int maximal = max(screenWidth, screenHeight);
-    Vector3 lightCenter(screenWidth * lightPosScale.x, screenHeight * lightPosScale.y,
-            maximal * lightPosScale.z);
+    Vector3 lightCenter(screenWidth * 0.5f, 0, maximal);
+
+    if (CC_UNLIKELY(caches.propertyLightPosY > 0)) {
+        lightCenter.y = - caches.propertyLightPosY; // negated since this shifts up
+    }
+    if (CC_UNLIKELY(caches.propertyLightPosZ > 0)) {
+        lightCenter.z = caches.propertyLightPosZ;
+    }
+
+
 #if DEBUG_SHADOW
     ALOGD("light center %f %f %f", lightCenter.x, lightCenter.y, lightCenter.z);
 #endif
@@ -82,9 +98,13 @@
     reverseReceiverTransform.loadInverse(receiverTransform);
     reverseReceiverTransform.mapPoint3d(lightCenter);
 
-    const float lightSize = maximal / 4;
+    float lightSize = maximal / 4;
     const int lightVertexCount = 8;
 
+    if (CC_UNLIKELY(caches.propertyLightDiameter > 0)) {
+        lightSize = caches.propertyLightDiameter;
+    }
+
     // Now light and caster are both in local space, we will check whether
     // the shadow is within the clip area.
     Rect lightRect = Rect(lightCenter.x - lightSize, lightCenter.y - lightSize,
@@ -176,6 +196,10 @@
  * @param len the number of points of the polygon
  */
 bool ShadowTessellator::isClockwise(const Vector2* polygon, int len) {
+    if (len < 2 || polygon == NULL) {
+        ALOGW("Invalid polygon %p, length is %d @ isClockwise()", polygon, len);
+        return true;
+    }
     double sum = 0;
     double p1x = polygon[len - 1].x;
     double p1y = polygon[len - 1].y;
diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h
index 64e69bc..e5a3da1 100644
--- a/libs/hwui/ShadowTessellator.h
+++ b/libs/hwui/ShadowTessellator.h
@@ -73,7 +73,7 @@
 
     static VertexBufferMode tessellateSpotShadow(bool isCasterOpaque,
             const Vector3* casterPolygon, int casterVertexCount,
-            const Vector3& lightPosScale, const mat4& receiverTransform,
+            const mat4& receiverTransform,
             int screenWidth, int screenHeight, const Rect& casterBounds,
             const Rect& localClip, VertexBuffer& shadowVertexBuffer);
 
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index d26ee38..029b56d 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -27,9 +27,14 @@
 // Constructors
 ///////////////////////////////////////////////////////////////////////////////
 
-Snapshot::Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0),
-        invisible(false), empty(false), alpha(1.0f) {
-
+Snapshot::Snapshot()
+        : flags(0)
+        , previous(NULL)
+        , layer(NULL)
+        , fbo(0)
+        , invisible(false)
+        , empty(false)
+        , alpha(1.0f) {
     transform = &mTransformRoot;
     clipRect = &mClipRectRoot;
     region = NULL;
@@ -40,10 +45,15 @@
  * Copies the specified snapshot/ The specified snapshot is stored as
  * the previous snapshot.
  */
-Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags):
-        flags(0), previous(s), layer(s->layer), fbo(s->fbo),
-        invisible(s->invisible), empty(false),
-        viewport(s->viewport), height(s->height), alpha(s->alpha) {
+Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags)
+        : flags(0)
+        , previous(s)
+        , layer(s->layer)
+        , fbo(s->fbo)
+        , invisible(s->invisible)
+        , empty(false)
+        , alpha(s->alpha)
+        , mViewportData(s->mViewportData) {
 
     if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
         mTransformRoot.load(*s->transform);
@@ -203,7 +213,7 @@
 
 void Snapshot::dump() const {
     ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d",
-            this, flags, previous.get(), height, isIgnored(), clipRegion && !clipRegion->isEmpty());
+            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);
     ALOGD("  Transform (at %p):", transform);
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 038aea8..e9ab1ff 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -65,17 +65,16 @@
          * Indicates that this snapshot is a special type of layer
          * backed by an FBO. This flag only makes sense when the
          * flag kFlagIsLayer is also set.
+         *
+         * Viewport has been modified to fit the new Fbo, and must be
+         * restored when this snapshot is restored.
          */
         kFlagIsFboLayer = 0x4,
         /**
-         * Indicates that this snapshot has changed the ortho matrix.
-         */
-        kFlagDirtyOrtho = 0x8,
-        /**
          * Indicates that this snapshot or an ancestor snapshot is
          * an FBO layer.
          */
-        kFlagFboTarget = 0x10
+        kFlagFboTarget = 0x8,
     };
 
     /**
@@ -125,6 +124,14 @@
      */
     void resetTransform(float x, float y, float z);
 
+    void initializeViewport(int width, int height) {
+        mViewportData.initialize(width, height);
+    }
+
+    int getViewportWidth() const { return mViewportData.mWidth; }
+    int getViewportHeight() const { return mViewportData.mHeight; }
+    const Matrix4& getOrthoMatrix() const { return mViewportData.mOrthoMatrix; }
+
     /**
      * Indicates whether this snapshot should be ignored. A snapshot
      * is typicalled ignored if its layer is invisible or empty.
@@ -173,21 +180,6 @@
     bool empty;
 
     /**
-     * Current viewport.
-     */
-    Rect viewport;
-
-    /**
-     * Height of the framebuffer the snapshot is rendering into.
-     */
-    int height;
-
-    /**
-     * Contains the previous ortho matrix.
-     */
-    mat4 orthoMatrix;
-
-    /**
      * Local transformation. Holds the current translation, scale and
      * rotation values.
      *
@@ -236,6 +228,27 @@
     void dump() const;
 
 private:
+    struct ViewportData {
+        ViewportData() : mWidth(0), mHeight() {}
+        void initialize(int width, int height) {
+            mWidth = width;
+            mHeight = height;
+            mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
+        }
+
+        /*
+         * Width and height of current viewport.
+         *
+         * The viewport is always defined to be (0, 0, width, height).
+         */
+        int mWidth;
+        int mHeight;
+        /**
+         * Contains the current orthographic, projection matrix.
+         */
+        mat4 mOrthoMatrix;
+    };
+
     void ensureClipRegion();
     void copyClipRectFromRegion();
 
@@ -246,6 +259,7 @@
     Rect mLocalClip; // don't use directly, call getLocalClip() which initializes this
 
     SkRegion mClipRegionRoot;
+    ViewportData mViewportData;
 
 }; // class Snapshot
 
diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp
index 05f6cf8..aa83e20 100644
--- a/libs/hwui/StatefulBaseRenderer.cpp
+++ b/libs/hwui/StatefulBaseRenderer.cpp
@@ -38,9 +38,7 @@
 void StatefulBaseRenderer::initializeViewport(int width, int height) {
     mWidth = width;
     mHeight = height;
-
-    mFirstSnapshot->height = height;
-    mFirstSnapshot->viewport.set(0, 0, width, height);
+    mFirstSnapshot->initializeViewport(width, height);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h
index 64354ac..9fbf2ca 100644
--- a/libs/hwui/StatefulBaseRenderer.h
+++ b/libs/hwui/StatefulBaseRenderer.h
@@ -46,6 +46,11 @@
     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.
+     */
     void initializeViewport(int width, int height);
     void initializeSaveStack(float clipLeft, float clipTop, float clipRight, float clipBottom);
 
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index 8957607..fc5994c 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -16,44 +16,51 @@
 #ifndef TREEINFO_H
 #define TREEINFO_H
 
-#include <cutils/compiler.h>
 #include <utils/Timers.h>
-#include <utils/StrongPointer.h>
 
 namespace android {
 namespace uirenderer {
 
-class RenderPropertyAnimator;
+class BaseAnimator;
+class AnimationListener;
 
-class AnimationListener {
+class AnimationHook {
 public:
-    ANDROID_API virtual void onAnimationFinished(const sp<RenderPropertyAnimator>&) = 0;
+    virtual void callOnFinished(BaseAnimator* animator, AnimationListener* listener) = 0;
 protected:
-    ANDROID_API virtual ~AnimationListener() {}
+    ~AnimationHook() {}
 };
 
 struct TreeInfo {
     // The defaults here should be safe for everyone but DrawFrameTask to use as-is.
     TreeInfo()
-            : hasFunctors(false)
-            , prepareTextures(false)
-            , performStagingPush(true)
-            , frameTimeMs(0)
-            , evaluateAnimations(false)
-            , hasAnimations(false)
-            , animationListener(0)
+        : frameTimeMs(0)
+        , animationHook(NULL)
+        , prepareTextures(false)
+        , performStagingPush(true)
+        , evaluateAnimations(false)
     {}
 
-    bool hasFunctors;
+    nsecs_t frameTimeMs;
+    AnimationHook* animationHook;
     bool prepareTextures;
     bool performStagingPush;
-
-    // Animations
-    nsecs_t frameTimeMs;
     bool evaluateAnimations;
-    // This is only updated if evaluateAnimations is true
-    bool hasAnimations;
-    AnimationListener* animationListener;
+
+    struct Out {
+        Out()
+            : hasFunctors(false)
+            , hasAnimations(false)
+            , requiresUiRedraw(false)
+        {}
+        bool hasFunctors;
+        // This is only updated if evaluateAnimations is true
+        bool hasAnimations;
+        // This is set to true if there is an animation that RenderThread cannot
+        // animate itself, such as if hasFunctors is true
+        // This is only set if hasAnimations is true
+        bool requiresUiRedraw;
+    } out;
 
     // TODO: Damage calculations
 };
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index d22cb8a..08e9a1a 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -214,18 +214,28 @@
     int dstY = y + glyph->mBitmapTop;
 
     CacheTexture* cacheTexture = glyph->mCacheTexture;
-
-    uint32_t cacheWidth = cacheTexture->getWidth();
-    uint32_t startY = glyph->mStartY * cacheWidth;
-    uint32_t endY = startY + (glyph->mBitmapHeight * cacheWidth);
-
     PixelBuffer* pixelBuffer = cacheTexture->getPixelBuffer();
+
+    uint32_t formatSize = PixelBuffer::formatSize(pixelBuffer->getFormat());
+    uint32_t cacheWidth = cacheTexture->getWidth();
+    uint32_t srcStride = formatSize * cacheWidth;
+    uint32_t startY = glyph->mStartY * srcStride;
+    uint32_t endY = startY + (glyph->mBitmapHeight * srcStride);
+
     const uint8_t* cacheBuffer = pixelBuffer->map();
 
     for (uint32_t cacheY = startY, bitmapY = dstY * bitmapWidth; cacheY < endY;
-            cacheY += cacheWidth, bitmapY += bitmapWidth) {
-        memcpy(&bitmap[bitmapY + dstX], &cacheBuffer[cacheY + glyph->mStartX], glyph->mBitmapWidth);
+            cacheY += srcStride, bitmapY += bitmapWidth) {
+
+        if (formatSize == 1) {
+            memcpy(&bitmap[bitmapY + dstX], &cacheBuffer[cacheY + glyph->mStartX], glyph->mBitmapWidth);
+        } else {
+            for (uint32_t i = 0; i < glyph->mBitmapWidth; ++i) {
+                bitmap[bitmapY + dstX + i] = cacheBuffer[cacheY + (glyph->mStartX + i)*formatSize];
+            }
+        }
     }
+
 }
 
 void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset,
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 63f4b95..48cd8fc 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -31,11 +31,10 @@
 
 #define PROPERTY_RENDER_DIRTY_REGIONS "debug.hwui.render_dirty_regions"
 #define GLES_VERSION 2
+#define USE_TEXTURE_ATLAS false
 
-#ifdef USE_OPENGL_RENDERER
 // Android-specific addition that is used to show when frames began in systrace
 EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
-#endif
 
 namespace android {
 namespace uirenderer {
@@ -98,6 +97,8 @@
 
     bool enableDirtyRegions(EGLSurface surface);
 
+    void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize);
+
 private:
     GlobalContext();
     // GlobalContext is never destroyed, method is purposely not implemented
@@ -118,6 +119,10 @@
     bool mCanSetDirtyRegions;
 
     EGLSurface mCurrentSurface;
+
+    sp<GraphicBuffer> mAtlasBuffer;
+    int64_t* mAtlasMap;
+    size_t mAtlasMapSize;
 };
 
 GlobalContext* GlobalContext::sContext = 0;
@@ -135,7 +140,9 @@
         , mEglContext(EGL_NO_CONTEXT)
         , mPBufferSurface(EGL_NO_SURFACE)
         , mRequestDirtyRegions(load_dirty_regions_property())
-        , mCurrentSurface(EGL_NO_SURFACE) {
+        , mCurrentSurface(EGL_NO_SURFACE)
+        , mAtlasMap(NULL)
+        , mAtlasMapSize(0) {
     mCanSetDirtyRegions = mRequestDirtyRegions;
     ALOGD("Render dirty regions requested: %s", mRequestDirtyRegions ? "true" : "false");
 }
@@ -201,9 +208,30 @@
         "Failed to create context, error = %s", egl_error_str());
 }
 
+void GlobalContext::setTextureAtlas(const sp<GraphicBuffer>& buffer,
+        int64_t* map, size_t mapSize) {
+
+    // Already initialized
+    if (mAtlasBuffer.get()) {
+        ALOGW("Multiple calls to setTextureAtlas!");
+        delete map;
+        return;
+    }
+
+    mAtlasBuffer = buffer;
+    mAtlasMap = map;
+    mAtlasMapSize = mapSize;
+
+    if (hasContext()) {
+        usePBufferSurface();
+        initAtlas();
+    }
+}
+
 void GlobalContext::initAtlas() {
-    // TODO implement
-    // For now just run without an atlas
+    if (USE_TEXTURE_ATLAS) {
+        Caches::getInstance().assetAtlas.init(mAtlasBuffer, mAtlasMap, mAtlasMapSize);
+    }
 }
 
 void GlobalContext::usePBufferSurface() {
@@ -349,6 +377,8 @@
         mDirtyRegionsEnabled = mGlobalContext->enableDirtyRegions(mEglSurface);
         mHaveNewSurface = true;
         makeCurrent();
+    } else {
+        mRenderThread.removeFrameCallback(this);
     }
 }
 
@@ -385,16 +415,30 @@
     mCanvas->setViewport(width, height);
 }
 
+void CanvasContext::setOpaque(bool opaque) {
+    mOpaque = opaque;
+}
+
 void CanvasContext::makeCurrent() {
     // TODO: Figure out why this workaround is needed, see b/13913604
     // In the meantime this matches the behavior of GLRenderer, so it is not a regression
     mHaveNewSurface |= mGlobalContext->makeCurrent(mEglSurface);
 }
 
+void CanvasContext::prepareDraw(const Vector<DeferredLayerUpdater*>* layerUpdaters,
+        TreeInfo& info) {
+    LOG_ALWAYS_FATAL_IF(!mCanvas, "Cannot prepareDraw without a canvas!");
+    makeCurrent();
+
+    processLayerUpdates(layerUpdaters, info);
+    if (info.out.hasAnimations) {
+        // TODO: Uh... crap?
+    }
+    prepareTree(info);
+}
+
 void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters,
         TreeInfo& info) {
-    LOG_ALWAYS_FATAL_IF(!mCanvas, "Cannot process layer updates without a canvas!");
-    makeCurrent();
     for (size_t i = 0; i < layerUpdaters->size(); i++) {
         DeferredLayerUpdater* update = layerUpdaters->itemAt(i);
         bool success = update->apply(info);
@@ -406,11 +450,19 @@
 }
 
 void CanvasContext::prepareTree(TreeInfo& info) {
+    mRenderThread.removeFrameCallback(this);
+
+    info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
     mRootRenderNode->prepareTree(info);
 
-    if (info.hasAnimations && !info.hasFunctors) {
-        // TODO: Functors
-        mRenderThread.postFrameCallback(this);
+    if (info.out.hasAnimations) {
+        if (info.out.hasFunctors) {
+            info.out.requiresUiRedraw = true;
+        } else if (!info.out.requiresUiRedraw) {
+            // If animationsNeedsRedraw is set don't bother posting for an RT anim
+            // as we will just end up fighting the UI thread.
+            mRenderThread.postFrameCallback(this);
+        }
     }
 }
 
@@ -449,12 +501,15 @@
 }
 
 // Called by choreographer to do an RT-driven animation
-void CanvasContext::doFrame(nsecs_t frameTimeNanos) {
+void CanvasContext::doFrame() {
+    if (CC_UNLIKELY(!mCanvas || mEglSurface == EGL_NO_SURFACE)) {
+        return;
+    }
+
     ATRACE_CALL();
 
     TreeInfo info;
     info.evaluateAnimations = true;
-    info.frameTimeMs = nanoseconds_to_milliseconds(frameTimeNanos);
     info.performStagingPush = false;
     info.prepareTextures = false;
 
@@ -469,10 +524,7 @@
         requireGlContext();
         mode = DrawGlInfo::kModeProcess;
     }
-    // TODO: Remove the dummy info in the future
-    DrawGlInfo dummyInfo;
-    memset(&dummyInfo, 0, sizeof(DrawGlInfo));
-    (*functor)(mode, &dummyInfo);
+    (*functor)(mode, NULL);
 
     if (mCanvas) {
         mCanvas->resume();
@@ -509,6 +561,11 @@
     }
 }
 
+void CanvasContext::setTextureAtlas(const sp<GraphicBuffer>& buffer,
+        int64_t* map, size_t mapSize) {
+    GlobalContext::get()->setTextureAtlas(buffer, map, mapSize);
+}
+
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 0873ad4..a793d42 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -52,14 +52,14 @@
     void updateSurface(EGLNativeWindowType window);
     void pauseSurface(EGLNativeWindowType window);
     void setup(int width, int height);
+    void setOpaque(bool opaque);
     void makeCurrent();
-    void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
-    void prepareTree(TreeInfo& info);
+    void prepareDraw(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
     void draw(Rect* dirty);
     void destroyCanvasAndSurface();
 
     // IFrameCallback, Chroreographer-driven frame callback entry point
-    virtual void doFrame(nsecs_t frameTimeNanos);
+    virtual void doFrame();
 
     bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
 
@@ -70,7 +70,13 @@
     Layer* createRenderLayer(int width, int height);
     Layer* createTextureLayer();
 
+    ANDROID_API static void setTextureAtlas(const sp<GraphicBuffer>& buffer,
+            int64_t* map, size_t mapSize);
+
 private:
+    void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
+    void prepareTree(TreeInfo& info);
+
     void setSurface(EGLNativeWindowType window);
     void swapBuffers();
     void requireSurface();
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index ff4be71..3b8786c 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -30,13 +30,18 @@
 namespace uirenderer {
 namespace renderthread {
 
-DrawFrameTask::DrawFrameTask() : mContext(0) {
+DrawFrameTask::DrawFrameTask()
+        : mRenderThread(NULL)
+        , mContext(NULL)
+        , mFrameTimeNanos(0)
+        , mSyncResult(kSync_OK) {
 }
 
 DrawFrameTask::~DrawFrameTask() {
 }
 
-void DrawFrameTask::setContext(CanvasContext* context) {
+void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context) {
+    mRenderThread = thread;
     mContext = context;
 }
 
@@ -59,18 +64,23 @@
     mDirty.set(left, top, right, bottom);
 }
 
-void DrawFrameTask::drawFrame(RenderThread* renderThread) {
+int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos) {
     LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
 
-    postAndWait(renderThread);
+    mSyncResult = kSync_OK;
+    mFrameTimeNanos = frameTimeNanos;
+    postAndWait();
 
     // Reset the single-frame data
+    mFrameTimeNanos = 0;
     mDirty.setEmpty();
+
+    return mSyncResult;
 }
 
-void DrawFrameTask::postAndWait(RenderThread* renderThread) {
+void DrawFrameTask::postAndWait() {
     AutoMutex _lock(mLock);
-    renderThread->queue(this);
+    mRenderThread->queue(this);
     mSignal.wait(mLock);
 }
 
@@ -99,21 +109,25 @@
     info.prepareTextures = true;
     info.performStagingPush = true;
     info.evaluateAnimations = true;
-    // TODO: Get this from Choreographer
-    nsecs_t frameTimeNs = systemTime(CLOCK_MONOTONIC);
-    info.frameTimeMs = nanoseconds_to_milliseconds(frameTimeNs);
 }
 
 bool DrawFrameTask::syncFrameState() {
     ATRACE_CALL();
+    mRenderThread->timeLord().vsyncReceived(mFrameTimeNanos);
     mContext->makeCurrent();
     Caches::getInstance().textureCache.resetMarkInUse();
     TreeInfo info;
     initTreeInfo(info);
-    mContext->processLayerUpdates(&mLayers, info);
-    mContext->prepareTree(info);
+    mContext->prepareDraw(&mLayers, info);
+    if (info.out.hasAnimations) {
+        // TODO: dirty calculations, for now just do a full-screen inval
+        mDirty.setEmpty();
+        if (info.out.requiresUiRedraw) {
+            mSyncResult |= kSync_UIRedrawRequired;
+        }
+    }
     // If prepareTextures is false, we ran out of texture cache space
-    return !info.hasFunctors && info.prepareTextures;
+    return !info.out.hasFunctors && info.prepareTextures;
 }
 
 void DrawFrameTask::unblockUiThread() {
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index c280868..b9307e1 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -37,6 +37,11 @@
 class CanvasContext;
 class RenderThread;
 
+enum SyncResult {
+    kSync_OK = 0,
+    kSync_UIRedrawRequired = 1 << 1,
+};
+
 /*
  * This is a special Super Task. It is re-used multiple times by RenderProxy,
  * and contains state (such as layer updaters & new DisplayListDatas) that is
@@ -48,30 +53,34 @@
     DrawFrameTask();
     virtual ~DrawFrameTask();
 
-    void setContext(CanvasContext* context);
+    void setContext(RenderThread* thread, CanvasContext* context);
 
     void addLayer(DeferredLayerUpdater* layer);
     void removeLayer(DeferredLayerUpdater* layer);
 
     void setDirty(int left, int top, int right, int bottom);
-    void drawFrame(RenderThread* renderThread);
+    int drawFrame(nsecs_t frameTimeNanos);
 
     virtual void run();
 
 private:
-    void postAndWait(RenderThread* renderThread);
+    void postAndWait();
     bool syncFrameState();
     void unblockUiThread();
 
     Mutex mLock;
     Condition mSignal;
 
+    RenderThread* mRenderThread;
     CanvasContext* mContext;
 
     /*********************************************
      *  Single frame data
      *********************************************/
     Rect mDirty;
+    nsecs_t mFrameTimeNanos;
+
+    int mSyncResult;
 
     /*********************************************
      *  Multi frame data
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 87886e6..82a2dbc 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -62,7 +62,7 @@
     args->translucent = translucent;
     args->rootRenderNode = rootRenderNode;
     mContext = (CanvasContext*) postAndWait(task);
-    mDrawFrameTask.setContext(mContext);
+    mDrawFrameTask.setContext(&mRenderThread, mContext);
 }
 
 RenderProxy::~RenderProxy() {
@@ -79,13 +79,38 @@
         SETUP_TASK(destroyContext);
         args->context = mContext;
         mContext = 0;
-        mDrawFrameTask.setContext(0);
+        mDrawFrameTask.setContext(NULL, NULL);
         // 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_BRIDGE0(loadSystemProperties) {
+    bool needsRedraw = false;
+    if (Caches::hasInstance()) {
+        needsRedraw = Caches::getInstance().initProperties();
+    }
+    return (void*) needsRedraw;
+}
+
+bool RenderProxy::loadSystemProperties() {
+    SETUP_TASK(loadSystemProperties);
+    return (bool) postAndWait(task);
+}
+
 CREATE_BRIDGE2(initialize, CanvasContext* context, EGLNativeWindowType window) {
     return (void*) args->context->initialize(args->window);
 }
@@ -134,10 +159,22 @@
     post(task);
 }
 
-void RenderProxy::syncAndDrawFrame(
+CREATE_BRIDGE2(setOpaque, CanvasContext* context, bool opaque) {
+    args->context->setOpaque(args->opaque);
+    return NULL;
+}
+
+void RenderProxy::setOpaque(bool opaque) {
+    SETUP_TASK(setOpaque);
+    args->context = mContext;
+    args->opaque = opaque;
+    post(task);
+}
+
+int RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos,
         int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) {
     mDrawFrameTask.setDirty(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
-    mDrawFrameTask.drawFrame(&mRenderThread);
+    return mDrawFrameTask.drawFrame(frameTimeNanos);
 }
 
 CREATE_BRIDGE1(destroyCanvasAndSurface, CanvasContext* context) {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index eab1395..4a7e70a 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -25,6 +25,7 @@
 #include <utils/Condition.h>
 #include <utils/Functor.h>
 #include <utils/Mutex.h>
+#include <utils/Timers.h>
 #include <utils/StrongPointer.h>
 #include <utils/Vector.h>
 
@@ -59,11 +60,15 @@
     ANDROID_API RenderProxy(bool translucent, RenderNode* rootNode);
     ANDROID_API virtual ~RenderProxy();
 
+    ANDROID_API void setFrameInterval(nsecs_t frameIntervalNanos);
+    ANDROID_API bool loadSystemProperties();
+
     ANDROID_API bool initialize(const sp<ANativeWindow>& window);
     ANDROID_API void updateSurface(const sp<ANativeWindow>& window);
     ANDROID_API void pauseSurface(const sp<ANativeWindow>& window);
     ANDROID_API void setup(int width, int height);
-    ANDROID_API void syncAndDrawFrame(
+    ANDROID_API void setOpaque(bool opaque);
+    ANDROID_API int syncAndDrawFrame(nsecs_t frameTimeNanos,
             int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
     ANDROID_API void destroyCanvasAndSurface();
 
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index e95707a..35a3eab 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -129,8 +129,7 @@
         , mDisplayEventReceiver(0)
         , mVsyncRequested(false)
         , mFrameCallbackTaskPending(false)
-        , mFrameCallbackTask(0)
-        , mFrameTime(0) {
+        , mFrameCallbackTask(0) {
     mFrameCallbackTask = new DispatchFrameCallbacks(this);
     mLooper = new Looper(false);
     run("RenderThread");
@@ -193,7 +192,7 @@
     nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver);
     if (vsyncEvent > 0) {
         mVsyncRequested = false;
-        mFrameTime = vsyncEvent;
+        mTimeLord.vsyncReceived(vsyncEvent);
         if (!mFrameCallbackTaskPending) {
             mFrameCallbackTaskPending = true;
             //queueDelayed(mFrameCallbackTask, DISPATCH_FRAME_CALLBACKS_DELAY);
@@ -209,7 +208,7 @@
     mFrameCallbacks.swap(callbacks);
 
     for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) {
-        (*it)->doFrame(mFrameTime);
+        (*it)->doFrame();
     }
 }
 
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index b93dfd6..215d294 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -28,6 +28,8 @@
 #include <utils/Singleton.h>
 #include <utils/Thread.h>
 
+#include "TimeLord.h"
+
 namespace android {
 class DisplayEventReceiver;
 
@@ -53,7 +55,7 @@
 // Mimics android.view.Choreographer.FrameCallback
 class IFrameCallback {
 public:
-    virtual void doFrame(nsecs_t frameTimeNanos) = 0;
+    virtual void doFrame() = 0;
 
 protected:
     ~IFrameCallback() {}
@@ -71,6 +73,8 @@
     void postFrameCallback(IFrameCallback* callback);
     void removeFrameCallback(IFrameCallback* callback);
 
+    TimeLord& timeLord() { return mTimeLord; }
+
 protected:
     virtual bool threadLoop();
 
@@ -102,7 +106,8 @@
     std::set<IFrameCallback*> mFrameCallbacks;
     bool mFrameCallbackTaskPending;
     DispatchFrameCallbacks* mFrameCallbackTask;
-    nsecs_t mFrameTime;
+
+    TimeLord mTimeLord;
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/TimeLord.cpp b/libs/hwui/renderthread/TimeLord.cpp
new file mode 100644
index 0000000..758d96e
--- /dev/null
+++ b/libs/hwui/renderthread/TimeLord.cpp
@@ -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.
+ */
+#include "TimeLord.h"
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+TimeLord::TimeLord()
+        : mFrameIntervalNanos(0)
+        , mFrameTimeNanos(0) {
+}
+
+void TimeLord::vsyncReceived(nsecs_t vsync) {
+    if (vsync > mFrameTimeNanos) {
+        mFrameTimeNanos = vsync;
+    }
+}
+
+nsecs_t TimeLord::frameTimeMs() {
+    // Logic copied from Choreographer.java
+    nsecs_t now = systemTime(CLOCK_MONOTONIC);
+    nsecs_t jitterNanos = now - mFrameTimeNanos;
+    if (jitterNanos >= mFrameIntervalNanos) {
+        nsecs_t lastFrameOffset = jitterNanos % mFrameIntervalNanos;
+        mFrameTimeNanos = now - lastFrameOffset;
+    }
+    return nanoseconds_to_milliseconds(mFrameTimeNanos);
+}
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/renderthread/TimeLord.h b/libs/hwui/renderthread/TimeLord.h
new file mode 100644
index 0000000..52c6d9e
--- /dev/null
+++ b/libs/hwui/renderthread/TimeLord.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef TIMELORD_H
+#define TIMELORD_H
+
+#include <utils/Timers.h>
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+class RenderThread;
+
+// This class serves as a helper to filter & manage frame times from multiple sources
+// ensuring that time flows linearly and smoothly
+class TimeLord {
+public:
+    void setFrameInterval(nsecs_t intervalNanos) { mFrameIntervalNanos = intervalNanos; }
+    void vsyncReceived(nsecs_t vsync);
+    nsecs_t frameTimeMs();
+
+private:
+    friend class RenderThread;
+
+    TimeLord();
+    ~TimeLord() {}
+
+    nsecs_t mFrameIntervalNanos;
+    nsecs_t mFrameTimeNanos;
+};
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* TIMELORD_H */
diff --git a/libs/hwui/utils/Blur.cpp b/libs/hwui/utils/Blur.cpp
index 85d90d0..c020b40 100644
--- a/libs/hwui/utils/Blur.cpp
+++ b/libs/hwui/utils/Blur.cpp
@@ -23,6 +23,31 @@
 namespace android {
 namespace uirenderer {
 
+// This constant approximates the scaling done in the software path's
+// "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)).
+static const float BLUR_SIGMA_SCALE = 0.57735f;
+
+float Blur::convertRadiusToSigma(float radius) {
+    return radius > 0 ? BLUR_SIGMA_SCALE * radius + 0.5f : 0.0f;
+}
+
+float Blur::convertSigmaToRadius(float sigma) {
+    return sigma > 0.5f ? (sigma - 0.5f) / BLUR_SIGMA_SCALE : 0.0f;
+}
+
+/**
+ * HWUI has used a slightly different equation than Skia to generate the value
+ * for sigma and to preserve compatibility we have kept that logic.
+ *
+ * Based on some experimental radius and sigma values we approximate the
+ * equation sigma = f(radius) as sigma = radius * 0.3  + 0.6.  The larger the
+ * radius gets, the more our gaussian blur will resemble a box blur since with
+ * large sigma the gaussian curve begins to lose its shape.
+ */
+static float legacyConvertRadiusToSigma(float radius) {
+    return radius > 0 ? 0.3f * radius + 0.6f : 0.0f;
+}
+
 void Blur::generateGaussianWeights(float* weights, int32_t radius) {
     // Compute gaussian weights for the blur
     // e is the euler's number
@@ -31,13 +56,7 @@
     // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
     // x is of the form [-radius .. 0 .. radius]
     // and sigma varies with radius.
-    // Based on some experimental radius values and sigma's
-    // we approximately fit sigma = f(radius) as
-    // sigma = radius * 0.3  + 0.6
-    // The larger the radius gets, the more our gaussian blur
-    // will resemble a box blur since with large sigma
-    // the gaussian curve begins to lose its shape
-    float sigma = 0.3f * (float) radius + 0.6f;
+    float sigma = legacyConvertRadiusToSigma((float) radius);
 
     // Now compute the coefficints
     // We will store some redundant values to save some math during
diff --git a/libs/hwui/utils/Blur.h b/libs/hwui/utils/Blur.h
index 6c176e9..79aff65 100644
--- a/libs/hwui/utils/Blur.h
+++ b/libs/hwui/utils/Blur.h
@@ -18,12 +18,18 @@
 #define ANDROID_HWUI_BLUR_H
 
 #include <stdint.h>
+#include <cutils/compiler.h>
 
 namespace android {
 namespace uirenderer {
 
 class Blur {
 public:
+    // If radius > 0, return the corresponding sigma, else return 0
+    ANDROID_API static float convertRadiusToSigma(float radius);
+    // If sigma > 0.6, return the corresponding radius, else return 0
+    ANDROID_API static float convertSigmaToRadius(float sigma);
+
     static void generateGaussianWeights(float* weights, int32_t radius);
     static void horizontal(float* weights, int32_t radius, const uint8_t* source,
         uint8_t* dest, int32_t width, int32_t height);
diff --git a/libs/hwui/utils/GLUtils.cpp b/libs/hwui/utils/GLUtils.cpp
new file mode 100644
index 0000000..9b298ca
--- /dev/null
+++ b/libs/hwui/utils/GLUtils.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <utils/Log.h>
+
+#include "GLUtils.h"
+
+namespace android {
+namespace uirenderer {
+
+void GLUtils::dumpGLErrors() {
+    GLenum status = GL_NO_ERROR;
+    while ((status = glGetError()) != GL_NO_ERROR) {
+        switch (status) {
+        case GL_INVALID_ENUM:
+            ALOGE("GL error:  GL_INVALID_ENUM");
+            break;
+        case GL_INVALID_VALUE:
+            ALOGE("GL error:  GL_INVALID_VALUE");
+            break;
+        case GL_INVALID_OPERATION:
+            ALOGE("GL error:  GL_INVALID_OPERATION");
+            break;
+        case GL_OUT_OF_MEMORY:
+            ALOGE("GL error:  Out of memory!");
+            break;
+        default:
+            ALOGE("GL error: 0x%x", status);
+        }
+    }
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/utils/GLUtils.h b/libs/hwui/utils/GLUtils.h
new file mode 100644
index 0000000..890e374
--- /dev/null
+++ b/libs/hwui/utils/GLUtils.h
@@ -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.
+ */
+#ifndef GLUTILS_H
+#define GLUTILS_H
+
+namespace android {
+namespace uirenderer {
+
+class GLUtils {
+private:
+public:
+    /**
+     * Print out any GL errors with ALOGE
+     */
+    static void dumpGLErrors();
+
+}; // class GLUtils
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* GLUTILS_H */
diff --git a/libs/hwui/utils/Macros.h b/libs/hwui/utils/Macros.h
new file mode 100644
index 0000000..14a3ec0
--- /dev/null
+++ b/libs/hwui/utils/Macros.h
@@ -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.
+ */
+#ifndef MACROS_H
+#define MACROS_H
+
+#define PREVENT_COPY_AND_ASSIGN(Type) \
+    private: \
+        Type(const Type&); \
+        void operator=(const Type&)
+
+
+#endif /* MACROS_H */
diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h
index 7deabe9..1a7082b 100644
--- a/libs/hwui/utils/MathUtils.h
+++ b/libs/hwui/utils/MathUtils.h
@@ -33,9 +33,17 @@
     inline static bool isPositive(float value) {
         return value >= gNonZeroEpsilon;
     }
+
+    inline static int min(int a, int b) {
+        return a < b ? a : b;
+    }
+
+    inline static float lerp(float v1, float v2, float t) {
+        return v1 + ((v2 - v1) * t);
+    }
 }; // class MathUtils
 
 } /* namespace uirenderer */
 } /* namespace android */
 
-#endif /* RENDERNODE_H */
+#endif /* MATHUTILS_H */
diff --git a/libs/hwui/utils/VirtualLightRefBase.h b/libs/hwui/utils/VirtualLightRefBase.h
deleted file mode 100644
index b545aab..0000000
--- a/libs/hwui/utils/VirtualLightRefBase.h
+++ /dev/null
@@ -1,34 +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 VIRTUALLIGHTREFBASE_H
-#define VIRTUALLIGHTREFBASE_H
-
-#include <utils/RefBase.h>
-
-namespace android {
-namespace uirenderer {
-
-// This is a wrapper around LightRefBase that simply enforces a virtual
-// destructor to eliminate the template requirement of LightRefBase
-class VirtualLightRefBase : public LightRefBase<VirtualLightRefBase> {
-public:
-    virtual ~VirtualLightRefBase() {}
-};
-
-} /* namespace uirenderer */
-} /* namespace android */
-
-#endif /* VIRTUALLIGHTREFBASE_H */
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
new file mode 100644
index 0000000..bb23a36
--- /dev/null
+++ b/media/java/android/media/AudioAttributes.java
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.IntDef;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A class to encapsulate a collection of attributes describing information about an audio
+ * player or recorder.
+ */
+public final class AudioAttributes {
+    private final static String TAG = "AudioAttributes";
+
+    /**
+     * Content type value to use when the content type is unknown, or other than the ones defined.
+     */
+    public final static int CONTENT_TYPE_UNKNOWN = 0;
+    /**
+     * Content type value to use when the content type is speech.
+     */
+    public final static int CONTENT_TYPE_SPEECH = 1;
+    /**
+     * Content type value to use when the content type is music.
+     */
+    public final static int CONTENT_TYPE_MUSIC = 2;
+    /**
+     * Content type value to use when the content type is a soundtrack, typically accompanying
+     * a movie or TV program.
+     */
+    public final static int CONTENT_TYPE_MOVIE = 3;
+    /**
+     * Content type value to use when the content type is a sound used to accompany a user
+     * action, such as a beep or sound effect expressing a key click, or event, such as the
+     * type of a sound for a bonus being received in a game. These sounds are mostly synthesized
+     * or short Foley sounds.
+     */
+    public final static int CONTENT_TYPE_SONIFICATION = 4;
+
+    /**
+     * Usage value to use when the usage is unknown.
+     */
+    public final static int USAGE_UNKNOWN = 0;
+    /**
+     * Usage value to use when the usage is media, such as music, or movie
+     * soundtracks.
+     */
+    public final static int USAGE_MEDIA = 1;
+    /**
+     * Usage value to use when the usage is voice communications, such as telephony
+     * or VoIP.
+     */
+    public final static int USAGE_VOICE_COMMUNICATION = 2;
+    /**
+     * Usage value to use when the usage is in-call signalling, such as with
+     * a "busy" beep, or DTMF tones.
+     */
+    public final static int USAGE_VOICE_COMMUNICATION_SIGNALLING = 3;
+    /**
+     * Usage value to use when the usage is an alarm (e.g. wake-up alarm).
+     */
+    public final static int USAGE_ALARM = 4;
+    /**
+     * Usage value to use when the usage is notification. See other
+     * notification usages for more specialized uses.
+     */
+    public final static int USAGE_NOTIFICATION = 5;
+    /**
+     * Usage value to use when the usage is telephony ringtone.
+     */
+    public final static int USAGE_NOTIFICATION_TELEPHONY_RINGTONE = 6;
+    /**
+     * Usage value to use when the usage is a request to enter/end a
+     * communication, such as a VoIP communication or video-conference.
+     */
+    public final static int USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7;
+    /**
+     * Usage value to use when the usage is notification for an "instant"
+     * communication such as a chat, or SMS.
+     */
+    public final static int USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8;
+    /**
+     * Usage value to use when the usage is notification for a
+     * non-immediate type of communication such as e-mail.
+     */
+    public final static int USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9;
+    /**
+     * Usage value to use when the usage is to attract the user's attention,
+     * such as a reminder or low battery warning.
+     */
+    public final static int USAGE_NOTIFICATION_EVENT = 10;
+    /**
+     * Usage value to use when the usage is for accessibility, such as with
+     * a screen reader.
+     */
+    public final static int USAGE_ASSISTANCE_ACCESSIBILITY = 11;
+    /**
+     * Usage value to use when the usage is driving or navigation directions.
+     */
+    public final static int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12;
+    /**
+     * Usage value to use when the usage is sonification, such as  with user
+     * interface sounds.
+     */
+    public final static int USAGE_ASSISTANCE_SONIFICATION = 13;
+    /**
+     * Usage value to use when the usage is for game audio.
+     */
+    public final static int USAGE_GAME = 14;
+
+    /**
+     * Flag defining a behavior where the audibility of the sound will be ensured by the system.
+     */
+    public final static int FLAG_AUDIBILITY_ENFORCED = 0x1 << 0;
+    /**
+     * @hide
+     * Flag defining a behavior where the playback of the sound is ensured without
+     * degradation only when going to a secure sink.
+     */
+    // FIXME not guaranteed yet
+    // TODO  add OR to getFlags() when supported and in public API
+    public final static int FLAG_SECURE = 0x1 << 1;
+    /**
+     * @hide
+     * Flag to enable when the stream is associated with SCO usage.
+     * Internal use only for dealing with legacy STREAM_BLUETOOTH_SCO
+     */
+    public final static int FLAG_SCO = 0x1 << 2;
+
+
+    private int mUsage = USAGE_UNKNOWN;
+    private int mContentType = CONTENT_TYPE_UNKNOWN;
+    private int mFlags = 0x0;
+    private HashSet<String> mTags;
+
+    private AudioAttributes() {
+    }
+
+    /**
+     * Return the content type.
+     * @return one of the values that can be set in {@link Builder#setContentType(int)}
+     */
+    public int getContentType() {
+        return mContentType;
+    }
+
+    /**
+     * Return the usage.
+     * @return one of the values that can be set in {@link Builder#setUsage(int)}
+     */
+    public int getUsage() {
+        return mUsage;
+    }
+
+    /**
+     * Return the flags.
+     * @return a combined mask of all flags
+     */
+    public int getFlags() {
+        // only return the flags that are public
+        return (mFlags & (FLAG_AUDIBILITY_ENFORCED));
+    }
+
+    /**
+     * @hide
+     * Return all the flags, even the non-public ones.
+     * Internal use only
+     * @return a combined mask of all flags
+     */
+    public int getAllFlags() {
+        return mFlags;
+    }
+
+    /**
+     * Return the set of tags.
+     * @return a read-only set of all tags stored as strings.
+     */
+    public Set<String> getTags() {
+        return Collections.unmodifiableSet(mTags);
+    }
+
+    /**
+     * Builder class for {@link AudioAttributes} objects.
+     */
+    public static class Builder {
+        private int mUsage = USAGE_UNKNOWN;
+        private int mContentType = CONTENT_TYPE_UNKNOWN;
+        private int mFlags = 0x0;
+        private HashSet<String> mTags = new HashSet<String>();
+
+        /**
+         * Constructs a new Builder with the defaults.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Constructs a new Builder from a given AudioAttributes
+         * @param aa the AudioAttributes object whose data will be reused in the new Builder.
+         */
+        @SuppressWarnings("unchecked") // for cloning of mTags
+        public Builder(AudioAttributes aa) {
+            mUsage = aa.mUsage;
+            mContentType = aa.mContentType;
+            mFlags = aa.mFlags;
+            mTags = (HashSet<String>) aa.mTags.clone();
+        }
+
+        /**
+         * Combines all of the attributes that have been set and return a new
+         * {@link AudioAttributes} object.
+         * @return a new {@link AudioAttributes} object
+         */
+        @SuppressWarnings("unchecked") // for cloning of mTags
+        public AudioAttributes build() {
+            AudioAttributes aa = new AudioAttributes();
+            aa.mContentType = mContentType;
+            aa.mUsage = mUsage;
+            aa.mFlags = mFlags;
+            aa.mTags = (HashSet<String>) mTags.clone();
+            return aa;
+        }
+
+        /**
+         * Sets the attribute describing what is the intended use of the the audio signal,
+         * such as alarm or ringtone.
+         * @param usage one of {@link AudioAttributes#USAGE_UNKNOWN},
+         *     {@link AudioAttributes#USAGE_MEDIA},
+         *     {@link AudioAttributes#USAGE_VOICE_COMMUNICATION},
+         *     {@link AudioAttributes#USAGE_VOICE_COMMUNICATION_SIGNALLING},
+         *     {@link AudioAttributes#USAGE_ALARM}, {@link AudioAttributes#USAGE_NOTIFICATION},
+         *     {@link AudioAttributes#USAGE_NOTIFICATION_TELEPHONY_RINGTONE},
+         *     {@link AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_REQUEST},
+         *     {@link AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_INSTANT},
+         *     {@link AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_DELAYED},
+         *     {@link AudioAttributes#USAGE_NOTIFICATION_EVENT},
+         *     {@link AudioAttributes#USAGE_ASSISTANCE_ACCESSIBILITY},
+         *     {@link AudioAttributes#USAGE_ASSISTANCE_NAVIGATION_GUIDANCE},
+         *     {@link AudioAttributes#USAGE_ASSISTANCE_SONIFICATION},
+         *     {@link AudioAttributes#USAGE_GAME}.
+         * @return the same Builder instance.
+         */
+        public Builder setUsage(@AttributeUsage int usage) {
+            switch (usage) {
+                case USAGE_UNKNOWN:
+                case USAGE_MEDIA:
+                case USAGE_VOICE_COMMUNICATION:
+                case USAGE_VOICE_COMMUNICATION_SIGNALLING:
+                case USAGE_ALARM:
+                case USAGE_NOTIFICATION:
+                case USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
+                case USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
+                case USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
+                case USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
+                case USAGE_NOTIFICATION_EVENT:
+                case USAGE_ASSISTANCE_ACCESSIBILITY:
+                case USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
+                case USAGE_ASSISTANCE_SONIFICATION:
+                case USAGE_GAME:
+                     mUsage = usage;
+                     break;
+                default:
+                     mUsage = USAGE_UNKNOWN;
+            }
+            return this;
+        }
+
+        /**
+         * Sets the attribute describing the content type of the audio signal, such as speech,
+         * or music.
+         * @param contentType the content type values, one of
+         *     {@link AudioAttributes#CONTENT_TYPE_MOVIE},
+         *     {@link AudioAttributes#CONTENT_TYPE_MUSIC},
+         *     {@link AudioAttributes#CONTENT_TYPE_SONIFICATION},
+         *     {@link AudioAttributes#CONTENT_TYPE_SPEECH},
+         *     {@link AudioAttributes#CONTENT_TYPE_UNKNOWN}.
+         * @return the same Builder instance.
+         */
+        public Builder setContentType(@AttributeContentType int contentType) {
+            switch (contentType) {
+                case CONTENT_TYPE_UNKNOWN:
+                case CONTENT_TYPE_MOVIE:
+                case CONTENT_TYPE_MUSIC:
+                case CONTENT_TYPE_SONIFICATION:
+                case CONTENT_TYPE_SPEECH:
+                     mContentType = contentType;
+                     break;
+                default:
+                     mUsage = CONTENT_TYPE_UNKNOWN;
+            }
+            return this;
+        }
+
+        /**
+         * Sets the combination of flags.
+         * @param flags the {@link AudioAttributes#FLAG_AUDIBILITY_ENFORCED} flag.
+         * @return the same Builder instance.
+         */
+        public Builder setFlags(int flags) {
+            flags &= (AudioAttributes.FLAG_AUDIBILITY_ENFORCED | AudioAttributes.FLAG_SCO
+                    | AudioAttributes.FLAG_SECURE);
+            mFlags |= flags;
+            return this;
+        }
+
+        /**
+         * Add a custom tag stored as a string
+         * @param tag
+         * @return the same Builder instance.
+         */
+        public Builder addTag(String tag) {
+            mTags.add(tag);
+            return this;
+        }
+
+        /**
+         * Adds attributes inferred from the legacy stream types.
+         * @param streamType one of {@link AudioManager#STREAM_VOICE_CALL},
+         *   {@link AudioManager#STREAM_SYSTEM}, {@link AudioManager#STREAM_RING},
+         *   {@link AudioManager#STREAM_MUSIC}, {@link AudioManager#STREAM_ALARM},
+         *    or {@link AudioManager#STREAM_NOTIFICATION}.
+         * @return the same Builder instance.
+         */
+        public Builder setLegacyStreamType(int streamType) {
+            return setInternalLegacyStreamType(streamType);
+        }
+
+        /**
+         * @hide
+         * For internal framework use only, enables building from hidden stream types.
+         * @param streamType
+         * @return the same Builder instance.
+         */
+        public Builder setInternalLegacyStreamType(int streamType) {
+            switch(streamType) {
+                case AudioSystem.STREAM_VOICE_CALL:
+                    mContentType = CONTENT_TYPE_SPEECH;
+                    mUsage = USAGE_VOICE_COMMUNICATION;
+                    break;
+                case AudioSystem.STREAM_SYSTEM_ENFORCED:
+                    mFlags |= FLAG_AUDIBILITY_ENFORCED;
+                    // intended fall through, attributes in common with STREAM_SYSTEM
+                case AudioSystem.STREAM_SYSTEM:
+                    mContentType = CONTENT_TYPE_SONIFICATION;
+                    mUsage = USAGE_ASSISTANCE_SONIFICATION;
+                    break;
+                case AudioSystem.STREAM_RING:
+                    mContentType = CONTENT_TYPE_SONIFICATION;
+                    mUsage = USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+                    break;
+                case AudioSystem.STREAM_MUSIC:
+                    mContentType = CONTENT_TYPE_MUSIC;
+                    mUsage = USAGE_MEDIA;
+                    break;
+                case AudioSystem.STREAM_ALARM:
+                    mContentType = CONTENT_TYPE_SONIFICATION;
+                    mUsage = USAGE_ALARM;
+                    break;
+                case AudioSystem.STREAM_NOTIFICATION:
+                    mContentType = CONTENT_TYPE_SONIFICATION;
+                    mUsage = USAGE_NOTIFICATION;
+                    break;
+                case AudioSystem.STREAM_BLUETOOTH_SCO:
+                    mContentType = CONTENT_TYPE_SPEECH;
+                    mUsage = USAGE_VOICE_COMMUNICATION;
+                    mFlags |= FLAG_SCO;
+                    break;
+                case AudioSystem.STREAM_DTMF:
+                    mContentType = CONTENT_TYPE_SONIFICATION;
+                    mUsage = USAGE_VOICE_COMMUNICATION_SIGNALLING;
+                    break;
+                case AudioSystem.STREAM_TTS:
+                    mContentType = CONTENT_TYPE_SPEECH;
+                    mUsage = USAGE_ASSISTANCE_ACCESSIBILITY;
+                    break;
+                default:
+                    Log.e(TAG, "Invalid stream type " + streamType + " in for AudioAttributes");
+            }
+            return this;
+        }
+    };
+
+    /** @hide */
+    @Override
+    public String toString () {
+        return new String("AudioAttributes:"
+                + " usage=" + mUsage
+                + " content=" + mContentType
+                + " flags=0x" + Integer.toHexString(mFlags)
+                + " tags=" + mTags);
+    }
+
+    /** @hide */
+    @IntDef({
+        USAGE_UNKNOWN,
+        USAGE_MEDIA,
+        USAGE_VOICE_COMMUNICATION,
+        USAGE_VOICE_COMMUNICATION_SIGNALLING,
+        USAGE_ALARM,
+        USAGE_NOTIFICATION,
+        USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
+        USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
+        USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
+        USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
+        USAGE_NOTIFICATION_EVENT,
+        USAGE_ASSISTANCE_ACCESSIBILITY,
+        USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+        USAGE_ASSISTANCE_SONIFICATION,
+        USAGE_GAME
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AttributeUsage {}
+
+    /** @hide */
+    @IntDef({
+        CONTENT_TYPE_UNKNOWN,
+        CONTENT_TYPE_SPEECH,
+        CONTENT_TYPE_MUSIC,
+        CONTENT_TYPE_MOVIE,
+        CONTENT_TYPE_SONIFICATION
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AttributeContentType {}
+}
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index ad0d459..57274ee 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -32,11 +32,13 @@
     /** Default audio data format */
     public static final int ENCODING_DEFAULT = 1;
 
-    // These two values must be kept in sync with core/jni/android_media_AudioFormat.h
+    // These values must be kept in sync with core/jni/android_media_AudioFormat.h
     /** Audio data format: PCM 16 bit per sample. Guaranteed to be supported by devices. */
     public static final int ENCODING_PCM_16BIT = 2;
     /** Audio data format: PCM 8 bit per sample. Not guaranteed to be supported by devices. */
     public static final int ENCODING_PCM_8BIT = 3;
+    /** Audio data format: single-precision floating-point per sample */
+    public static final int ENCODING_PCM_FLOAT = 4;
 
     /** Invalid audio channel configuration */
     /** @deprecated use CHANNEL_INVALID instead  */
@@ -139,4 +141,19 @@
     public static final int CHANNEL_IN_FRONT_BACK = CHANNEL_IN_FRONT | CHANNEL_IN_BACK;
     // CHANNEL_IN_ALL is not yet defined; if added then it should match AUDIO_CHANNEL_IN_ALL
 
+    /** @hide */
+    public static int getBytesPerSample(int audioFormat)
+    {
+        switch (audioFormat) {
+        case ENCODING_PCM_8BIT:
+            return 1;
+        case ENCODING_PCM_16BIT:
+        case ENCODING_DEFAULT:
+            return 2;
+        case ENCODING_INVALID:
+        default:
+            throw new IllegalArgumentException("Bad audio format " + audioFormat);
+        }
+    }
+
 }
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 8ae06e0..1dcfcb8 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -25,6 +25,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.media.RemoteController.OnClientUpdateListener;
+import android.media.session.MediaSessionLegacyHelper;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -48,6 +49,12 @@
  */
 public class AudioManager {
 
+    // If we should use the new sessions APIs.
+    private final static boolean USE_SESSIONS = true;
+    // If we should use the legacy APIs. If both are true information will be
+    // duplicated through both paths. Currently this flag isn't used.
+    private final static boolean USE_LEGACY = true;
+
     private final Context mContext;
     private long mVolumeKeyUpTime;
     private final boolean mUseMasterVolume;
@@ -421,6 +428,7 @@
     public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE;
 
     private static IAudioService sService;
+    private MediaSessionLegacyHelper mSessionHelper;
 
     /**
      * @hide
@@ -431,6 +439,9 @@
                 com.android.internal.R.bool.config_useMasterVolume);
         mUseVolumeKeySounds = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_useVolumeKeySounds);
+        if (USE_SESSIONS) {
+            mSessionHelper = MediaSessionLegacyHelper.getHelper(context);
+        }
     }
 
     private static IAudioService getService()
@@ -2166,6 +2177,9 @@
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in registerMediaButtonIntent"+e);
         }
+        if (USE_SESSIONS) {
+            mSessionHelper.addMediaButtonListener(pi, mContext);
+        }
     }
 
     /**
@@ -2239,6 +2253,9 @@
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in unregisterMediaButtonIntent"+e);
         }
+        if (USE_SESSIONS) {
+            mSessionHelper.removeMediaButtonListener(pi);
+        }
     }
 
     /**
@@ -2263,6 +2280,9 @@
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in registerRemoteControlClient"+e);
         }
+        if (USE_SESSIONS) {
+            rcClient.registerWithSession(mSessionHelper);
+        }
     }
 
     /**
@@ -2282,6 +2302,9 @@
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in unregisterRemoteControlClient"+e);
         }
+        if (USE_SESSIONS) {
+            rcClient.unregisterWithSession(mSessionHelper);
+        }
     }
 
     /**
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index a4891f8..384e120 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -319,7 +319,7 @@
         // NB: this section is only valid with PCM data.
         // To update when supporting compressed formats
         int frameSizeInBytes = mChannelCount
-            * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
+            * (AudioFormat.getBytesPerSample(mAudioFormat));
         if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
             throw new IllegalArgumentException("Invalid audio buffer size.");
         }
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 4513ead..724022b 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -149,6 +149,7 @@
     private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
     private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
     private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
+    private static final int MSG_SYSTEM_READY = 21;
     // start of messages handled under wakelock
     //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
     //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -370,7 +371,7 @@
     private int mScoConnectionState;
 
     // true if boot sequence has been completed
-    private boolean mBootCompleted;
+    private boolean mSystemReady;
     // listener for SoundPool sample load completion indication
     private SoundPoolCallback mSoundPoolCallBack;
     // thread for SoundPool listener
@@ -525,7 +526,6 @@
         intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
         intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
         intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
-        intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
         intentFilter.addAction(Intent.ACTION_SCREEN_ON);
         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
         intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
@@ -559,6 +559,43 @@
 
     }
 
+    public void systemReady() {
+        sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
+                0, 0, null, 0);
+    }
+
+    public void onSystemReady() {
+        mSystemReady = true;
+        sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
+                0, 0, null, 0);
+
+        mKeyguardManager =
+                (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+        mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
+        resetBluetoothSco();
+        getBluetoothHeadset();
+        //FIXME: this is to maintain compatibility with deprecated intent
+        // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
+        Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
+        newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
+                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+        sendStickyBroadcastToAll(newIntent);
+
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter != null) {
+            adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
+                                    BluetoothProfile.A2DP);
+        }
+
+        sendMsg(mAudioHandler,
+                MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
+                SENDMSG_REPLACE,
+                0,
+                0,
+                null,
+                SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
+    }
+
     private void createAudioSystemThread() {
         mAudioSystemThread = new AudioSystemThread();
         mAudioSystemThread.start();
@@ -1787,6 +1824,11 @@
 
     /** @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);
     }
@@ -1991,7 +2033,7 @@
     /** @see AudioManager#startBluetoothSco() */
     public void startBluetoothSco(IBinder cb, int targetSdkVersion){
         if (!checkAudioSettingsPermission("startBluetoothSco()") ||
-                !mBootCompleted) {
+                !mSystemReady) {
             return;
         }
         ScoClient client = getScoClient(cb, true);
@@ -2008,7 +2050,7 @@
     /** @see AudioManager#stopBluetoothSco() */
     public void stopBluetoothSco(IBinder cb){
         if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
-                !mBootCompleted) {
+                !mSystemReady) {
             return;
         }
         ScoClient client = getScoClient(cb, false);
@@ -3272,7 +3314,7 @@
             int status;
 
             synchronized (mSoundEffectsLock) {
-                if (!mBootCompleted) {
+                if (!mSystemReady) {
                     Log.w(TAG, "onLoadSoundEffects() called before boot complete");
                     return false;
                 }
@@ -3695,6 +3737,10 @@
                 case MSG_BROADCAST_BT_CONNECTION_STATE:
                     onBroadcastScoConnectionState(msg.arg1);
                     break;
+
+                case MSG_SYSTEM_READY:
+                    onSystemReady();
+                    break;
             }
         }
     }
@@ -4164,36 +4210,6 @@
                     newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
                     sendStickyBroadcastToAll(newIntent);
                 }
-            } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
-                mBootCompleted = true;
-                sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
-                        0, 0, null, 0);
-
-                mKeyguardManager =
-                        (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
-                mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
-                resetBluetoothSco();
-                getBluetoothHeadset();
-                //FIXME: this is to maintain compatibility with deprecated intent
-                // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
-                Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
-                newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
-                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
-                sendStickyBroadcastToAll(newIntent);
-
-                BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-                if (adapter != null) {
-                    adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
-                                            BluetoothProfile.A2DP);
-                }
-
-                sendMsg(mAudioHandler,
-                        MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
-                        SENDMSG_REPLACE,
-                        0,
-                        0,
-                        null,
-                        SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
             } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
                 AudioSystem.setParameters("screen_state=on");
             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 17840f2..1a64cff 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -42,7 +42,8 @@
  * The AudioTrack class manages and plays a single audio resource for Java applications.
  * It allows streaming of PCM audio buffers to the audio sink for playback. This is
  * achieved by "pushing" the data to the AudioTrack object using one of the
- *  {@link #write(byte[], int, int)} and {@link #write(short[], int, int)} methods.
+ *  {@link #write(byte[], int, int)}, {@link #write(short[], int, int)},
+ *  and {@link #write(float[], int, int, int)} methods.
  *
  * <p>An AudioTrack instance can operate under two modes: static or streaming.<br>
  * In Streaming mode, the application writes a continuous stream of data to the AudioTrack, using
@@ -172,16 +173,14 @@
     public @interface WriteMode {}
 
     /**
-     * @hide CANDIDATE FOR PUBLIC API
      * The write mode indicating the write operation will block until all data has been written,
-     * to be used in {@link #write(ByteBuffer, int, int, int)}.
+     * to be used in {@link #write(ByteBuffer, int, int)}
      */
     public final static int WRITE_BLOCKING = 0;
     /**
-     * @hide CANDIDATE FOR PUBLIC API
      * The write mode indicating the write operation will return immediately after
      * queuing as much audio data for playback as possible without blocking, to be used in
-     * {@link #write(ByteBuffer, int, int, int)}.
+     * {@link #write(ByteBuffer, int, int)}.
      */
     public final static int WRITE_NON_BLOCKING = 1;
 
@@ -246,6 +245,7 @@
      * The encoding of the audio samples.
      * @see AudioFormat#ENCODING_PCM_8BIT
      * @see AudioFormat#ENCODING_PCM_16BIT
+     * @see AudioFormat#ENCODING_PCM_FLOAT
      */
     private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
     /**
@@ -287,8 +287,9 @@
      *   See {@link AudioFormat#CHANNEL_OUT_MONO} and
      *   {@link AudioFormat#CHANNEL_OUT_STEREO}
      * @param audioFormat the format in which the audio data is represented.
-     *   See {@link AudioFormat#ENCODING_PCM_16BIT} and
-     *   {@link AudioFormat#ENCODING_PCM_8BIT}
+     *   See {@link AudioFormat#ENCODING_PCM_16BIT},
+     *   {@link AudioFormat#ENCODING_PCM_8BIT},
+     *   and {@link AudioFormat#ENCODING_PCM_FLOAT}.
      * @param bufferSizeInBytes the total size (in bytes) of the internal buffer where audio data is
      *   read from for playback.
      *   If track's creation mode is {@link #MODE_STREAM}, you can write data into
@@ -331,7 +332,8 @@
      *   {@link AudioFormat#CHANNEL_OUT_STEREO}
      * @param audioFormat the format in which the audio data is represented.
      *   See {@link AudioFormat#ENCODING_PCM_16BIT} and
-     *   {@link AudioFormat#ENCODING_PCM_8BIT}
+     *   {@link AudioFormat#ENCODING_PCM_8BIT},
+     *   and {@link AudioFormat#ENCODING_PCM_FLOAT}.
      * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is read
      *   from for playback. If using the AudioTrack in streaming mode, you can write data into
      *   this buffer in smaller chunks than this size. If using the AudioTrack in static mode,
@@ -461,11 +463,14 @@
             break;
         case AudioFormat.ENCODING_PCM_16BIT:
         case AudioFormat.ENCODING_PCM_8BIT:
+        case AudioFormat.ENCODING_PCM_FLOAT:
             mAudioFormat = audioFormat;
             break;
         default:
             throw new IllegalArgumentException("Unsupported sample encoding."
-                + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT.");
+                + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT"
+                + " or ENCODING_PCM_FLOAT"
+                + ".");
         }
 
         //--------------
@@ -518,7 +523,7 @@
         // NB: this section is only valid with PCM data.
         //     To update when supporting compressed formats
         int frameSizeInBytes = mChannelCount
-                * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
+                * (AudioFormat.getBytesPerSample(mAudioFormat));
         if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
             throw new IllegalArgumentException("Invalid audio buffer size.");
         }
@@ -725,7 +730,8 @@
      *   {@link AudioFormat#CHANNEL_OUT_STEREO}
      * @param audioFormat the format in which the audio data is represented.
      *   See {@link AudioFormat#ENCODING_PCM_16BIT} and
-     *   {@link AudioFormat#ENCODING_PCM_8BIT}
+     *   {@link AudioFormat#ENCODING_PCM_8BIT},
+     *   and {@link AudioFormat#ENCODING_PCM_FLOAT}.
      * @return {@link #ERROR_BAD_VALUE} if an invalid parameter was passed,
      *   or {@link #ERROR} if unable to query for output properties,
      *   or the minimum buffer size expressed in bytes.
@@ -752,7 +758,8 @@
         }
 
         if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT)
-            && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) {
+            && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)
+            && (audioFormat != AudioFormat.ENCODING_PCM_FLOAT)) {
             loge("getMinBufferSize(): Invalid audio format.");
             return ERROR_BAD_VALUE;
         }
@@ -1152,7 +1159,7 @@
 
     public int write(byte[] audioData, int offsetInBytes, int sizeInBytes) {
 
-        if (mState == STATE_UNINITIALIZED) {
+        if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
             return ERROR_INVALID_OPERATION;
         }
 
@@ -1190,13 +1197,13 @@
      *     starts.
      * @param sizeInShorts the number of shorts to read in audioData after the offset.
      * @return the number of shorts that were written or {@link #ERROR_INVALID_OPERATION}
-      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
-      *    the parameters don't resolve to valid data and indexes.
+     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+     *    the parameters don't resolve to valid data and indexes.
      */
 
     public int write(short[] audioData, int offsetInShorts, int sizeInShorts) {
 
-        if (mState == STATE_UNINITIALIZED) {
+        if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
             return ERROR_INVALID_OPERATION;
         }
 
@@ -1220,7 +1227,79 @@
 
 
     /**
-     * @hide CANDIDATE FOR PUBLIC API
+     * Writes the audio data to the audio sink for playback (streaming mode),
+     * or copies audio data for later playback (static buffer mode).
+     * In static buffer mode, copies the data to the buffer starting at offset 0,
+     * and the write mode is ignored.
+     * In streaming mode, the blocking behavior will depend on the write mode.
+     * <p>
+     * Note that the actual playback of this data might occur after this function
+     * returns. This function is thread safe with respect to {@link #stop} calls,
+     * in which case all of the specified data might not be written to the audio sink.
+     * <p>
+     * @param audioData the array that holds the data to play.
+     *     The implementation does not clip for sample values within the nominal range
+     *     [-1.0f, 1.0f], provided that all gains in the audio pipeline are
+     *     less than or equal to unity (1.0f), and in the absence of post-processing effects
+     *     that could add energy, such as reverb.  For the convenience of applications
+     *     that compute samples using filters with non-unity gain,
+     *     sample values +3 dB beyond the nominal range are permitted.
+     *     However such values may eventually be limited or clipped, depending on various gains
+     *     and later processing in the audio path.  Therefore applications are encouraged
+     *     to provide samples values within the nominal range.
+     * @param offsetInFloats the offset, expressed as a number of floats,
+     *     in audioData where the data to play starts.
+     * @param sizeInFloats the number of floats to read in audioData after the offset.
+     * @param writeMode one of {@link #WRITE_BLOCKING}, {@link #WRITE_NON_BLOCKING}. It has no
+     *     effect in static mode.
+     *     <BR>With {@link #WRITE_BLOCKING}, the write will block until all data has been written
+     *         to the audio sink.
+     *     <BR>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after
+     *     queuing as much audio data for playback as possible without blocking.
+     * @return the number of floats that were written, or {@link #ERROR_INVALID_OPERATION}
+     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+     *    the parameters don't resolve to valid data and indexes.
+     */
+    public int write(float[] audioData, int offsetInFloats, int sizeInFloats,
+            @WriteMode int writeMode) {
+
+        if (mState == STATE_UNINITIALIZED) {
+            Log.e(TAG, "AudioTrack.write() called in invalid state STATE_UNINITIALIZED");
+            return ERROR_INVALID_OPERATION;
+        }
+
+        if (mAudioFormat != AudioFormat.ENCODING_PCM_FLOAT) {
+            Log.e(TAG, "AudioTrack.write(float[] ...) requires format ENCODING_PCM_FLOAT");
+            return ERROR_INVALID_OPERATION;
+        }
+
+        if ((writeMode != WRITE_BLOCKING) && (writeMode != WRITE_NON_BLOCKING)) {
+            Log.e(TAG, "AudioTrack.write() called with invalid blocking mode");
+            return ERROR_BAD_VALUE;
+        }
+
+        if ( (audioData == null) || (offsetInFloats < 0 ) || (sizeInFloats < 0)
+                || (offsetInFloats + sizeInFloats < 0)  // detect integer overflow
+                || (offsetInFloats + sizeInFloats > audioData.length)) {
+            Log.e(TAG, "AudioTrack.write() called with invalid array, offset, or size");
+            return ERROR_BAD_VALUE;
+        }
+
+        int ret = native_write_float(audioData, offsetInFloats, sizeInFloats, mAudioFormat,
+                writeMode == WRITE_BLOCKING);
+
+        if ((mDataLoadMode == MODE_STATIC)
+                && (mState == STATE_NO_STATIC_DATA)
+                && (ret > 0)) {
+            // benign race with respect to other APIs that read mState
+            mState = STATE_INITIALIZED;
+        }
+
+        return ret;
+    }
+
+
+    /**
      * Writes the audio data to the audio sink for playback (streaming mode),
      * or copies audio data for later playback (static buffer mode).
      * In static buffer mode, copies the data to the buffer starting at its 0 offset, and the write
@@ -1250,6 +1329,11 @@
             return ERROR_INVALID_OPERATION;
         }
 
+        if (mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
+            Log.e(TAG, "AudioTrack.write(ByteBuffer ...) not yet supported for ENCODING_PCM_FLOAT");
+            return ERROR_INVALID_OPERATION;
+        }
+
         if ((writeMode != WRITE_BLOCKING) && (writeMode != WRITE_NON_BLOCKING)) {
             Log.e(TAG, "AudioTrack.write() called with invalid blocking mode");
             return ERROR_BAD_VALUE;
@@ -1490,6 +1574,10 @@
     private native final int native_write_short(short[] audioData,
                                                 int offsetInShorts, int sizeInShorts, int format);
 
+    private native final int native_write_float(float[] audioData,
+                                                int offsetInFloats, int sizeInFloats, int format,
+                                                boolean isBlocking);
+
     private native final int native_write_native_bytes(Object audioData,
             int positionInBytes, int sizeInBytes, int format, boolean blocking);
 
diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java
index bd91fc5..7735e78 100644
--- a/media/java/android/media/JetPlayer.java
+++ b/media/java/android/media/JetPlayer.java
@@ -169,9 +169,11 @@
                             
             native_setup(new WeakReference<JetPlayer>(this),
                     JetPlayer.getMaxTracks(),
-                    // bytes to frame conversion: sample format is ENCODING_PCM_16BIT, 2 channels
+                    // bytes to frame conversion:
                     // 1200 == minimum buffer size in frames on generation 1 hardware
-                    Math.max(1200, buffSizeInBytes / 4));
+                    Math.max(1200, buffSizeInBytes /
+                            (AudioFormat.getBytesPerSample(AudioFormat.ENCODING_PCM_16BIT) *
+                            2 /*channels*/)));
         }
     }
     
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 115786c..34c55202 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -585,11 +585,63 @@
      * the codec. If you previously specified a surface when configuring this
      * video decoder you can optionally render the buffer.
      * @param index The index of a client-owned output buffer previously returned
-     *              in a call to {@link #dequeueOutputBuffer}.
+     *              from a call to {@link #dequeueOutputBuffer}.
      * @param render If a valid surface was specified when configuring the codec,
      *               passing true renders this output buffer to the surface.
      */
-    public native final void releaseOutputBuffer(int index, boolean render);
+    public final void releaseOutputBuffer(int index, boolean render) {
+        releaseOutputBuffer(index, render, false /* updatePTS */, 0 /* dummy */);
+    }
+
+    /**
+     * If you are done with a buffer, use this call to update its surface timestamp
+     * and return it to the codec to render it on the output surface. If you
+     * have not specified an output surface when configuring this video codec,
+     * this call will simply return the buffer to the codec.<p>
+     *
+     * The timestamp may have special meaning depending on the destination surface.
+     *
+     * <table>
+     * <tr><th>SurfaceView specifics</th></tr>
+     * <tr><td>
+     * If you render your buffer on a {@link android.view.SurfaceView},
+     * you can use the timestamp to render the buffer at a specific time (at the
+     * VSYNC at or after the buffer timestamp).  For this to work, the timestamp
+     * needs to be <i>reasonably close</i> to the current {@link System#nanoTime}.
+     * Currently, this is set as within one (1) second. A few notes:
+     *
+     * <ul>
+     * <li>the buffer will not be returned to the codec until the timestamp
+     * has passed and the buffer is no longer used by the {@link android.view.Surface}.
+     * <li>buffers are processed sequentially, so you may block subsequent buffers to
+     * be displayed on the {@link android.view.Surface}.  This is important if you
+     * want to react to user action, e.g. stop the video or seek.
+     * <li>if multiple buffers are sent to the {@link android.view.Surface} to be
+     * rendered at the same VSYNC, the last one will be shown, and the other ones
+     * will be dropped.
+     * <li>if the timestamp is <em>not</em> "reasonably close" to the current system
+     * time, the {@link android.view.Surface} will ignore the timestamp, and
+     * display the buffer at the earliest feasible time.  In this mode it will not
+     * drop frames.
+     * <li>for best performance and quality, call this method when you are about
+     * two VSYNCs' time before the desired render time.  For 60Hz displays, this is
+     * about 33 msec.
+     * </ul>
+     * </td></tr>
+     * </table>
+     *
+     * @param index The index of a client-owned output buffer previously returned
+     *              from a call to {@link #dequeueOutputBuffer}.
+     * @param renderTimestampNs The timestamp to associate with this buffer when
+     *              it is sent to the Surface.
+     */
+    public final void releaseOutputBuffer(int index, long renderTimestampNs) {
+        releaseOutputBuffer(
+                index, true /* render */, true /* updatePTS */, renderTimestampNs);
+    }
+
+    private native final void releaseOutputBuffer(
+            int index, boolean render, boolean updatePTS, long timeNs);
 
     /**
      * Signals end-of-stream on input.  Equivalent to submitting an empty buffer with
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index 2dea509..1c73c05 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -1250,8 +1250,6 @@
                 }
                 if (prse.hasMatchingMediaButtonIntent(mediaIntent)) {
                     inStackIndex = index;
-                    // found it, ok to stop here
-                    break;
                 }
             }
 
@@ -1272,7 +1270,11 @@
                         mPRStack.push(prse);
                     } else {
                         // and put it after the ones with active playback
-                        mPRStack.add(lastPlayingIndex, prse);
+                        if (inStackIndex > lastPlayingIndex) {
+                            mPRStack.add(lastPlayingIndex, prse);
+                        } else {
+                            mPRStack.add(lastPlayingIndex - 1, prse);
+                        }
                     }
                 }
             }
@@ -2151,13 +2153,13 @@
                 // of this RemoteControlClient (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.getRccId() == rccId) {
                         inStackIndex = index;
                         prse.mPlaybackState = newState;
                     }
+                    if (prse.isPlaybackActive()) {
+                        lastPlayingIndex = index;
+                    }
                 }
 
                 if (inStackIndex != -1) {
@@ -2177,7 +2179,11 @@
                             mPRStack.push(prse);
                         } else {
                             // and put it after the ones with active playback
-                            mPRStack.add(lastPlayingIndex, prse);
+                            if (inStackIndex > lastPlayingIndex) {
+                                mPRStack.add(lastPlayingIndex, prse);
+                            } else {
+                                mPRStack.add(lastPlayingIndex - 1, prse);
+                            }
                         }
                     }
 
diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java
index eb91668..d3b1520 100644
--- a/media/java/android/media/MediaHTTPConnection.java
+++ b/media/java/android/media/MediaHTTPConnection.java
@@ -28,9 +28,12 @@
 import java.net.URL;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
+import java.net.NoRouteToHostException;
 import java.util.HashMap;
 import java.util.Map;
 
+import static android.media.MediaPlayer.MEDIA_ERROR_UNSUPPORTED;
+
 /** @hide */
 public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
     private static final String TAG = "MediaHTTPConnection";
@@ -43,6 +46,12 @@
     private long mTotalSize = -1;
     private InputStream mInputStream = null;
 
+    private boolean mAllowCrossDomainRedirect = true;
+
+    // from com.squareup.okhttp.internal.http
+    private final static int HTTP_TEMP_REDIRECT = 307;
+    private final static int MAX_REDIRECTS = 20;
+
     public MediaHTTPConnection() {
         if (CookieHandler.getDefault() == null) {
             CookieHandler.setDefault(new CookieManager());
@@ -59,6 +68,7 @@
 
         try {
             disconnect();
+            mAllowCrossDomainRedirect = true;
             mURL = new URL(uri);
             mHeaders = convertHeaderStringToMap(headers);
         } catch (MalformedURLException e) {
@@ -68,6 +78,25 @@
         return native_getIMemory();
     }
 
+    private boolean parseBoolean(String val) {
+        try {
+            return Long.parseLong(val) != 0;
+        } catch (NumberFormatException e) {
+            return "true".equalsIgnoreCase(val) ||
+                "yes".equalsIgnoreCase(val);
+        }
+    }
+
+    /* returns true iff header is internal */
+    private boolean filterOutInternalHeaders(String key, String val) {
+        if ("android-allow-cross-domain-redirect".equalsIgnoreCase(key)) {
+            mAllowCrossDomainRedirect = parseBoolean(val);
+        } else {
+            return false;
+        }
+        return true;
+    }
+
     private Map<String, String> convertHeaderStringToMap(String headers) {
         HashMap<String, String> map = new HashMap<String, String>();
 
@@ -78,7 +107,9 @@
                 String key = pair.substring(0, colonPos);
                 String val = pair.substring(colonPos + 1);
 
-                map.put(key, val);
+                if (!filterOutInternalHeaders(key, val)) {
+                    map.put(key, val);
+                }
             }
         }
 
@@ -107,24 +138,75 @@
         teardownConnection();
 
         try {
-            mConnection = (HttpURLConnection)mURL.openConnection();
+            int response;
+            int redirectCount = 0;
 
-            if (mHeaders != null) {
-                for (Map.Entry<String, String> entry : mHeaders.entrySet()) {
+            URL url = mURL;
+            while (true) {
+                mConnection = (HttpURLConnection)url.openConnection();
+                // handle redirects ourselves if we do not allow cross-domain redirect
+                mConnection.setInstanceFollowRedirects(mAllowCrossDomainRedirect);
+
+                if (mHeaders != null) {
+                    for (Map.Entry<String, String> entry : mHeaders.entrySet()) {
+                        mConnection.setRequestProperty(
+                                entry.getKey(), entry.getValue());
+                    }
+                }
+
+                if (offset > 0) {
                     mConnection.setRequestProperty(
-                            entry.getKey(), entry.getValue());
+                            "Range", "bytes=" + offset + "-");
+                }
+
+                response = mConnection.getResponseCode();
+                if (response != HttpURLConnection.HTTP_MULT_CHOICE &&
+                        response != HttpURLConnection.HTTP_MOVED_PERM &&
+                        response != HttpURLConnection.HTTP_MOVED_TEMP &&
+                        response != HttpURLConnection.HTTP_SEE_OTHER &&
+                        response != HTTP_TEMP_REDIRECT) {
+                    // not a redirect, or redirect handled by HttpURLConnection
+                    break;
+                }
+
+                if (++redirectCount > MAX_REDIRECTS) {
+                    throw new NoRouteToHostException("Too many redirects: " + redirectCount);
+                }
+
+                String method = mConnection.getRequestMethod();
+                if (response == HTTP_TEMP_REDIRECT &&
+                        !method.equals("GET") && !method.equals("HEAD")) {
+                    // "If the 307 status code is received in response to a
+                    // request other than GET or HEAD, the user agent MUST NOT
+                    // automatically redirect the request"
+                    throw new NoRouteToHostException("Invalid redirect");
+                }
+                String location = mConnection.getHeaderField("Location");
+                if (location == null) {
+                    throw new NoRouteToHostException("Invalid redirect");
+                }
+                url = new URL(mURL /* TRICKY: don't use url! */, location);
+                if (!url.getProtocol().equals("https") &&
+                        !url.getProtocol().equals("http")) {
+                    throw new NoRouteToHostException("Unsupported protocol redirect");
+                }
+                boolean sameHost = mURL.getHost().equals(url.getHost());
+                if (!sameHost) {
+                    throw new NoRouteToHostException("Cross-domain redirects are disallowed");
+                }
+
+                if (response != HTTP_TEMP_REDIRECT) {
+                    // update effective URL, unless it is a Temporary Redirect
+                    mURL = url;
                 }
             }
 
-            if (offset > 0) {
-                mConnection.setRequestProperty(
-                        "Range", "bytes=" + offset + "-");
+            if (mAllowCrossDomainRedirect) {
+                // remember the current, potentially redirected URL if redirects
+                // were handled by HttpURLConnection
+                mURL = mConnection.getURL();
             }
 
-            int response = mConnection.getResponseCode();
-            // remember the current, possibly redirected URL
-            mURL = mConnection.getURL();
-
             if (response == HttpURLConnection.HTTP_PARTIAL) {
                 // Partial content, we cannot just use getContentLength
                 // because what we want is not just the length of the range
@@ -207,6 +289,9 @@
             }
 
             return n;
+        } catch (NoRouteToHostException e) {
+            Log.w(TAG, "readAt " + offset + " / " + size + " => " + e);
+            return MEDIA_ERROR_UNSUPPORTED;
         } catch (IOException e) {
             if (VERBOSE) {
                 Log.d(TAG, "readAt " + offset + " / " + size + " => -1");
diff --git a/media/java/android/media/MediaMetadataEditor.java b/media/java/android/media/MediaMetadataEditor.java
index 3bfdb5a..1a4e8da 100644
--- a/media/java/android/media/MediaMetadataEditor.java
+++ b/media/java/android/media/MediaMetadataEditor.java
@@ -17,6 +17,7 @@
 package android.media;
 
 import android.graphics.Bitmap;
+import android.media.session.MediaMetadata;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.util.Log;
@@ -106,6 +107,10 @@
      */
     protected Bundle mEditorMetadata;
 
+    /**
+     * @hide
+     */
+    protected MediaMetadata.Builder mMetadataBuilder;
 
     /**
      * Clears all the pending metadata changes set since the MediaMetadataEditor instance was
@@ -120,6 +125,7 @@
         }
         mEditorMetadata.clear();
         mEditorArtwork = null;
+        mMetadataBuilder = new MediaMetadata.Builder();
     }
 
     /**
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index c2c61d3..8368df94 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -24,6 +24,11 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.RectF;
+import android.media.session.MediaMetadata;
+import android.media.session.MediaSessionLegacyHelper;
+import android.media.session.PlaybackState;
+import android.media.session.Session;
+import android.media.session.TransportPerformer;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -336,6 +341,8 @@
      */
     public final static int FLAG_INFORMATION_REQUEST_ALBUM_ART = 1 << 3;
 
+    private Session mSession;
+
     /**
      * Class constructor.
      * @param mediaButtonIntent The intent that will be sent for the media button events sent
@@ -385,6 +392,22 @@
     }
 
     /**
+     * @hide
+     */
+    public void registerWithSession(MediaSessionLegacyHelper helper) {
+        helper.addRccListener(mRcMediaIntent, mTransportListener);
+        mSession = helper.getSession(mRcMediaIntent);
+    }
+
+    /**
+     * @hide
+     */
+    public void unregisterWithSession(MediaSessionLegacyHelper helper) {
+        helper.removeRccListener(mRcMediaIntent);
+        mSession = null;
+    }
+
+    /**
      * Class used to modify metadata in a {@link RemoteControlClient} object.
      * Use {@link RemoteControlClient#editMetadata(boolean)} to create an instance of an editor,
      * on which you set the metadata for the RemoteControlClient instance. Once all the information
@@ -438,6 +461,15 @@
         public synchronized MetadataEditor putString(int key, String value)
                 throws IllegalArgumentException {
             super.putString(key, value);
+            if (mMetadataBuilder != null) {
+                // MediaMetadata supports all the same fields as MetadataEditor
+                String metadataKey = MediaMetadata.getKeyFromMetadataEditorKey(key);
+                // But just in case, don't add things we don't understand
+                if (metadataKey != null) {
+                    mMetadataBuilder.putString(metadataKey, value);
+                }
+            }
+
             return this;
         }
 
@@ -459,6 +491,14 @@
         public synchronized MetadataEditor putLong(int key, long value)
                 throws IllegalArgumentException {
             super.putLong(key, value);
+            if (mMetadataBuilder != null) {
+                // MediaMetadata supports all the same fields as MetadataEditor
+                String metadataKey = MediaMetadata.getKeyFromMetadataEditorKey(key);
+                // But just in case, don't add things we don't understand
+                if (metadataKey != null) {
+                    mMetadataBuilder.putLong(metadataKey, value);
+                }
+            }
             return this;
         }
 
@@ -476,6 +516,14 @@
         public synchronized MetadataEditor putBitmap(int key, Bitmap bitmap)
                 throws IllegalArgumentException {
             super.putBitmap(key, bitmap);
+            if (mMetadataBuilder != null) {
+                // MediaMetadata supports all the same fields as MetadataEditor
+                String metadataKey = MediaMetadata.getKeyFromMetadataEditorKey(key);
+                // But just in case, don't add things we don't understand
+                if (metadataKey != null) {
+                    mMetadataBuilder.putBitmap(metadataKey, bitmap);
+                }
+            }
             return this;
         }
 
@@ -501,7 +549,7 @@
                 Log.e(TAG, "Can't apply a previously applied MetadataEditor");
                 return;
             }
-            synchronized(mCacheLock) {
+            synchronized (mCacheLock) {
                 // assign the edited data
                 mMetadata = new Bundle(mEditorMetadata);
                 // add the information about editable keys
@@ -521,6 +569,11 @@
                     // send to remote control display if conditions are met
                     sendArtwork_syncCacheLock(null, 0, 0);
                 }
+
+                // USE_SESSIONS
+                if (mSession != null && mMetadataBuilder != null) {
+                    mSession.getTransportPerformer().setMetadata(mMetadataBuilder.build());
+                }
                 mApplied = true;
             }
         }
@@ -546,6 +599,12 @@
             editor.mMetadataChanged = false;
             editor.mArtworkChanged = false;
         }
+        // USE_SESSIONS
+        if (startEmpty || mMediaMetadata == null) {
+            editor.mMetadataBuilder = new MediaMetadata.Builder();
+        } else {
+            editor.mMetadataBuilder = new MediaMetadata.Builder(mMediaMetadata);
+        }
         return editor;
     }
 
@@ -624,6 +683,15 @@
 
                 // handle automatic playback position refreshes
                 initiateCheckForDrift_syncCacheLock();
+
+                // USE_SESSIONS
+                if (mSession != null) {
+                    int pbState = PlaybackState.getStateFromRccState(state);
+                    mSessionPlaybackState.setState(pbState, hasPosition ?
+                            mPlaybackPositionMs : PlaybackState.PLAYBACK_POSITION_UNKNOWN,
+                            playbackSpeed);
+                    mSession.getTransportPerformer().setPlaybackState(mSessionPlaybackState);
+                }
             }
         }
     }
@@ -704,6 +772,13 @@
 
             // send to remote control display if conditions are met
             sendTransportControlInfo_syncCacheLock(null);
+
+            // USE_SESSIONS
+            if (mSession != null) {
+                mSessionPlaybackState.setActions(PlaybackState
+                        .getActionsFromRccControlFlags(transportControlFlags));
+                mSession.getTransportPerformer().setPlaybackState(mSessionPlaybackState);
+            }
         }
     }
 
@@ -1038,6 +1113,16 @@
     private boolean mNeedsPositionSync = false;
 
     /**
+     * Cache for the current playback state using Session APIs.
+     */
+    private final PlaybackState mSessionPlaybackState = new PlaybackState();
+
+    /**
+     * Cache for metadata using Session APIs. This is re-initialized in apply().
+     */
+    private MediaMetadata mMediaMetadata;
+
+    /**
      * A class to encapsulate all the information about a remote control display.
      * A RemoteControlClient's metadata and state may be displayed on multiple IRemoteControlDisplay
      */
@@ -1219,6 +1304,26 @@
         return mRcseId;
     }
 
+    // USE_SESSIONS
+    private TransportPerformer.Listener mTransportListener = new TransportPerformer.Listener() {
+
+        @Override
+        public void onSeekTo(long pos) {
+            RemoteControlClient.this.onSeekTo(mCurrentClientGenId, pos);
+        }
+
+        @Override
+        public void onRate(Rating rating) {
+            if ((mTransportControlFlags & FLAG_KEY_MEDIA_RATING) != 0) {
+                if (mEventHandler != null) {
+                    mEventHandler.sendMessage(mEventHandler.obtainMessage(
+                            MSG_UPDATE_METADATA, mCurrentClientGenId,
+                            MetadataEditor.RATING_KEY_BY_USER, rating));
+                }
+            }
+        }
+    };
+
     private EventHandler mEventHandler;
     private final static int MSG_REQUEST_PLAYBACK_STATE = 1;
     private final static int MSG_REQUEST_METADATA = 2;
@@ -1325,7 +1430,7 @@
             // target == null implies all displays must be updated
             final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
             while (displayIterator.hasNext()) {
-                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+                final DisplayInfoForClient di = displayIterator.next();
                 if (di.mEnabled) {
                     try {
                         di.mRcDisplay.setPlaybackState(mInternalClientGenId,
@@ -1353,7 +1458,7 @@
             // target == null implies all displays must be updated
             final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
             while (displayIterator.hasNext()) {
-                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+                final DisplayInfoForClient di = displayIterator.next();
                 if (di.mEnabled) {
                     try {
                         di.mRcDisplay.setMetadata(mInternalClientGenId, mMetadata);
@@ -1381,7 +1486,7 @@
             // target == null implies all displays must be updated
             final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
             while (displayIterator.hasNext()) {
-                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+                final DisplayInfoForClient di = displayIterator.next();
                 if (di.mEnabled) {
                     try {
                         di.mRcDisplay.setTransportControlInfo(mInternalClientGenId,
@@ -1407,7 +1512,7 @@
             // target == null implies all displays must be updated
             final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
             while (displayIterator.hasNext()) {
-                if (!sendArtworkToDisplay((DisplayInfoForClient) displayIterator.next())) {
+                if (!sendArtworkToDisplay(displayIterator.next())) {
                     displayIterator.remove();
                 }
             }
@@ -1453,7 +1558,7 @@
             // target == null implies all displays must be updated
             final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
             while (displayIterator.hasNext()) {
-                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+                final DisplayInfoForClient di = displayIterator.next();
                 try {
                     if (di.mEnabled) {
                         if ((di.mArtworkExpectedWidth > 0) && (di.mArtworkExpectedHeight > 0)) {
@@ -1537,7 +1642,7 @@
             boolean displayKnown = false;
             final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
             while (displayIterator.hasNext() && !displayKnown) {
-                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+                final DisplayInfoForClient di = displayIterator.next();
                 displayKnown = di.mRcDisplay.asBinder().equals(rcd.asBinder());
                 if (displayKnown) {
                     // this display was known but the change in artwork size will cause the
@@ -1562,7 +1667,7 @@
         synchronized(mCacheLock) {
             Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
             while (displayIterator.hasNext()) {
-                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+                final DisplayInfoForClient di = displayIterator.next();
                 if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
                     displayIterator.remove();
                     break;
@@ -1573,7 +1678,7 @@
             boolean newNeedsPositionSync = false;
             displayIterator = mRcDisplays.iterator();
             while (displayIterator.hasNext()) {
-                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+                final DisplayInfoForClient di = displayIterator.next();
                 if (di.mWantsPositionSync) {
                     newNeedsPositionSync = true;
                     break;
@@ -1592,7 +1697,7 @@
         synchronized(mCacheLock) {
             final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
             while (displayIterator.hasNext()) {
-                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+                final DisplayInfoForClient di = displayIterator.next();
                 if (di.mRcDisplay.asBinder().equals(rcd.asBinder()) &&
                         ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h))) {
                     di.mArtworkExpectedWidth = w;
@@ -1617,7 +1722,7 @@
             // go through the list of RCDs and for each entry, check both whether this is the RCD
             //  that gets upated, and whether the list has one entry that wants position sync
             while (displayIterator.hasNext()) {
-                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+                final DisplayInfoForClient di = displayIterator.next();
                 if (di.mEnabled) {
                     if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
                         di.mWantsPositionSync = wantsSync;
@@ -1640,7 +1745,7 @@
         synchronized(mCacheLock) {
             final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
             while (displayIterator.hasNext()) {
-                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+                final DisplayInfoForClient di = displayIterator.next();
                 if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
                     di.mEnabled = enable;
                 }
diff --git a/media/java/android/media/routeprovider/RouteRequest.java b/media/java/android/media/routeprovider/RouteRequest.java
index 9913566..68475c0 100644
--- a/media/java/android/media/routeprovider/RouteRequest.java
+++ b/media/java/android/media/routeprovider/RouteRequest.java
@@ -20,6 +20,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.io.PrintWriter;
+
 /**
  * A request to connect or discover routes with certain capabilities.
  * <p>
@@ -70,6 +72,17 @@
     }
 
     @Override
+    public String toString() {
+        StringBuilder bob = new StringBuilder();
+        bob.append("RouteRequest {");
+        bob.append("active=").append(mActive);
+        bob.append(", info=").append(mSessionInfo.toString());
+        bob.append(", options=").append(mOptions.toString());
+        bob.append("}");
+        return bob.toString();
+    }
+
+    @Override
     public int describeContents() {
         return 0;
     }
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index ca77f04..3ff07d9 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -31,8 +31,8 @@
 interface ISession {
     void sendEvent(String event, in Bundle data);
     ISessionController getController();
-    void setTransportPerformerEnabled();
-    void publish();
+    void setFlags(int flags);
+    void setActive(boolean active);
     void destroy();
 
     // These commands are for setting up and communicating with routes
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 84b9a0f..e341647 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -15,6 +15,7 @@
 
 package android.media.session;
 
+import android.content.ComponentName;
 import android.media.session.ISession;
 import android.media.session.ISessionCallback;
 import android.os.Bundle;
@@ -24,5 +25,6 @@
  * @hide
  */
 interface ISessionManager {
-    ISession createSession(String packageName, in ISessionCallback cb, String tag);
+    ISession createSession(String packageName, in ISessionCallback cb, String tag, int userId);
+    List<IBinder> getSessions(in ComponentName compName, int userId);
 }
\ No newline at end of file
diff --git a/media/java/android/media/session/MediaMetadata.java b/media/java/android/media/session/MediaMetadata.java
index e2330f7..8a8af45 100644
--- a/media/java/android/media/session/MediaMetadata.java
+++ b/media/java/android/media/session/MediaMetadata.java
@@ -16,12 +16,15 @@
 package android.media.session;
 
 import android.graphics.Bitmap;
+import android.media.MediaMetadataEditor;
+import android.media.MediaMetadataRetriever;
 import android.media.Rating;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.SparseArray;
 
 /**
  * Contains metadata about an item, such as the title, artist, etc.
@@ -40,7 +43,8 @@
     public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
 
     /**
-     * The duration of the media in ms. A duration of 0 is the default.
+     * The duration of the media in ms. A negative duration indicates that the
+     * duration is unknown (or infinite).
      */
     public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
 
@@ -65,12 +69,17 @@
     public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
 
     /**
+     * The compilation status of the media.
+     */
+    public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
+
+    /**
      * The date the media was created or published as TODO determine format.
      */
     public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
 
     /**
-     * The year the media was created or published as a numeric String.
+     * The year the media was created or published as a long.
      */
     public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
 
@@ -151,8 +160,9 @@
         METADATA_KEYS_TYPE.put(METADATA_KEY_AUTHOR, METADATA_TYPE_STRING);
         METADATA_KEYS_TYPE.put(METADATA_KEY_WRITER, METADATA_TYPE_STRING);
         METADATA_KEYS_TYPE.put(METADATA_KEY_COMPOSER, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_COMPILATION, METADATA_TYPE_STRING);
         METADATA_KEYS_TYPE.put(METADATA_KEY_DATE, METADATA_TYPE_STRING);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_YEAR, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_YEAR, METADATA_TYPE_LONG);
         METADATA_KEYS_TYPE.put(METADATA_KEY_GENRE, METADATA_TYPE_STRING);
         METADATA_KEYS_TYPE.put(METADATA_KEY_TRACK_NUMBER, METADATA_TYPE_LONG);
         METADATA_KEYS_TYPE.put(METADATA_KEY_NUM_TRACKS, METADATA_TYPE_LONG);
@@ -165,6 +175,36 @@
         METADATA_KEYS_TYPE.put(METADATA_KEY_USER_RATING, METADATA_TYPE_RATING);
         METADATA_KEYS_TYPE.put(METADATA_KEY_RATING, METADATA_TYPE_RATING);
     }
+
+    private static final SparseArray<String> EDITOR_KEY_MAPPING;
+
+    static {
+        EDITOR_KEY_MAPPING = new SparseArray<String>();
+        EDITOR_KEY_MAPPING.put(MediaMetadataEditor.BITMAP_KEY_ARTWORK, METADATA_KEY_ART);
+        EDITOR_KEY_MAPPING.put(MediaMetadataEditor.RATING_KEY_BY_OTHERS, METADATA_KEY_RATING);
+        EDITOR_KEY_MAPPING.put(MediaMetadataEditor.RATING_KEY_BY_USER, METADATA_KEY_USER_RATING);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ALBUM, METADATA_KEY_ALBUM);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
+                METADATA_KEY_ALBUM_ARTIST);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ARTIST, METADATA_KEY_ARTIST);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_AUTHOR, METADATA_KEY_AUTHOR);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
+                METADATA_KEY_TRACK_NUMBER);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_COMPOSER, METADATA_KEY_COMPOSER);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_COMPILATION,
+                METADATA_KEY_COMPILATION);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DATE, METADATA_KEY_DATE);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
+                METADATA_KEY_DISC_NUMBER);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DURATION, METADATA_KEY_DURATION);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_GENRE, METADATA_KEY_GENRE);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS,
+                METADATA_KEY_NUM_TRACKS);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_TITLE, METADATA_KEY_TITLE);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_WRITER, METADATA_KEY_WRITER);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_YEAR, METADATA_KEY_YEAR);
+    }
+
     private final Bundle mBundle;
 
     private MediaMetadata(Bundle bundle) {
@@ -176,6 +216,16 @@
     }
 
     /**
+     * Returns true if the given key is contained in the metadata
+     *
+     * @param key a String key
+     * @return true if the key exists in this metadata, false otherwise
+     */
+    public boolean containsKey(String key) {
+        return mBundle.containsKey(key);
+    }
+
+    /**
      * Returns the value associated with the given key, or null if no mapping of
      * the desired type exists for the given key or a null value is explicitly
      * associated with the key.
@@ -195,7 +245,7 @@
      * @return a long value
      */
     public long getLong(String key) {
-        return mBundle.getLong(key);
+        return mBundle.getLong(key, 0);
     }
 
     /**
@@ -244,6 +294,27 @@
         dest.writeBundle(mBundle);
     }
 
+    /**
+     * Get the number of fields in this metadata.
+     *
+     * @return The number of fields in the metadata.
+     */
+    public int size() {
+        return mBundle.size();
+    }
+
+    /**
+     * Helper for getting the String key used by {@link MediaMetadata} from the
+     * integer key that {@link MediaMetadataEditor} uses.
+     *
+     * @param editorKey The key used by the editor
+     * @return The key used by this class or null if no mapping exists
+     * @hide
+     */
+    public static String getKeyFromMetadataEditorKey(int editorKey) {
+        return EDITOR_KEY_MAPPING.get(editorKey, null);
+    }
+
     public static final Parcelable.Creator<MediaMetadata> CREATOR
             = new Parcelable.Creator<MediaMetadata>() {
                 @Override
@@ -295,10 +366,9 @@
          * <li>{@link #METADATA_KEY_WRITER}</li>
          * <li>{@link #METADATA_KEY_COMPOSER}</li>
          * <li>{@link #METADATA_KEY_DATE}</li>
-         * <li>{@link #METADATA_KEY_YEAR}</li>
          * <li>{@link #METADATA_KEY_GENRE}</li>
-         * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>li>
-         * <li>{@link #METADATA_KEY_ART_URI}</li>li>
+         * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>
+         * <li>{@link #METADATA_KEY_ART_URI}</li>
          * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li>
          * </ul>
          *
@@ -326,6 +396,7 @@
          * <li>{@link #METADATA_KEY_TRACK_NUMBER}</li>
          * <li>{@link #METADATA_KEY_NUM_TRACKS}</li>
          * <li>{@link #METADATA_KEY_DISC_NUMBER}</li>
+         * <li>{@link #METADATA_KEY_YEAR}</li>
          * </ul>
          *
          * @param key The key for referencing this value
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
new file mode 100644
index 0000000..c07229d
--- /dev/null
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.session;
+
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.view.KeyEvent;
+
+/**
+ * Helper for connecting existing APIs up to the new session APIs. This can be
+ * used by RCC, AudioFocus, etc. to create a single session that translates to
+ * all those components.
+ *
+ * @hide
+ */
+public class MediaSessionLegacyHelper {
+    private static final String TAG = "MediaSessionHelper";
+
+    private static final Object sLock = new Object();
+    private static MediaSessionLegacyHelper sInstance;
+
+    private SessionManager mSessionManager;
+    private Handler mHandler = new Handler(Looper.getMainLooper());
+    // The legacy APIs use PendingIntents to register/unregister media button
+    // receivers and these are associated with RCC.
+    private ArrayMap<PendingIntent, SessionHolder> mSessions
+            = new ArrayMap<PendingIntent, SessionHolder>();
+
+    private MediaSessionLegacyHelper(Context context) {
+        mSessionManager = (SessionManager) context
+                .getSystemService(Context.MEDIA_SESSION_SERVICE);
+    }
+
+    public static MediaSessionLegacyHelper getHelper(Context context) {
+        synchronized (sLock) {
+            if (sInstance == null) {
+                sInstance = new MediaSessionLegacyHelper(context);
+            }
+        }
+        return sInstance;
+    }
+
+    public Session getSession(PendingIntent pi) {
+        SessionHolder holder = mSessions.get(pi);
+        return holder == null ? null : holder.mSession;
+    }
+
+    public void addRccListener(PendingIntent pi, TransportPerformer.Listener listener) {
+
+        SessionHolder holder = getHolder(pi, true);
+        TransportPerformer performer = holder.mSession.getTransportPerformer();
+        if (holder.mRccListener != null) {
+            if (holder.mRccListener == listener) {
+                // This is already the registered listener, ignore
+                return;
+            }
+            // Otherwise it changed so we need to switch to the new one
+            performer.removeListener(holder.mRccListener);
+        }
+        performer.addListener(listener, mHandler);
+        holder.mRccListener = listener;
+        holder.mFlags |= Session.FLAG_HANDLES_TRANSPORT_CONTROLS;
+        holder.mSession.setFlags(holder.mFlags);
+        holder.update();
+    }
+
+    public void removeRccListener(PendingIntent pi) {
+        SessionHolder holder = getHolder(pi, false);
+        if (holder != null && holder.mRccListener != null) {
+            holder.mSession.getTransportPerformer().removeListener(holder.mRccListener);
+            holder.mRccListener = null;
+            holder.mFlags &= ~Session.FLAG_HANDLES_TRANSPORT_CONTROLS;
+            holder.mSession.setFlags(holder.mFlags);
+            holder.update();
+        }
+    }
+
+    public void addMediaButtonListener(PendingIntent pi,
+            Context context) {
+        SessionHolder holder = getHolder(pi, true);
+        if (holder.mMediaButtonListener != null) {
+            // Already have this listener registered
+            return;
+        }
+        holder.mMediaButtonListener = new MediaButtonListener(pi, context);
+        holder.mFlags |= Session.FLAG_HANDLES_MEDIA_BUTTONS;
+        holder.mSession.setFlags(holder.mFlags);
+        holder.mSession.getTransportPerformer().addListener(holder.mMediaButtonListener, mHandler);
+    }
+
+    public void removeMediaButtonListener(PendingIntent pi) {
+        SessionHolder holder = getHolder(pi, false);
+        if (holder != null && holder.mMediaButtonListener != null) {
+            holder.mSession.getTransportPerformer().removeListener(holder.mMediaButtonListener);
+            holder.mFlags &= ~Session.FLAG_HANDLES_MEDIA_BUTTONS;
+            holder.mSession.setFlags(holder.mFlags);
+            holder.mMediaButtonListener = null;
+            holder.update();
+        }
+    }
+
+    private SessionHolder getHolder(PendingIntent pi, boolean createIfMissing) {
+        SessionHolder holder = mSessions.get(pi);
+        if (holder == null && createIfMissing) {
+            Session session = mSessionManager.createSession(TAG);
+            session.setActive(true);
+            holder = new SessionHolder(session, pi);
+            mSessions.put(pi, holder);
+        }
+        return holder;
+    }
+
+    public static class MediaButtonListener extends TransportPerformer.Listener {
+        private final PendingIntent mPendingIntent;
+        private final Context mContext;
+
+        public MediaButtonListener(PendingIntent pi, Context context) {
+            mPendingIntent = pi;
+            mContext = context;
+        }
+
+        @Override
+        public void onPlay() {
+            sendKeyEvent(KeyEvent.KEYCODE_MEDIA_PLAY);
+        }
+
+        @Override
+        public void onPause() {
+            sendKeyEvent(KeyEvent.KEYCODE_MEDIA_PAUSE);
+        }
+
+        @Override
+        public void onNext() {
+            sendKeyEvent(KeyEvent.KEYCODE_MEDIA_NEXT);
+        }
+
+        @Override
+        public void onPrevious() {
+            sendKeyEvent(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
+        }
+
+        @Override
+        public void onFastForward() {
+            sendKeyEvent(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD);
+        }
+
+        @Override
+        public void onRewind() {
+            sendKeyEvent(KeyEvent.KEYCODE_MEDIA_REWIND);
+        }
+
+        @Override
+        public void onStop() {
+            sendKeyEvent(KeyEvent.KEYCODE_MEDIA_STOP);
+        }
+
+        private void sendKeyEvent(int keyCode) {
+            KeyEvent ke = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
+            Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+
+            intent.putExtra(Intent.EXTRA_KEY_EVENT, ke);
+            try {
+                mPendingIntent.send(mContext, 0, intent);
+            } catch (CanceledException e) {
+                Log.e(TAG, "Error sending media key down event:", e);
+                // Don't bother sending up if down failed
+                return;
+            }
+
+            ke = new KeyEvent(KeyEvent.ACTION_UP, keyCode);
+            intent.putExtra(Intent.EXTRA_KEY_EVENT, ke);
+            try {
+                mPendingIntent.send(mContext, 0, intent);
+            } catch (CanceledException e) {
+                Log.e(TAG, "Error sending media key up event:", e);
+            }
+        }
+    }
+
+    private class SessionHolder {
+        public final Session mSession;
+        public final PendingIntent mPi;
+        public MediaButtonListener mMediaButtonListener;
+        public TransportPerformer.Listener mRccListener;
+        public int mFlags;
+
+        public SessionHolder(Session session, PendingIntent pi) {
+            mSession = session;
+            mPi = pi;
+        }
+
+        public void update() {
+            if (mMediaButtonListener == null && mRccListener == null) {
+                mSession.release();
+                mSessions.remove(mPi);
+            } else if (mMediaButtonListener != null && mRccListener != null) {
+                // TODO set session to active
+            } else {
+                // TODO set session to inactive
+            }
+        }
+    }
+}
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index 14d9fb1..3254e5d 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -15,8 +15,10 @@
  */
 package android.media.session;
 
+import android.media.RemoteControlClient;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.SystemClock;
 
 /**
  * Playback state for a {@link Session}. This includes a state like
@@ -88,6 +90,13 @@
     public static final long ACTION_SEEK_TO = 1 << 8;
 
     /**
+     * Indicates this performer supports the play/pause toggle command.
+     *
+     * @see #setActions
+     */
+    public static final long ACTION_PLAY_PAUSE = 1 << 9;
+
+    /**
      * This is the default playback state and indicates that no media has been
      * added yet, or the performer has been reset and has no content to play.
      *
@@ -154,12 +163,32 @@
      */
     public final static int PLAYSTATE_CONNECTING = 8;
 
+    /**
+     * State indicating the player is currently skipping to the previous item.
+     *
+     * @see #setState
+     */
+    public final static int PLAYSTATE_SKIPPING_BACKWARDS = 9;
+
+    /**
+     * State indicating the player is currently skipping to the next item.
+     *
+     * @see #setState
+     */
+    public final static int PLAYSTATE_SKIPPING_FORWARDS = 10;
+
+    /**
+     * Use this value for the position to indicate the position is not known.
+     */
+    public final static long PLAYBACK_POSITION_UNKNOWN = -1;
+
     private int mState;
     private long mPosition;
     private long mBufferPosition;
-    private float mSpeed;
-    private long mCapabilities;
+    private float mRate;
+    private long mActions;
     private String mErrorMessage;
+    private long mUpdateTime;
 
     /**
      * Create an empty PlaybackState. At minimum a state and actions should be
@@ -175,21 +204,38 @@
      * @param from The PlaybackState to duplicate
      */
     public PlaybackState(PlaybackState from) {
-        this.setState(from.getState());
-        this.setPosition(from.getPosition());
-        this.setBufferPosition(from.getBufferPosition());
-        this.setSpeed(from.getSpeed());
-        this.setActions(from.getActions());
-        this.setErrorMessage(from.getErrorMessage());
+        mState = from.mState;
+        mPosition = from.mPosition;
+        mRate = from.mRate;
+        mUpdateTime = from.mUpdateTime;
+        mBufferPosition = from.mBufferPosition;
+        mActions = from.mActions;
+        mErrorMessage = from.mErrorMessage;
     }
 
     private PlaybackState(Parcel in) {
-        this.setState(in.readInt());
-        this.setPosition(in.readLong());
-        this.setBufferPosition(in.readLong());
-        this.setSpeed(in.readFloat());
-        this.setActions(in.readLong());
-        this.setErrorMessage(in.readString());
+        mState = in.readInt();
+        mPosition = in.readLong();
+        mRate = in.readFloat();
+        mUpdateTime = in.readLong();
+        mBufferPosition = in.readLong();
+        mActions = in.readLong();
+        mErrorMessage = in.readString();
+
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder bob = new StringBuilder("PlaybackState {");
+        bob.append("state=").append(mState);
+        bob.append(", position=").append(mPosition);
+        bob.append(", buffered position=").append(mBufferPosition);
+        bob.append(", rate=").append(mRate);
+        bob.append(", updated=").append(mUpdateTime);
+        bob.append(", actions=").append(mActions);
+        bob.append(", error=").append(mErrorMessage);
+        bob.append("}");
+        return bob.toString();
     }
 
     @Override
@@ -199,12 +245,13 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(getState());
-        dest.writeLong(getPosition());
-        dest.writeLong(getBufferPosition());
-        dest.writeFloat(getSpeed());
-        dest.writeLong(getActions());
-        dest.writeString(getErrorMessage());
+        dest.writeInt(mState);
+        dest.writeLong(mPosition);
+        dest.writeFloat(mRate);
+        dest.writeLong(mUpdateTime);
+        dest.writeLong(mBufferPosition);
+        dest.writeLong(mActions);
+        dest.writeString(mErrorMessage);
     }
 
     /**
@@ -224,7 +271,16 @@
     }
 
     /**
-     * Set the current state of playback. One of the following:
+     * Set the current state of playback.
+     * <p>
+     * The position must be in ms and indicates the current playback position
+     * within the track. If the position is unknown use
+     * {@link #PLAYBACK_POSITION_UNKNOWN}.
+     * <p>
+     * The rate is a multiple of normal playback and should be 0 when paused and
+     * negative when rewinding. Normal playback rate is 1.0.
+     * <p>
+     * The state must be one of the following:
      * <ul>
      * <li> {@link PlaybackState#PLAYSTATE_NONE}</li>
      * <li> {@link PlaybackState#PLAYSTATE_STOPPED}</li>
@@ -234,9 +290,18 @@
      * <li> {@link PlaybackState#PLAYSTATE_REWINDING}</li>
      * <li> {@link PlaybackState#PLAYSTATE_BUFFERING}</li>
      * <li> {@link PlaybackState#PLAYSTATE_ERROR}</li>
+     * </ul>
+     *
+     * @param state The current state of playback.
+     * @param position The position in the current track in ms.
+     * @param rate The current rate of playback as a multiple of normal
+     *            playback.
      */
-    public void setState(int mState) {
-        this.mState = mState;
+    public void setState(int state, long position, float rate) {
+        this.mState = state;
+        this.mPosition = position;
+        this.mRate = rate;
+        mUpdateTime = SystemClock.elapsedRealtime();
     }
 
     /**
@@ -247,13 +312,6 @@
     }
 
     /**
-     * Set the current playback position in ms.
-     */
-    public void setPosition(long position) {
-        mPosition = position;
-    }
-
-    /**
      * Get the current buffer position in ms. This is the farthest playback
      * point that can be reached from the current position using only buffered
      * content.
@@ -272,21 +330,14 @@
     }
 
     /**
-     * Get the current playback speed as a multiple of normal playback. This
+     * Get the current playback rate as a multiple of normal playback. This
      * should be negative when rewinding. A value of 1 means normal playback and
      * 0 means paused.
+     *
+     * @return The current rate of playback.
      */
-    public float getSpeed() {
-        return mSpeed;
-    }
-
-    /**
-     * Set the current playback speed as a multiple of normal playback. This
-     * should be negative when rewinding. A value of 1 means normal playback and
-     * 0 means paused.
-     */
-    public void setSpeed(float speed) {
-        mSpeed = speed;
+    public float getRate() {
+        return mRate;
     }
 
     /**
@@ -305,7 +356,7 @@
      * </ul>
      */
     public long getActions() {
-        return mCapabilities;
+        return mActions;
     }
 
     /**
@@ -324,7 +375,7 @@
      * </ul>
      */
     public void setActions(long capabilities) {
-        mCapabilities = capabilities;
+        mActions = capabilities;
     }
 
     /**
@@ -336,6 +387,17 @@
     }
 
     /**
+     * Get the elapsed real time at which position was last updated. If the
+     * position has never been set this will return 0;
+     *
+     * @return The last time the position was updated.
+     * @hide
+     */
+    public long getLastPositionUpdateTime() {
+        return mUpdateTime;
+    }
+
+    /**
      * Set a user readable error message. This should be set when the state is
      * {@link PlaybackState#PLAYSTATE_ERROR}.
      */
@@ -343,6 +405,80 @@
         mErrorMessage = errorMessage;
     }
 
+    /**
+     * Get the {@link PlaybackState} state for the given
+     * {@link RemoteControlClient} state.
+     *
+     * @param rccState The state used by {@link RemoteControlClient}.
+     * @return The equivalent state used by {@link PlaybackState}.
+     * @hide
+     */
+    public static int getStateFromRccState(int rccState) {
+        switch (rccState) {
+            case RemoteControlClient.PLAYSTATE_BUFFERING:
+                return PLAYSTATE_BUFFERING;
+            case RemoteControlClient.PLAYSTATE_ERROR:
+                return PLAYSTATE_ERROR;
+            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
+                return PLAYSTATE_FAST_FORWARDING;
+            case RemoteControlClient.PLAYSTATE_NONE:
+                return PLAYSTATE_NONE;
+            case RemoteControlClient.PLAYSTATE_PAUSED:
+                return PLAYSTATE_PAUSED;
+            case RemoteControlClient.PLAYSTATE_PLAYING:
+                return PLAYSTATE_PLAYING;
+            case RemoteControlClient.PLAYSTATE_REWINDING:
+                return PLAYSTATE_REWINDING;
+            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
+                return PLAYSTATE_SKIPPING_BACKWARDS;
+            case RemoteControlClient.PLAYSTATE_STOPPED:
+                return PLAYSTATE_STOPPED;
+            default:
+                return -1;
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public static long getActionsFromRccControlFlags(int rccFlags) {
+        long actions = 0;
+        long flag = 1;
+        while (flag <= rccFlags) {
+            if ((flag & rccFlags) != 0) {
+                actions |= getActionForRccFlag((int) flag);
+            }
+            flag = flag << 1;
+        }
+        return actions;
+    }
+
+    private static long getActionForRccFlag(int flag) {
+        switch (flag) {
+            case RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS:
+                return ACTION_PREVIOUS_ITEM;
+            case RemoteControlClient.FLAG_KEY_MEDIA_REWIND:
+                return ACTION_REWIND;
+            case RemoteControlClient.FLAG_KEY_MEDIA_PLAY:
+                return ACTION_PLAY;
+            case RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE:
+                return ACTION_PLAY_PAUSE;
+            case RemoteControlClient.FLAG_KEY_MEDIA_PAUSE:
+                return ACTION_PAUSE;
+            case RemoteControlClient.FLAG_KEY_MEDIA_STOP:
+                return ACTION_STOP;
+            case RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD:
+                return ACTION_FASTFORWARD;
+            case RemoteControlClient.FLAG_KEY_MEDIA_NEXT:
+                return ACTION_NEXT_ITEM;
+            case RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE:
+                return ACTION_SEEK_TO;
+            case RemoteControlClient.FLAG_KEY_MEDIA_RATING:
+                return ACTION_RATING;
+        }
+        return 0;
+    }
+
     public static final Parcelable.Creator<PlaybackState> CREATOR
             = new Parcelable.Creator<PlaybackState>() {
         @Override
diff --git a/media/java/android/media/session/Session.java b/media/java/android/media/session/Session.java
index 8ccd788..194679e7 100644
--- a/media/java/android/media/session/Session.java
+++ b/media/java/android/media/session/Session.java
@@ -45,12 +45,13 @@
  * media to multiple routes or to provide finer grain controls of media.
  * <p>
  * A MediaSession is created by calling
- * {@link SessionManager#createSession(String)}. Once a session is created
- * apps that have the MEDIA_CONTENT_CONTROL permission can interact with the
- * session through {@link SessionManager#getActiveSessions()}. The owner of
- * the session may also use {@link #getSessionToken()} to allow apps without
- * this permission to create a {@link SessionController} to interact with this
- * session.
+ * {@link SessionManager#createSession(String)}. Once a session is created apps
+ * that have the MEDIA_CONTENT_CONTROL permission can interact with the session
+ * through
+ * {@link SessionManager#getActiveSessions(android.content.ComponentName)}. The
+ * owner of the session may also use {@link #getSessionToken()} to allow apps
+ * without this permission to create a {@link SessionController} to interact
+ * with this session.
  * <p>
  * To receive commands, media keys, and other events a Callback must be set with
  * {@link #addCallback(Callback)}.
@@ -63,6 +64,28 @@
 public final class Session {
     private static final String TAG = "Session";
 
+    /**
+     * Set this flag on the session to indicate that it can handle media button
+     * events.
+     */
+    public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1 << 0;
+
+    /**
+     * Set this flag on the session to indicate that it handles commands through
+     * the {@link TransportPerformer}. The performer can be retrieved by calling
+     * {@link #getTransportPerformer()}.
+     */
+    public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;
+
+    /**
+     * System only flag for a session that needs to have priority over all other
+     * sessions. This flag ensures this session will receive media button events
+     * regardless of the current ordering in the system.
+     *
+     * @hide
+     */
+    public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 1 << 16;
+
     private static final int MSG_MEDIA_BUTTON = 1;
     private static final int MSG_COMMAND = 2;
     private static final int MSG_ROUTE_CHANGE = 3;
@@ -86,7 +109,7 @@
     private TransportPerformer mPerformer;
     private Route mRoute;
 
-    private boolean mPublished = false;;
+    private boolean mActive = false;;
 
     /**
      * @hide
@@ -101,6 +124,7 @@
             throw new RuntimeException("Dead object in MediaSessionController constructor: ", e);
         }
         mSessionToken = new SessionToken(controllerBinder);
+        mPerformer = new TransportPerformer(mBinder);
     }
 
     /**
@@ -148,56 +172,57 @@
     }
 
     /**
-     * Start using a TransportPerformer with this media session. This must be
-     * called before calling publish and cannot be called more than once.
-     * Calling this will allow MediaControllers to retrieve a
-     * TransportController.
+     * Retrieves the {@link TransportPerformer} for this session. To receive
+     * commands through the performer you must also set the
+     * {@link #FLAG_HANDLES_TRANSPORT_CONTROLS} flag using
+     * {@link #setFlags(int)}.
      *
-     * @see TransportController
-     * @return The TransportPerformer created for this session
-     */
-    public TransportPerformer setTransportPerformerEnabled() {
-        if (mPerformer != null) {
-            throw new IllegalStateException("setTransportPerformer can only be called once.");
-        }
-        if (mPublished) {
-            throw new IllegalStateException("setTransportPerformer cannot be called after publish");
-        }
-
-        mPerformer = new TransportPerformer(mBinder);
-        try {
-            mBinder.setTransportPerformerEnabled();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setTransportPerformerEnabled.", e);
-        }
-        return mPerformer;
-    }
-
-    /**
-     * Retrieves the TransportPerformer used by this session. If called before
-     * {@link #setTransportPerformerEnabled} null will be returned.
-     *
-     * @return The TransportPerformer associated with this session or null
+     * @return The performer associated with this session.
      */
     public TransportPerformer getTransportPerformer() {
         return mPerformer;
     }
 
     /**
-     * Call after you have finished setting up the session. This will make it
-     * available to listeners and begin pushing updates to MediaControllers.
-     * This can only be called once.
+     * Set any flags for the session.
+     *
+     * @param flags The flags to set for this session.
      */
-    public void publish() {
-        if (mPublished) {
-            throw new RuntimeException("publish() may only be called once.");
+    public void setFlags(int flags) {
+        try {
+            mBinder.setFlags(flags);
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Failure in setFlags.", e);
+        }
+    }
+
+    /**
+     * Set if this session is currently active and ready to receive commands. If
+     * set to false your session's controller may not be discoverable. You must
+     * set the session to active before it can start receiving media button
+     * events or transport commands.
+     *
+     * @param active Whether this session is active or not.
+     */
+    public void setActive(boolean active) {
+        if (mActive == active) {
+            return;
         }
         try {
-            mBinder.publish();
+            mBinder.setActive(active);
+            mActive = active;
         } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in publish.", e);
+            Log.wtf(TAG, "Failure in setActive.", e);
         }
-        mPublished = true;
+    }
+
+    /**
+     * Get the current active state of this session.
+     *
+     * @return True if the session is active, false otherwise.
+     */
+    public boolean isActive() {
+        return mActive;
     }
 
     /**
diff --git a/media/java/android/media/session/SessionInfo.java b/media/java/android/media/session/SessionInfo.java
index 22d8ab1..2b65528 100644
--- a/media/java/android/media/session/SessionInfo.java
+++ b/media/java/android/media/session/SessionInfo.java
@@ -57,6 +57,11 @@
     }
 
     @Override
+    public String toString() {
+        return "SessionInfo {id=" + mId + ", pkg=" + mPackageName + "}";
+    }
+
+    @Override
     public int describeContents() {
         return 0;
     }
diff --git a/media/java/android/media/session/SessionManager.java b/media/java/android/media/session/SessionManager.java
index 15bf0e3..1eb3b7a 100644
--- a/media/java/android/media/session/SessionManager.java
+++ b/media/java/android/media/session/SessionManager.java
@@ -16,11 +16,14 @@
 
 package android.media.session;
 
+import android.content.ComponentName;
 import android.content.Context;
 import android.media.session.ISessionManager;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.service.notification.NotificationListenerService;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -63,10 +66,25 @@
      * @return a {@link Session} for the new session
      */
     public Session createSession(String tag) {
+        return createSessionAsUser(tag, UserHandle.myUserId());
+    }
+
+    /**
+     * Creates a new session as the specified user. To create a session as a
+     * user other than your own you must hold the
+     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}
+     * permission.
+     *
+     * @param tag A short name for debugging purposes
+     * @param userId The user id to create the session as.
+     * @return a {@link Session} for the new session
+     * @hide
+     */
+    public Session createSessionAsUser(String tag, int userId) {
         try {
             Session.CallbackStub cbStub = new Session.CallbackStub();
             Session session = new Session(mService
-                    .createSession(mContext.getPackageName(), cbStub, tag), cbStub);
+                    .createSession(mContext.getPackageName(), cbStub, tag, userId), cbStub);
             cbStub.setMediaSession(session);
 
             return session;
@@ -79,12 +97,45 @@
     /**
      * Get a list of controllers for all ongoing sessions. This requires the
      * android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by
-     * the calling app.
+     * the calling app. You may also retrieve this list if your app is an
+     * enabled notification listener using the
+     * {@link NotificationListenerService} APIs, in which case you must pass the
+     * {@link ComponentName} of your enabled listener.
      *
-     * @return a list of controllers for ongoing sessions
+     * @param notificationListener The enabled notification listener component.
+     *            May be null.
+     * @return A list of controllers for ongoing sessions
      */
-    public List<SessionController> getActiveSessions() {
-        // TODO
-        return new ArrayList<SessionController>();
+    public List<SessionController> getActiveSessions(ComponentName notificationListener) {
+        return getActiveSessionsForUser(notificationListener, UserHandle.myUserId());
+    }
+
+    /**
+     * Get active sessions for a specific user. To retrieve actions for a user
+     * other than your own you must hold the
+     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission
+     * in addition to any other requirements. If you are an enabled notification
+     * listener you may only get sessions for the users you are enabled for.
+     *
+     * @param notificationListener The enabled notification listener component.
+     *            May be null.
+     * @param userId The user id to fetch sessions for.
+     * @return A list of controllers for ongoing sessions.
+     * @hide
+     */
+    public List<SessionController> getActiveSessionsForUser(ComponentName notificationListener,
+            int userId) {
+        ArrayList<SessionController> controllers = new ArrayList<SessionController>();
+        try {
+            List<IBinder> binders = mService.getSessions(notificationListener, userId);
+            for (int i = binders.size() - 1; i >= 0; i--) {
+                SessionController controller = SessionController.fromBinder(ISessionController.Stub
+                        .asInterface(binders.get(i)));
+                controllers.add(controller);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to get active sessions: ", e);
+        }
+        return controllers;
     }
 }
diff --git a/media/java/android/media/session/TransportPerformer.java b/media/java/android/media/session/TransportPerformer.java
index eddffd1..187f48d 100644
--- a/media/java/android/media/session/TransportPerformer.java
+++ b/media/java/android/media/session/TransportPerformer.java
@@ -280,18 +280,11 @@
         /**
          * Report that audio focus has changed on the app. This only happens if
          * you have indicated you have started playing with
-         * {@link #setPlaybackState}. TODO figure out route focus apis/handling.
+         * {@link #setPlaybackState}.
          *
-         * @param focusChange The type of focus change, TBD. The default
-         *            implementation will deliver a call to {@link #onPause}
-         *            when focus is lost.
+         * @param focusChange The type of focus change, TBD.
          */
         public void onRouteFocusChange(int focusChange) {
-            switch (focusChange) {
-                case AudioManager.AUDIOFOCUS_LOSS:
-                    onPause();
-                    break;
-            }
         }
     }
 
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index ed98b96..90fe695 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -66,8 +66,6 @@
 
 LOCAL_CFLAGS +=
 
-LOCAL_LDLIBS := -lpthread
-
 LOCAL_MODULE:= libmedia_jni
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index d04b1f8..4a7c096 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -255,12 +255,16 @@
             env, env->FindClass("android/media/MediaCodec$BufferInfo"));
 
     jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
-    env->CallVoidMethod(bufferInfo, method, offset, size, timeUs, flags);
+    env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags);
 
     return OK;
 }
 
-status_t JMediaCodec::releaseOutputBuffer(size_t index, bool render) {
+status_t JMediaCodec::releaseOutputBuffer(
+        size_t index, bool render, bool updatePTS, int64_t timestampNs) {
+    if (updatePTS) {
+        return mCodec->renderOutputBufferAndRelease(index, timestampNs);
+    }
     return render
         ? mCodec->renderOutputBufferAndRelease(index)
         : mCodec->releaseOutputBuffer(index);
@@ -873,7 +877,8 @@
 }
 
 static void android_media_MediaCodec_releaseOutputBuffer(
-        JNIEnv *env, jobject thiz, jint index, jboolean render) {
+        JNIEnv *env, jobject thiz,
+        jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
     ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
 
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
@@ -883,7 +888,7 @@
         return;
     }
 
-    status_t err = codec->releaseOutputBuffer(index, render);
+    status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
 
     throwExceptionAsNecessary(env, err);
 }
@@ -1138,7 +1143,7 @@
     { "dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
       (void *)android_media_MediaCodec_dequeueOutputBuffer },
 
-    { "releaseOutputBuffer", "(IZ)V",
+    { "releaseOutputBuffer", "(IZZJ)V",
       (void *)android_media_MediaCodec_releaseOutputBuffer },
 
     { "signalEndOfInputStream", "()V",
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 2f2ea96..bf9f4ea 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -79,7 +79,8 @@
     status_t dequeueOutputBuffer(
             JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs);
 
-    status_t releaseOutputBuffer(size_t index, bool render);
+    status_t releaseOutputBuffer(
+            size_t index, bool render, bool updatePTS, int64_t timestampNs);
 
     status_t signalEndOfInputStream();
 
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 4e42ae3..157dd49 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -273,6 +273,13 @@
                             width,
                             height,
                             config);
+    if (jBitmap == NULL) {
+        if (env->ExceptionCheck()) {
+            env->ExceptionClear();
+        }
+        ALOGE("getFrameAtTime: create Bitmap failed!");
+        return NULL;
+    }
 
     SkBitmap *bitmap =
             (SkBitmap *) env->GetLongField(jBitmap, fields.nativeBitmap);
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index abebd48..6f42057 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -648,7 +648,7 @@
         return;
     }
 
-    clazz = env->FindClass("android/net/ProxyProperties");
+    clazz = env->FindClass("android/net/ProxyInfo");
     if (clazz == NULL) {
         return;
     }
@@ -660,7 +660,7 @@
         env->GetMethodID(clazz, "getPort", "()I");
 
     fields.proxyConfigGetExclusionList =
-        env->GetMethodID(clazz, "getExclusionList", "()Ljava/lang/String;");
+        env->GetMethodID(clazz, "getExclusionListAsString", "()Ljava/lang/String;");
 }
 
 static void
diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk
index 1e6b2e7..42da48d 100644
--- a/media/tests/MediaFrameworkTest/Android.mk
+++ b/media/tests/MediaFrameworkTest/Android.mk
@@ -7,7 +7,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_STATIC_JAVA_LIBRARIES := easymocklib mockito-target
+LOCAL_STATIC_JAVA_LIBRARIES := easymocklib mockito-target core-tests android-support-test
 
 LOCAL_PACKAGE_NAME := mediaframeworktest
 
diff --git a/media/tests/MediaFrameworkTest/AndroidManifest.xml b/media/tests/MediaFrameworkTest/AndroidManifest.xml
index 91ee2c6..c62199f 100644
--- a/media/tests/MediaFrameworkTest/AndroidManifest.xml
+++ b/media/tests/MediaFrameworkTest/AndroidManifest.xml
@@ -76,4 +76,8 @@
          android:label="MediaFramework integration tests InstrumentationRunner">
      </instrumentation>
 
+     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+         android:targetPackage="com.android.mediaframeworktest"
+         android:label="media framework tests"/>
+
 </manifest>
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
index 64b12b7..11d9070 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
@@ -63,6 +63,7 @@
         suite.addTestSuite(CameraUtilsRuntimeExceptionTest.class);
         suite.addTestSuite(CameraUtilsUncheckedThrowTest.class);
         suite.addTestSuite(CameraUtilsBinderDecoratorTest.class);
+        suite.addTestSuite(CameraUtilsTypeReferenceTest.class);
         suite.addTestSuite(CameraMetadataTest.class);
     }
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ByteArrayHelpers.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ByteArrayHelpers.java
new file mode 100644
index 0000000..6f31480
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ByteArrayHelpers.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.mediaframeworktest.unit;
+
+import android.util.Log;
+
+import java.lang.reflect.Array;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+
+public class ByteArrayHelpers {
+
+    private static final String TAG = "ByteArrayHelpers";
+    private static boolean VERBOSE = false;
+
+    /**
+     * Convert an array of byte primitives to a {@code byte[]} using native endian order.
+     *
+     * <p>This function is a pass-through; it's here only to provide overloads for
+     * every single type of primitive arrays.
+     *
+     * @param array array of primitives
+     * @return array
+     */
+    public static byte[] toByteArray(byte[] array) {
+        return array;
+    }
+
+    /**
+     * Convert an array of shorts to a {@code byte[]} using native endian order.
+     *
+     * @param array array of shorts
+     * @return array converted into byte array using native endian order
+     */
+    public static byte[] toByteArray(short[] array) {
+        return toByteArray(array, Short.SIZE);
+    }
+
+    /**
+     * Convert an array of chars to a {@code byte[]} using native endian order.
+     *
+     * @param array array of chars
+     * @return array converted into byte array using native endian order
+     */
+    public static byte[] toByteArray(char[] array) {
+        return toByteArray(array, Character.SIZE);
+    }
+    /**
+     * Convert an array of ints to a {@code byte[]} using native endian order.
+     *
+     * @param array array of ints
+     * @return array converted into byte array using native endian order
+     */
+    public static byte[] toByteArray(int[] array) {
+        return toByteArray(array, Integer.SIZE);
+    }
+    /**
+     * Convert an array of longs to a {@code byte[]} using native endian order.
+     *
+     * @param array array of longs
+     * @return array converted into byte array using native endian order
+     */
+    public static byte[] toByteArray(long[] array) {
+        return toByteArray(array, Long.SIZE);
+    }
+    /**
+     * Convert an array of floats to a {@code byte[]} using native endian order.
+     *
+     * @param array array of floats
+     * @return array converted into byte array using native endian order
+     */
+    public static byte[] toByteArray(float[] array) {
+        return toByteArray(array, Float.SIZE);
+    }
+    /**
+     * Convert an array of doubles to a {@code byte[]} using native endian order.
+     *
+     * @param array array of doubles
+     * @return array converted into byte array using native endian order
+     */
+    public static byte[] toByteArray(double[] array) {
+        return toByteArray(array, Double.SIZE);
+    }
+
+    /**
+     * Convert an array of primitives to a {@code byte[]} using native endian order.
+     *
+     * <p>Arguments other than arrays are not supported. The array component must be primitive,
+     * the wrapper class is not allowed (e.g. {@code int[]} is ok, but {@code Integer[]} is not.</p>
+     *
+     * @param array array of primitives
+     * @return array converted into byte array using native endian order
+     *
+     * @throws IllegalArgumentException if {@code array} was not an array of primitives
+     */
+    public static <T> byte[] toByteArray(T array) {
+        @SuppressWarnings("unchecked")
+        Class<T> klass = (Class<T>) array.getClass();
+
+        if (!klass.isArray()) {
+            throw new IllegalArgumentException("array class must be an array");
+        }
+
+        Class<?> componentClass = klass.getComponentType();
+
+        if (!componentClass.isPrimitive()) {
+            throw new IllegalArgumentException("array's component must be a primitive");
+        }
+
+        int sizeInBits;
+        if (klass == int.class) {
+            sizeInBits = Integer.SIZE;
+        } else if (klass == float.class) {
+            sizeInBits = Float.SIZE;
+        } else if (klass == double.class) {
+            sizeInBits = Double.SIZE;
+        } else if (klass == short.class) {
+            sizeInBits = Short.SIZE;
+        } else if (klass == char.class) {
+            sizeInBits = Character.SIZE;
+        } else if (klass == long.class) {
+            sizeInBits = Long.SIZE;
+        } else if (klass == byte.class) {
+            sizeInBits = Byte.SIZE;
+        } else {
+            throw new AssertionError();
+        }
+
+        return toByteArray(array, sizeInBits);
+    }
+
+    /**
+     * Convert a variadic list of {@code Number}s into a byte array using native endian order.
+     *
+     * <p>Each {@link Number} must be an instance of a primitive wrapper class
+     * (e.g. {@link Integer} is OK, since it wraps {@code int}, but {@code BigInteger} is not.</p>
+     *
+     * @param numbers variadic list of numeric values
+     * @return array converted into byte array using native endian order
+     *
+     * @throws IllegalArgumentException
+     *          if {@code numbers} contained a class that wasn't a primitive wrapper
+     */
+    public static byte[] toByteArray(Number... numbers) {
+        if (numbers.length == 0) {
+            throw new IllegalArgumentException("too few numbers");
+        }
+
+        if (VERBOSE) Log.v(TAG, "toByteArray - input: " + Arrays.toString(numbers));
+
+        // Have a large enough capacity to fit in every number as a double
+        ByteBuffer byteBuffer = ByteBuffer.allocate(numbers.length * (Double.SIZE / Byte.SIZE))
+                .order(ByteOrder.nativeOrder());
+
+        for (int i = 0; i < numbers.length; ++i) {
+            Number value = numbers[i];
+            Class<? extends Number> klass = value.getClass();
+
+            if (VERBOSE) Log.v(TAG, "toByteArray - number " + i + ", class " + klass);
+
+            if (klass == Integer.class) {
+                byteBuffer.putInt((Integer)value);
+            } else if (klass == Float.class) {
+                byteBuffer.putFloat((Float)value);
+            } else if (klass == Double.class) {
+                byteBuffer.putDouble((Double)value);
+            } else if (klass == Short.class) {
+                byteBuffer.putShort((Short)value);
+            } else if (klass == Long.class) {
+                byteBuffer.putLong((Long)value);
+            } else if (klass == Byte.class) {
+                byteBuffer.put((Byte)value);
+            } else {
+                throw new IllegalArgumentException(
+                        "number class invalid; must be wrapper around primitive class");
+            }
+        }
+
+        if (VERBOSE) Log.v(TAG, "toByteArray - end of loop");
+
+        // Each number written is at least 1 byte, so the position should be at least length
+        if (numbers.length != 0 && byteBuffer.position() < numbers.length) {
+            throw new AssertionError(String.format(
+                    "Had %d numbers, but byte buffer position was only %d",
+                    numbers.length, byteBuffer.position()));
+        }
+
+        byteBuffer.flip();
+
+        byte[] bytes = new byte[byteBuffer.limit()];
+        byteBuffer.get(bytes);
+
+        if (VERBOSE) Log.v(TAG, "toByteArray - output: " + Arrays.toString(bytes));
+
+        return bytes;
+    }
+
+    private static <T> byte[] toByteArray(T array, int sizeOfTBits) {
+        @SuppressWarnings("unchecked")
+        Class<T> klass = (Class<T>) array.getClass();
+
+        if (!klass.isArray()) {
+            throw new IllegalArgumentException("array class must be an array");
+        }
+
+        int sizeOfT = sizeOfTBits / Byte.SIZE;
+        int byteLength = Array.getLength(array) * sizeOfT;
+
+        if (klass == byte[].class) {
+            // Always return a copy
+            return Arrays.copyOf((byte[])array, byteLength);
+        }
+
+        ByteBuffer byteBuffer = ByteBuffer.allocate(byteLength).order(ByteOrder.nativeOrder());
+
+        if (klass == int[].class) {
+            byteBuffer.asIntBuffer().put((int[])array);
+        } else if (klass == float[].class) {
+            byteBuffer.asFloatBuffer().put((float[])array);
+        } else if (klass == double[].class) {
+            byteBuffer.asDoubleBuffer().put((double[])array);
+        } else if (klass == short[].class) {
+            byteBuffer.asShortBuffer().put((short[])array);
+        } else if (klass == char[].class) {
+            byteBuffer.asCharBuffer().put((char[])array);
+        } else if (klass == long[].class) {
+            byteBuffer.asLongBuffer().put((long[])array);
+        } else {
+            throw new IllegalArgumentException("array class invalid; must be a primitive array");
+        }
+
+        return byteBuffer.array();
+    }
+
+    private ByteArrayHelpers() {
+        throw new AssertionError();
+    }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index 45df065..b28733a 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -16,18 +16,30 @@
 
 package com.android.mediaframeworktest.unit;
 
-import android.os.Parcel;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Range;
+import android.util.SizeF;
+import android.graphics.ImageFormat;
 import android.graphics.Point;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.ColorSpaceTransform;
 import android.hardware.camera2.Face;
+import android.hardware.camera2.MeteringRectangle;
 import android.hardware.camera2.Rational;
+import android.hardware.camera2.ReprocessFormatsMap;
+import android.hardware.camera2.RggbChannelVector;
 import android.hardware.camera2.Size;
+import android.hardware.camera2.StreamConfiguration;
+import android.hardware.camera2.StreamConfigurationDuration;
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
+import android.hardware.camera2.utils.TypeReference;
 
 import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static com.android.mediaframeworktest.unit.ByteArrayHelpers.*;
 
 import java.lang.reflect.Array;
 import java.nio.ByteBuffer;
@@ -43,7 +55,6 @@
 public class CameraMetadataTest extends junit.framework.TestCase {
 
     CameraMetadataNative mMetadata;
-    Parcel mParcel;
 
     // Sections
     static final int ANDROID_COLOR_CORRECTION = 0;
@@ -64,15 +75,11 @@
     @Override
     public void setUp() {
         mMetadata = new CameraMetadataNative();
-        mParcel = Parcel.obtain();
     }
 
     @Override
     public void tearDown() throws Exception {
         mMetadata = null;
-
-        mParcel.recycle();
-        mParcel = null;
     }
 
     @SmallTest
@@ -130,10 +137,14 @@
 
     @SmallTest
     public void testGetTypeFromTag() {
-        assertEquals(TYPE_BYTE, CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_MODE));
-        assertEquals(TYPE_RATIONAL, CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_TRANSFORM));
-        assertEquals(TYPE_FLOAT, CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_GAINS));
-        assertEquals(TYPE_BYTE, CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_ANTIBANDING_MODE));
+        assertEquals(TYPE_BYTE,
+                CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_MODE));
+        assertEquals(TYPE_RATIONAL,
+                CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_TRANSFORM));
+        assertEquals(TYPE_FLOAT,
+                CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_GAINS));
+        assertEquals(TYPE_BYTE,
+                CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_ANTIBANDING_MODE));
         assertEquals(TYPE_INT32,
                 CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION));
 
@@ -215,35 +226,163 @@
         assertEquals(1, mMetadata.getEntryCount());
     }
 
+    /**
+     * Format an array into a string with the {@code badIndex} highlighted with {@code **}.
+     *
+     * <p>Numbers are printed as hexadecimal values.</p>
+     *
+     * <p>Example: {@code "[hello, **world**]"} for a {@code string[]},
+     * or a {@code "[**0xFF**, 0xFF]"} for a {@code int[]}.</p>
+     */
+    private static <T> String formatArray(T array, int badIndex) {
+        StringBuilder builder = new StringBuilder();
+
+        builder.append("[");
+
+        int len = Array.getLength(array);
+        for (int i = 0; i < len; ++i) {
+
+            Object elem = Array.get(array, i);
+
+            if (i == badIndex) {
+                builder.append("**");
+            }
+
+            if (elem instanceof Number) {
+                builder.append(String.format("%x", elem));
+            } else {
+                builder.append(elem);
+            }
+
+            if (i == badIndex) {
+                builder.append("**");
+            }
+
+            if (i != len - 1) {
+                builder.append(", ");
+            }
+        }
+
+        builder.append("]");
+
+        return builder.toString();
+    }
+
     private static <T> void assertArrayEquals(T expected, T actual) {
-        assertEquals(Array.getLength(expected), Array.getLength(actual));
+        if (!expected.getClass().isArray() || !actual.getClass().isArray()) {
+            throw new IllegalArgumentException("expected, actual must both be arrays");
+        }
+
+        assertEquals("Array lengths must be equal",
+                Array.getLength(expected), Array.getLength(actual));
 
         int len = Array.getLength(expected);
         for (int i = 0; i < len; ++i) {
-            assertEquals(Array.get(expected, i), Array.get(actual, i));
+
+            Object expectedElement = Array.get(expected, i);
+            Object actualElement = Array.get(actual, i);
+
+            if (!expectedElement.equals(actualElement)) {
+                fail(String.format(
+                        "element %d in array was not equal (expected %s, actual %s). "
+                                + "Arrays were: (expected %s, actual %s).",
+                                i, expectedElement, actualElement,
+                                formatArray(expected, i),
+                                formatArray(actual, i)));
+            }
         }
     }
 
-    private <T> void checkKeyGetAndSet(String keyStr, Class<T> type, T value) {
-        assertFalse("Use checkKeyGetAndSetArray to compare array Keys", type.isArray());
-
-        Key<T> key = new Key<T>(keyStr, type);
+    private <T> void checkKeyGetAndSet(String keyStr, TypeReference<T> typeToken, T expected,
+            boolean reuse) {
+        Key<T> key = new Key<T>(keyStr, typeToken);
         assertNull(mMetadata.get(key));
         mMetadata.set(key, null);
         assertNull(mMetadata.get(key));
-        mMetadata.set(key, value);
+        mMetadata.set(key, expected);
 
         T actual = mMetadata.get(key);
-        assertEquals(value, actual);
+
+        if (typeToken.getRawType().isArray()) {
+            assertArrayEquals(expected, actual);
+        } else {
+            assertEquals(expected, actual);
+        }
+
+        if (reuse) {
+            // reset the key incase we want to use it again
+            mMetadata.set(key, null);
+        }
     }
 
-    private <T> void checkKeyGetAndSetArray(String keyStr, Class<T> type, T value) {
-        assertTrue(type.isArray());
+    private <T> void checkKeyGetAndSet(String keyStr, TypeReference<T> typeToken, T expected) {
+        checkKeyGetAndSet(keyStr, typeToken, expected, /*reuse*/false);
+    }
 
-        Key<T> key = new Key<T>(keyStr, type);
+    private <T> void checkKeyGetAndSet(String keyStr, Class<T> type, T expected) {
+        checkKeyGetAndSet(keyStr, TypeReference.createSpecializedTypeReference(type), expected);
+    }
+
+    /**
+     * Ensure that the data survives a marshal/unmarshal round-trip;
+     * it must also be equal to the {@code expectedNative} byte array.
+     *
+     * <p>As a side-effect, the metadata value corresponding to the key is now set to
+     * {@code expected}.</p>
+     *
+     * @return key created with {@code keyName} and {@code T}
+     */
+    private <T> Key<T> checkKeyMarshal(String keyName, TypeReference<T> typeReference,
+            T expected, byte[] expectedNative) {
+        Key<T> key = new Key<T>(keyName, typeReference);
+
+        mMetadata.set(key, null);
         assertNull(mMetadata.get(key));
-        mMetadata.set(key, value);
-        assertArrayEquals(value, mMetadata.get(key));
+
+        // Write managed value -> make sure native bytes are what we expect
+        mMetadata.set(key, expected);
+
+        byte[] actualValues = mMetadata.readValues(key.getTag());
+        assertArrayEquals(expectedNative, actualValues);
+
+        // Write managed value -> make sure read-out managed value is what we expect
+        T actual = mMetadata.get(key);
+
+        if (typeReference.getRawType().isArray()) {
+            assertArrayEquals(expected, actual);
+        } else {
+            assertEquals(expected, actual);
+        }
+
+        // Write native bytes -> make sure read-out managed value is what we expect
+        mMetadata.writeValues(key.getTag(), expectedNative);
+        actual = mMetadata.get(key);
+
+        if (typeReference.getRawType().isArray()) {
+            assertArrayEquals(expected, actual);
+        } else {
+            assertEquals(expected, actual);
+        }
+
+        return key;
+    }
+
+    /**
+     * Ensure that the data survives a marshal/unmarshal round-trip;
+     * it must also be equal to the {@code expectedNative} byte array.
+     *
+     * <p>As a side-effect,
+     * the metadata value corresponding to the key is now set to {@code expected}.</p>
+     *
+     * @return key created with {@code keyName} and {@code T}
+     */
+    private <T> Key<T> checkKeyMarshal(String keyName, T expected, byte[] expectedNative) {
+        @SuppressWarnings("unchecked")
+        Class<T> expectedClass = (Class<T>) expected.getClass();
+        return checkKeyMarshal(keyName,
+                TypeReference.createSpecializedTypeReference(expectedClass),
+                expected,
+                expectedNative);
     }
 
     @SmallTest
@@ -280,36 +419,36 @@
     @SmallTest
     public void testReadWritePrimitiveArray() {
         // int32 (n)
-        checkKeyGetAndSetArray("android.sensor.info.sensitivityRange", int[].class,
+        checkKeyGetAndSet("android.sensor.info.sensitivityRange", int[].class,
                 new int[] {
                         0xC0FFEE, 0xDEADF00D
                 });
 
         // byte (n)
-        checkKeyGetAndSetArray("android.statistics.faceScores", byte[].class, new byte[] {
+        checkKeyGetAndSet("android.statistics.faceScores", byte[].class, new byte[] {
                 1, 2, 3, 4
         });
 
         // int64 (n)
-        checkKeyGetAndSetArray("android.scaler.availableProcessedMinDurations", long[].class,
+        checkKeyGetAndSet("android.scaler.availableProcessedMinDurations", long[].class,
                 new long[] {
                         0xABCD12345678FFFFL, 0x1234ABCD5678FFFFL, 0xFFFF12345678ABCDL
                 });
 
         // float (n)
-        checkKeyGetAndSetArray("android.lens.info.availableApertures", float[].class,
+        checkKeyGetAndSet("android.lens.info.availableApertures", float[].class,
                 new float[] {
                         Float.MAX_VALUE, Float.MIN_NORMAL, Float.MIN_VALUE
                 });
 
         // double (n) -- in particular double x 3
-        checkKeyGetAndSetArray("android.jpeg.gpsCoordinates", double[].class,
+        checkKeyGetAndSet("android.jpeg.gpsCoordinates", double[].class,
                 new double[] {
                         Double.MAX_VALUE, Double.MIN_NORMAL, Double.MIN_VALUE
                 });
 
         // rational (n) -- in particular rational x 9
-        checkKeyGetAndSetArray("android.sensor.calibrationTransform1", Rational[].class,
+        checkKeyGetAndSet("android.sensor.calibrationTransform1", Rational[].class,
                 new Rational[] {
                         new Rational(1, 2), new Rational(3, 4), new Rational(5, 6),
                         new Rational(7, 8), new Rational(9, 10), new Rational(10, 11),
@@ -321,13 +460,12 @@
          */
 
         // bool (n) -- with TYPE_BYTE
-        checkKeyGetAndSetArray("android.control.aeLock", boolean[].class, new boolean[] {
+        checkKeyGetAndSet("android.control.aeLock", boolean[].class, new boolean[] {
                 true, false, true
         });
 
-
         // integer (n) -- with TYPE_BYTE
-        checkKeyGetAndSetArray("android.control.aeAvailableModes", int[].class, new int[] {
+        checkKeyGetAndSet("android.control.aeAvailableModes", int[].class, new int[] {
             1, 2, 3, 4
         });
     }
@@ -345,7 +483,6 @@
         AUTO
     }
 
-    // TODO: special values for the enum.
     private enum AvailableFormat {
         RAW_SENSOR,
         YV12,
@@ -366,7 +503,7 @@
                 AeAntibandingMode.AUTO);
 
         // byte (n)
-        checkKeyGetAndSetArray("android.control.aeAvailableAntibandingModes",
+        checkKeyGetAndSet("android.control.aeAvailableAntibandingModes",
                 AeAntibandingMode[].class, new AeAntibandingMode[] {
                         AeAntibandingMode.OFF, AeAntibandingMode._50HZ, AeAntibandingMode._60HZ,
                         AeAntibandingMode.AUTO
@@ -376,7 +513,7 @@
          * Stranger cases that don't use byte enums
          */
         // int (n)
-        checkKeyGetAndSetArray("android.scaler.availableFormats", AvailableFormat[].class,
+        checkKeyGetAndSet("android.scaler.availableFormats", AvailableFormat[].class,
                 new AvailableFormat[] {
                         AvailableFormat.RAW_SENSOR,
                         AvailableFormat.YV12,
@@ -389,7 +526,7 @@
 
     @SmallTest
     public void testReadWriteEnumWithCustomValues() {
-        CameraMetadataNative.registerEnumValues(AeAntibandingMode.class, new int[] {
+        MarshalQueryableEnum.registerEnumValues(AeAntibandingMode.class, new int[] {
             0,
             10,
             20,
@@ -401,15 +538,12 @@
                 AeAntibandingMode.AUTO);
 
         // byte (n)
-        checkKeyGetAndSetArray("android.control.aeAvailableAntibandingModes",
+        checkKeyGetAndSet("android.control.aeAvailableAntibandingModes",
                 AeAntibandingMode[].class, new AeAntibandingMode[] {
                         AeAntibandingMode.OFF, AeAntibandingMode._50HZ, AeAntibandingMode._60HZ,
                         AeAntibandingMode.AUTO
                 });
 
-        Key<AeAntibandingMode[]> aeAntibandingModeKey =
-                new Key<AeAntibandingMode[]>("android.control.aeAvailableAntibandingModes",
-                        AeAntibandingMode[].class);
         byte[] aeAntibandingModeValues = mMetadata.readValues(CameraMetadataNative
                 .getTag("android.control.aeAvailableAntibandingModes"));
         byte[] expectedValues = new byte[] { 0, 10, 20, 30 };
@@ -420,7 +554,7 @@
          * Stranger cases that don't use byte enums
          */
         // int (n)
-        CameraMetadataNative.registerEnumValues(AvailableFormat.class, new int[] {
+        MarshalQueryableEnum.registerEnumValues(AvailableFormat.class, new int[] {
             0x20,
             0x32315659,
             0x11,
@@ -429,7 +563,7 @@
             0x21,
         });
 
-        checkKeyGetAndSetArray("android.scaler.availableFormats", AvailableFormat[].class,
+        checkKeyGetAndSet("android.scaler.availableFormats", AvailableFormat[].class,
                 new AvailableFormat[] {
                         AvailableFormat.RAW_SENSOR,
                         AvailableFormat.YV12,
@@ -466,7 +600,7 @@
         checkKeyGetAndSet("android.jpeg.thumbnailSize", Size.class, new Size(123, 456));
 
         // int32 x 2 x n
-        checkKeyGetAndSetArray("android.scaler.availableJpegSizes", Size[].class, new Size[] {
+        checkKeyGetAndSet("android.scaler.availableJpegSizes", Size[].class, new Size[] {
             new Size(123, 456),
             new Size(0xDEAD, 0xF00D),
             new Size(0xF00, 0xB00)
@@ -474,16 +608,217 @@
     }
 
     @SmallTest
-    public void testReadWriteRectangle() {
+    public void testReadWriteRggbChannelVector() {
         // int32 x n
-        checkKeyGetAndSet("android.scaler.cropRegion", Rect.class, new Rect(10, 11, 1280, 1024));
+        checkKeyMarshal("android.colorCorrection.gains",
+                new RggbChannelVector(1.0f, 2.1f, 3.2f, 4.5f),
+                toByteArray(1.0f, 2.1f, 3.2f, 4.5f));
+
+        // int32 x 2 x n [pretend; actual is not array]
+        checkKeyMarshal("android.colorCorrection.gains",
+                new RggbChannelVector[] {
+                    new RggbChannelVector(1.0f, 2.0f, 3.0f, 4.0f),
+                    new RggbChannelVector(9.0f, 8.0f, 7.0f, 6.0f),
+                    new RggbChannelVector(1.3f, 5.5f, 2.4f, 6.7f),
+                }, toByteArray(
+                        1.0f, 2.0f, 3.0f, 4.0f,
+                        9.0f, 8.0f, 7.0f, 6.0f,
+                        1.3f, 5.5f, 2.4f, 6.7f
+                ));
+    }
+
+    @SmallTest
+    public void testReadWriteSizeF() {
+        // int32 x n
+        checkKeyMarshal("android.sensor.info.physicalSize",
+                new SizeF(123f, 456f),
+                toByteArray(123f, 456f));
 
         // int32 x 2 x n
-        checkKeyGetAndSetArray("android.statistics.faceRectangles", Rect[].class, new Rect[] {
+        checkKeyMarshal("android.sensor.info.physicalSize",
+                new SizeF[] {
+                    new SizeF(123f, 456f),
+                    new SizeF(1.234f, 4.567f),
+                    new SizeF(999.0f, 555.0f)
+                },
+                toByteArray(
+                        123f, 456f,
+                        1.234f, 4.567f,
+                        999.0f, 555.0f)
+        );
+    }
+
+    @SmallTest
+    public void testReadWriteRectangle() {
+        // int32 x n
+        checkKeyMarshal("android.scaler.cropRegion",
+                // x1, y1, x2, y2
+                new Rect(10, 11, 1280, 1024),
+                // x, y, width, height
+                toByteArray(10, 11, 1280 - 10, 1024 - 11));
+
+        // int32 x 2 x n  [actually not array, but we pretend it is]
+        checkKeyMarshal("android.scaler.cropRegion", new Rect[] {
             new Rect(110, 111, 11280, 11024),
             new Rect(210, 111, 21280, 21024),
             new Rect(310, 111, 31280, 31024)
-        });
+        }, toByteArray(
+                110, 111, 11280 - 110, 11024 - 111,
+                210, 111, 21280 - 210, 21024 - 111,
+                310, 111, 31280 - 310, 31024 - 111
+        ));
+    }
+
+    @SmallTest
+    public void testReadWriteMeteringRectangle() {
+        // int32 x 5 x area_count [but we pretend it's a single element]
+        checkKeyMarshal("android.control.aeRegions",
+                new MeteringRectangle(/*x*/1, /*y*/2, /*width*/100, /*height*/200, /*weight*/5),
+                /* xmin, ymin, xmax, ymax, weight */
+                toByteArray(1, 2, 1 + 100, 2 + 200, 5));
+
+        // int32 x 5 x area_count
+        checkKeyMarshal("android.control.afRegions",
+                new MeteringRectangle[] {
+                    new MeteringRectangle(/*x*/5, /*y*/6, /*width*/123, /*height*/456, /*weight*/7),
+                    new MeteringRectangle(/*x*/7, /*y*/8, /*width*/456, /*height*/999, /*weight*/6),
+                    new MeteringRectangle(/*x*/1, /*y*/2, /*width*/100, /*height*/200, /*weight*/5)
+                },
+                toByteArray(
+                        5, 6, 5 + 123, 6 + 456, 7,
+                        7, 8, 7 + 456, 8 + 999, 6,
+                        1, 2, 1 + 100, 2 + 200, 5
+        ));
+    }
+
+    @SmallTest
+    public void testReadWriteColorSpaceTransform() {
+        // rational x 3 x 3
+        checkKeyMarshal("android.colorCorrection.transform",
+                new ColorSpaceTransform(new Rational[] {
+                        new Rational(1, 2), new Rational(3, 4), new Rational(5, 6),
+                        new Rational(7, 8), new Rational(8, 9), new Rational(10, 11),
+                        new Rational(1, 5), new Rational(2, 8), new Rational(3, 9),
+                }),
+                toByteArray(
+                        1, 2, 3, 4, 5, 6,
+                        7, 8, 8, 9, 10, 11,
+                        1, 5, 2, 8, 3, 9));
+    }
+
+    @SmallTest
+    public void testReadWritePoint() {
+        // int32 x 2 [actually 'x n' but pretend it's a single value for now]
+        checkKeyMarshal("android.statistics.hotPixelMap",
+                new Point(1, 2),
+                toByteArray(1, 2));
+
+        // int32 x 2 x samples
+        checkKeyMarshal("android.statistics.hotPixelMap",
+                new Point[] {
+                    new Point(1, 2),
+                    new Point(3, 4),
+                    new Point(5, 6),
+                    new Point(7, 8),
+                },
+                toByteArray(
+                        1, 2,
+                        3, 4,
+                        5, 6,
+                        7, 8)
+        );
+    }
+
+    @SmallTest
+    public void testReadWritePointF() {
+        // float x 2 [actually 'x samples' but pretend it's a single value for now]
+        checkKeyMarshal(
+                "android.sensor.profileToneCurve",
+                new PointF(1.0f, 2.0f),
+                toByteArray(1.0f, 2.0f));
+
+        // float x 2 x samples
+        checkKeyMarshal("android.sensor.profileToneCurve",
+                new PointF[] {
+                    new PointF(1.0f, 2.0f),
+                    new PointF(3.0f, 4.0f),
+                    new PointF(5.0f, 6.0f),
+                    new PointF(7.0f, 8.0f),
+                },
+                toByteArray(
+                        1.0f, 2.0f,
+                        3.0f, 4.0f,
+                        5.0f, 6.0f,
+                        7.0f, 8.0f));
+    }
+
+    @SmallTest
+    public void testReadWriteRange() {
+        // int32 x 2
+        checkKeyMarshal("android.control.aeTargetFpsRange",
+                new TypeReference<Range<Integer>>() {{ }},
+                Range.create(123, 456),
+                toByteArray(123, 456));
+
+        // int64 x 2
+        checkKeyMarshal("android.sensor.info.exposureTimeRange",
+                new TypeReference<Range<Long>>() {{ }},
+                Range.create(123L, 456L),
+                toByteArray(123L, 456L));
+    }
+
+    @SmallTest
+    public void testReadWriteStreamConfiguration() {
+        // int32 x 4 x n
+        checkKeyMarshal("android.scaler.availableStreamConfigurations",
+                new StreamConfiguration[] {
+                    new StreamConfiguration(ImageFormat.YUV_420_888, 640, 480, /*input*/false),
+                    new StreamConfiguration(ImageFormat.RGB_565, 320, 240, /*input*/true),
+                },
+                toByteArray(
+                        ImageFormat.YUV_420_888, 640, 480, /*input*/0,
+                        ImageFormat.RGB_565, 320, 240, /*input*/1)
+        );
+    }
+
+    @SmallTest
+    public void testReadWriteStreamConfigurationDuration() {
+        // Avoid sign extending ints when converting to a long
+        final long MASK_UNSIGNED_INT = 0x00000000ffffffffL;
+
+        // int64 x 4 x n
+        checkKeyMarshal("android.scaler.availableMinFrameDurations",
+                new StreamConfigurationDuration[] {
+                    new StreamConfigurationDuration(
+                            ImageFormat.YUV_420_888, 640, 480, /*duration*/123L),
+                    new StreamConfigurationDuration(
+                            ImageFormat.RGB_565, 320, 240, /*duration*/345L),
+                },
+                toByteArray(
+                        ImageFormat.YUV_420_888 & MASK_UNSIGNED_INT, 640L, 480L, /*duration*/123L,
+                        ImageFormat.RGB_565 & MASK_UNSIGNED_INT, 320L, 240L, /*duration*/345L)
+        );
+    }
+
+
+    @SmallTest
+    public void testReadWriteReprocessFormatsMap() {
+
+        final int RAW_OPAQUE = 0x24;
+        final int RAW16 = ImageFormat.RAW_SENSOR;
+        final int YUV_420_888 = ImageFormat.YUV_420_888;
+        final int BLOB = 0x21;
+
+        int[] contents = new int[] {
+                RAW_OPAQUE, 3, RAW16, YUV_420_888, BLOB,
+                RAW16, 2, YUV_420_888, BLOB,
+        };
+
+        // int32 x n
+        checkKeyMarshal("android.scaler.availableInputOutputFormatsMap",
+                new ReprocessFormatsMap(contents),
+                toByteArray(contents)
+        );
     }
 
     @SmallTest
@@ -525,10 +860,6 @@
         assertArrayEquals(gpsBytes, actualBytes2);
     }
 
-    <T> void compareGeneric(T expected, T actual) {
-        assertEquals(expected, actual);
-    }
-
     @SmallTest
     public void testReadWriteOverride() {
         //
@@ -691,7 +1022,7 @@
      */
     private <T> void validateArrayMetadataReadWriteOverride(Key<T> key, T writeValues,
             T readValues, int tag) {
-        Class<T> type = key.getType();
+        Class<?> type = writeValues.getClass();
         if (!type.isArray()) {
             throw new IllegalArgumentException("This function expects an key with array type");
         } else if (type != int[].class && type != long[].class) {
@@ -737,4 +1068,20 @@
         assertNotNull(key.getName() + " result shouldn't be null", result);
         assertArrayEquals(writeValues, result);
     }
+
+    // TODO: move somewhere else
+    @SmallTest
+    public void testToByteArray() {
+        assertArrayEquals(new byte[] { 5, 0, 0, 0, 6, 0, 0, 0 },
+                toByteArray(5, 6));
+        assertArrayEquals(new byte[] { 5, 0, 6, 0, },
+                toByteArray((short)5, (short)6));
+        assertArrayEquals(new byte[] { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
+                                        (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,},
+                toByteArray(~0, ~0));
+
+        assertArrayEquals(new byte[] { (byte)0xAB, (byte)0xFF, 0, 0,
+                0x0D, (byte)0xF0, (byte)0xAD, (byte)0xDE },
+                toByteArray(0xFFAB, 0xDEADF00D));
+    }
 }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsTypeReferenceTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsTypeReferenceTest.java
new file mode 100644
index 0000000..1b765ea
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsTypeReferenceTest.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.mediaframeworktest.unit;
+
+import static android.hardware.camera2.utils.TypeReference.*;
+
+import android.hardware.camera2.utils.TypeReference;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import java.lang.reflect.Type;
+import java.util.List;
+
+public class CameraUtilsTypeReferenceTest extends junit.framework.TestCase {
+    private static final String TAG = CameraUtilsTypeReferenceTest.class.getSimpleName();
+    private static final boolean VERBOSE = false;
+
+    private class RegularClass {}
+    private class SubClass extends RegularClass {}
+
+    private class GenericClass<T> {}
+    private class SubGenericClass<T> extends GenericClass<T> {}
+
+    private class SpecificClass extends GenericClass<Integer> {}
+
+    private interface RegularInterface {}
+    private interface GenericInterface<T> {}
+    private interface GenericInterface2<T> {}
+
+    private class ImplementsRegularInterface implements RegularInterface {}
+    private class ImplementsGenericInterface<T> implements GenericInterface<T> {}
+    private class Implements2GenericInterface<T>
+        implements GenericInterface<Integer>, GenericInterface2<T> {}
+
+    private class GenericOuterClass<T> {
+        class GenericInnerClass {
+            @SuppressWarnings("unused")
+            T field;
+        }
+    }
+
+    private static void assertContainsTypeVariable(Type type) {
+        assertTrue(type.toString() + " was expected to have a type variable, but it didn't",
+                containsTypeVariable(type));
+    }
+
+    private static void assertLacksTypeVariable(Type type) {
+        assertFalse(type.toString() + " was expected to *not* have a type variable, but it did",
+                containsTypeVariable(type));
+    }
+
+    /*
+     * Only test classes and interfaces. Other types are not tested (e.g. fields, methods, etc).
+     */
+
+    @SmallTest
+    public void testLacksTypeVariables() {
+        assertLacksTypeVariable(RegularClass.class);
+        assertLacksTypeVariable(SubClass.class);
+        assertLacksTypeVariable(SpecificClass.class);
+
+        assertLacksTypeVariable(RegularInterface.class);
+        assertLacksTypeVariable(ImplementsRegularInterface.class);
+    }
+
+    @SmallTest
+    public void testContainsTypeVariables() {
+        assertContainsTypeVariable(GenericClass.class);
+        assertContainsTypeVariable(SubGenericClass.class);
+
+        assertContainsTypeVariable(GenericInterface.class);
+        assertContainsTypeVariable(ImplementsGenericInterface.class);
+        assertContainsTypeVariable(Implements2GenericInterface.class);
+
+        assertContainsTypeVariable(GenericOuterClass.class);
+        assertContainsTypeVariable(GenericOuterClass.GenericInnerClass.class);
+    }
+
+    /**
+     * This should always throw an IllegalArgumentException since the
+     * type reference to {@code T} will contain a type variable (also {@code T}).
+     *
+     * @throws IllegalArgumentException unconditionally
+     */
+    private static <T> TypeReference<T> createTypeRefWithTypeVar() {
+        return new TypeReference<T>() {{ }};
+    }
+
+    @SmallTest
+    public void testTypeReferences() {
+        TypeReference<Integer> typeRefInt = new TypeReference<Integer>() {{ }};
+        TypeReference<Integer> typeRefInt2 = new TypeReference<Integer>() {{ }};
+
+        assertEquals(typeRefInt, typeRefInt2);
+        assertEquals("The type ref's captured type should be the Integer class",
+                Integer.class, typeRefInt.getType());
+
+        TypeReference<Float> typeRefFloat = new TypeReference<Float>() {{ }};
+        assertFalse("Integer/Float type references must not be equal",
+                typeRefInt.equals(typeRefFloat));
+        assertEquals("The type ref's captured type should be the Float class",
+                Float.class, typeRefFloat.getType());
+
+        try {
+            TypeReference<Integer> typeRefTypeVar = createTypeRefWithTypeVar();
+            fail("Expected a type reference with type variables to fail");
+            // Unreachable. Make the warning about an unused variable go away.
+            assertFalse(typeRefTypeVar.equals(typeRefInt));
+        } catch (IllegalArgumentException e) {
+            // OK. Expected behavior
+        }
+    }
+
+    // Compare the raw type against rawClass
+    private static <T> void assertRawTypeEquals(TypeReference<T> typeRef, Class<?> rawClass) {
+        assertEquals("Expected the raw type from " + typeRef + " to match the class " + rawClass,
+                rawClass, typeRef.getRawType());
+    }
+
+    // Compare the normal type against the klass
+    private static <T> void assertTypeReferenceEquals(TypeReference<T> typeRef, Class<?> klass) {
+        assertEquals("Expected the type from " + typeRef + " to match the class " + klass,
+                klass, typeRef.getType());
+    }
+
+    @SmallTest
+    public void testRawTypes() {
+        TypeReference<Integer> intToken = new TypeReference<Integer>() {{ }};
+        assertRawTypeEquals(intToken, Integer.class);
+
+        TypeReference<List<Integer>> listToken = new TypeReference<List<Integer>>() {{ }};
+        assertRawTypeEquals(listToken, List.class);
+
+        TypeReference<List<List<Integer>>> listListToken =
+                new TypeReference<List<List<Integer>>>() {{ }};
+        assertRawTypeEquals(listListToken, List.class);
+
+        TypeReference<int[]> intArrayToken = new TypeReference<int[]>() {{ }};
+        assertRawTypeEquals(intArrayToken, int[].class);
+
+        TypeReference<Integer[]> integerArrayToken = new TypeReference<Integer[]>() {{ }};
+        assertRawTypeEquals(integerArrayToken, Integer[].class);
+
+        TypeReference<List<Integer>[]> listArrayToken = new TypeReference<List<Integer>[]>() {{ }};
+        assertRawTypeEquals(listArrayToken, List[].class);
+    }
+
+    private class IntTokenOne extends TypeReference<Integer> {}
+    private class IntTokenTwo extends TypeReference<Integer> {}
+
+    private class IntArrayToken1 extends TypeReference<Integer[]> {}
+    private class IntArrayToken2 extends TypeReference<Integer[]> {}
+
+    private class IntListToken1 extends TypeReference<List<Integer>> {}
+    private class IntListToken2 extends TypeReference<List<Integer>> {}
+
+    private class IntListArrayToken1 extends TypeReference<List<Integer>[]> {}
+    private class IntListArrayToken2 extends TypeReference<List<Integer>[]> {}
+
+
+    // FIXME: Equality will fail: b/14590652
+    @SmallTest
+    public void testEquals() {
+        // Not an array. component type should be null.
+        TypeReference<Integer> intToken = new TypeReference<Integer>() {{ }};
+        assertEquals(intToken, intToken);
+        assertEquals(intToken, new TypeReference<Integer>() {{ }});
+
+        assertEquals(intToken, new IntTokenOne());
+        assertEquals(intToken, new IntTokenTwo());
+        assertEquals(new IntTokenOne(), new IntTokenTwo());
+
+        assertEquals(new IntArrayToken1(), new IntArrayToken2());
+        assertEquals(new IntListToken1(), new IntListToken2());
+        assertEquals(new IntListArrayToken1(), new IntListArrayToken2());
+    }
+
+    @SmallTest
+    public void testComponentType() {
+        // Not an array. component type should be null.
+        TypeReference<Integer> intToken = new TypeReference<Integer>() {{ }};
+        assertNull(intToken.getComponentType());
+
+        TypeReference<List<Integer>> listToken = new TypeReference<List<Integer>>() {{ }};
+        assertNull(listToken.getComponentType());
+
+        TypeReference<List<List<Integer>>> listListToken =
+                new TypeReference<List<List<Integer>>>() {{ }};
+        assertNull(listListToken.getComponentType());
+
+        // Check arrays. Component types should be what we expect.
+        TypeReference<int[]> intArrayToken = new TypeReference<int[]>() {{ }};
+        assertTypeReferenceEquals(intArrayToken.getComponentType(), int.class);
+
+        TypeReference<Integer[]> integerArrayToken = new TypeReference<Integer[]>() {{ }};
+        assertTypeReferenceEquals(integerArrayToken.getComponentType(), Integer.class);
+
+        assertEquals(new IntArrayToken1().getComponentType(),
+                new IntArrayToken2().getComponentType());
+
+        assertEquals(new IntListArrayToken1().getComponentType(),
+                new IntListArrayToken2().getComponentType());
+
+        // FIXME: Equality will fail: b/14590652
+        TypeReference<List<Integer>[]> listArrayToken = new TypeReference<List<Integer>[]>() {{ }};
+        assertEquals(listToken, listArrayToken.getComponentType());
+    }
+}
diff --git a/packages/BackupRestoreConfirmation/res/values-sk/strings.xml b/packages/BackupRestoreConfirmation/res/values-sk/strings.xml
index 12f562b..21e21b5 100644
--- a/packages/BackupRestoreConfirmation/res/values-sk/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-sk/strings.xml
@@ -24,7 +24,7 @@
     <string name="restore_confirm_text" msgid="7499866728030461776">"Z pripojeného počítača bolo vyžiadané úplné obnovenie všetkých údajov. Chcete túto akciu povoliť?\n\nAk ste toto obnovenie nevyžiadali vy, túto operáciu nepovoľujte. Táto akcia nahradí všetky údaje v zariadení."</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Obnoviť údaje"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Neobnoviť"</string>
-    <string name="current_password_text" msgid="8268189555578298067">"Zadajte svoje aktuálne heslo záloh nižšie:"</string>
+    <string name="current_password_text" msgid="8268189555578298067">"Zadajte svoje aktuálne heslo pre zálohu nižšie:"</string>
     <string name="device_encryption_restore_text" msgid="1570864916855208992">"Zadajte svoje heslo na šifrovanie zariadenia nižšie."</string>
     <string name="device_encryption_backup_text" msgid="5866590762672844664">"Zadajte svoje heslo na šifrovanie zariadenia nižšie. Bude tiež použité na šifrovanie archívu zálohy."</string>
     <string name="backup_enc_password_text" msgid="4981585714795233099">"Zadajte heslo, ktoré sa použije pri šifrovaní údajov úplnej zálohy. Ak pole ponecháte prázdne, použije sa vaše aktuálne heslo zálohy:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-sw/strings.xml b/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
index 4e35b91..619a6db 100644
--- a/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
@@ -18,17 +18,17 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Kuhifadhi kikamilifu"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Kurejesha kila kitu"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Ombi la kuhifadhi nakala rudufu kamili za data kwenye eneo kazi la kompyuta iliyounganishwa limewasilishwa. Ungependa shughuli hii ufanyike?\n\n Ikiwa sio wewe uliyewasilisha ombi hili, usikubali shughuli hii iendelee."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Chelezo kamili la data iliyounganishwa kwenye eneo kazi la kompyuta limeombwa. Unataka kuruhusu hii kutendeka?\n\n Ikiwa hukuomba chelezo mwenyewe, usikubali uendeshaji kuendelea."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Hifadhi nakala ya data yangu"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Usicheleze"</string>
     <string name="restore_confirm_text" msgid="7499866728030461776">"Kurejesha kamili kwa data nzima kutoka kwa eneo kazi la kompyuta lililounganishwa limeombwa. Unataka kuruhusu hii kutendeka?\n\n Ikiwa hukuweza kurejesha upya mwenyewe, usiruhusu uendeshaji huu kuendelea. Hii itaweka upya data yoyote iliyo kwenye kifaa hiki sasa!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Rejesha upya data yangu"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Usirejeshe upya"</string>
-    <string name="current_password_text" msgid="8268189555578298067">"Tafadhali ingiza nenosiri unalotumia kuhifadhi nakala rudufu hapo chini:"</string>
+    <string name="current_password_text" msgid="8268189555578298067">"Tafadhali ingiza nenosiri lako la chelezo hapo chini:"</string>
     <string name="device_encryption_restore_text" msgid="1570864916855208992">"Tafadhali ingiza nenosiri la usimbaji fiche wa kifaa chako hapo chini."</string>
     <string name="device_encryption_backup_text" msgid="5866590762672844664">"Tafadhali ingiza nenosiri lako la msimbo fiche hapo chini. Pia litatumika kusimba fiche jalidi ya hifadhi."</string>
-    <string name="backup_enc_password_text" msgid="4981585714795233099">"Tafadhali ingiza nenosiri la kutumia katika kusimba nakala rudufu kamili za data kwa njia fiche. Ikiwa hii itawachwa wazi, nenosiri lako la sasa litatumika:"</string>
-    <string name="backup_enc_password_optional" msgid="1350137345907579306">"Ikiwa unataka kusimba kwa njia fiche nakala rudufu za data, ingiza nenosiri lililo hapo chini:"</string>
+    <string name="backup_enc_password_text" msgid="4981585714795233099">"Tafadhali ingiza nenosiri la kutumia kwa usimbaji fiche wa chelezo ya data kamili. Ikiwa hii itawachwa wazi, nenosiri lako la sasa litatumika:"</string>
+    <string name="backup_enc_password_optional" msgid="1350137345907579306">"Ikiwa unataka kusimba fiche data nzima ya kucheleza, ingiza nenosiri la hapo chini:"</string>
     <string name="restore_enc_password_text" msgid="6140898525580710823">"Ikiwa data iliyorejeshwa upya, tafadhali ingiza nenosiri lililo hapo chini:"</string>
     <string name="toast_backup_started" msgid="550354281452756121">"Inaanza kuhifadhi..."</string>
     <string name="toast_backup_ended" msgid="3818080769548726424">"Imemaliza kuhifadhi"</string>
diff --git a/packages/DefaultContainerService/res/values-th/strings.xml b/packages/DefaultContainerService/res/values-th/strings.xml
index 621d7ed..3a7080c 100644
--- a/packages/DefaultContainerService/res/values-th/strings.xml
+++ b/packages/DefaultContainerService/res/values-th/strings.xml
@@ -20,5 +20,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="service_name" msgid="4841491635055379553">"ตัวช่วยเหลือของการเข้าถึงแพ็กเกจ"</string>
+    <string name="service_name" msgid="4841491635055379553">"ตัวช่วยเหลือของการเข้าถึงแพคเกจ"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml
index ca76a7d..41fd63a 100644
--- a/packages/DocumentsUI/res/values-af/strings.xml
+++ b/packages/DocumentsUI/res/values-af/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Stoor"</string>
     <string name="menu_share" msgid="3075149983979628146">"Deel"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Vee uit"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Kies \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> gekies"</string>
     <string name="sort_name" msgid="9183560467917256779">"Volgens naam"</string>
     <string name="sort_date" msgid="586080032956151448">"Volgens datum gewysig"</string>
diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml
index 84879d5..c77a8ee 100644
--- a/packages/DocumentsUI/res/values-am/strings.xml
+++ b/packages/DocumentsUI/res/values-am/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"አስቀምጥ"</string>
     <string name="menu_share" msgid="3075149983979628146">"አጋራ"</string>
     <string name="menu_delete" msgid="8138799623850614177">"ሰርዝ"</string>
-    <string name="menu_select" msgid="8711270657353563424">"«<xliff:g id="DIRECTORY">^1</xliff:g>»ን ይምረጡ"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> ተመርጠዋል"</string>
     <string name="sort_name" msgid="9183560467917256779">"በስም"</string>
     <string name="sort_date" msgid="586080032956151448">"በተለወጠበት ቀን"</string>
diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml
index 5c5d863..c59c0ee 100644
--- a/packages/DocumentsUI/res/values-ar/strings.xml
+++ b/packages/DocumentsUI/res/values-ar/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"حفظ"</string>
     <string name="menu_share" msgid="3075149983979628146">"مشاركة"</string>
     <string name="menu_delete" msgid="8138799623850614177">"حذف"</string>
-    <string name="menu_select" msgid="8711270657353563424">"تحديد \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"تم تحديد <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="sort_name" msgid="9183560467917256779">"بحسب الاسم"</string>
     <string name="sort_date" msgid="586080032956151448">"بحسب تاريخ التعديل"</string>
diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml
index d1da879..c3242b2 100644
--- a/packages/DocumentsUI/res/values-bg/strings.xml
+++ b/packages/DocumentsUI/res/values-bg/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Запазване"</string>
     <string name="menu_share" msgid="3075149983979628146">"Споделяне"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Изтриване"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Избиране на „<xliff:g id="DIRECTORY">^1</xliff:g>“"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"Избрахте <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="sort_name" msgid="9183560467917256779">"По име"</string>
     <string name="sort_date" msgid="586080032956151448">"По дата на промяната"</string>
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index 23e7284..68c7b0e 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Desa"</string>
     <string name="menu_share" msgid="3075149983979628146">"Comparteix"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Suprimeix"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Selecciona \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"Seleccionats: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="sort_name" msgid="9183560467917256779">"Per nom"</string>
     <string name="sort_date" msgid="586080032956151448">"Per data de modificació"</string>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index ad8897a..f089c8b 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Uložit"</string>
     <string name="menu_share" msgid="3075149983979628146">"Sdílet"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Smazat"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Vyberte adresář <xliff:g id="DIRECTORY">^1</xliff:g>"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"Vybráno: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="sort_name" msgid="9183560467917256779">"Podle názvu"</string>
     <string name="sort_date" msgid="586080032956151448">"Podle data úpravy"</string>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index 7ae5d1e..816f9a7 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Gem"</string>
     <string name="menu_share" msgid="3075149983979628146">"Del"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Slet"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Vælg \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> er valgt"</string>
     <string name="sort_name" msgid="9183560467917256779">"Efter navn"</string>
     <string name="sort_date" msgid="586080032956151448">"Efter ændringsdato"</string>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index 98c1787..3b448d9 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Speichern"</string>
     <string name="menu_share" msgid="3075149983979628146">"Teilen"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Löschen"</string>
-    <string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" auswählen"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> ausgewählt"</string>
     <string name="sort_name" msgid="9183560467917256779">"Nach Name"</string>
     <string name="sort_date" msgid="586080032956151448">"Nach Änderungsdatum"</string>
@@ -48,7 +47,7 @@
     <string name="pref_advanced_devices" msgid="903257239609301276">"Erweiterte Geräte anzeigen"</string>
     <string name="pref_file_size" msgid="2826879315743961459">"Dateigröße anzeigen"</string>
     <string name="pref_device_size" msgid="3542106883278997222">"Geräteabmessungen anzeigen"</string>
-    <string name="empty" msgid="7858882803708117596">"Keine Dokumente"</string>
+    <string name="empty" msgid="7858882803708117596">"Keine Elemente"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Datei kann nicht geöffnet werden."</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Einige Dokumente konnten nicht gelöscht werden."</string>
     <string name="share_via" msgid="8966594246261344259">"Teilen über"</string>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index f0f7e10..aec3318 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -27,9 +27,8 @@
     <string name="menu_settings" msgid="6008033148948428823">"Ρυθμίσεις"</string>
     <string name="menu_open" msgid="432922957274920903">"Άνοιγμα"</string>
     <string name="menu_save" msgid="2394743337684426338">"Αποθήκευση"</string>
-    <string name="menu_share" msgid="3075149983979628146">"Κοινοποίηση"</string>
+    <string name="menu_share" msgid="3075149983979628146">"Κοινή χρήση"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Διαγραφή"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Επιλογή \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"Επιλέχθηκαν <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="sort_name" msgid="9183560467917256779">"Κατά όνομα"</string>
     <string name="sort_date" msgid="586080032956151448">"Κατά ημερομηνία τροποποίησης"</string>
@@ -51,5 +50,5 @@
     <string name="empty" msgid="7858882803708117596">"Δεν υπάρχουν στοιχεία"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Δεν είναι δυνατό το άνοιγμα του αρχείου"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Δεν είναι δυνατή η διαγραφή ορισμένων εγγράφων"</string>
-    <string name="share_via" msgid="8966594246261344259">"Κοινοποίηση μέσω"</string>
+    <string name="share_via" msgid="8966594246261344259">"Κοινή χρήση μέσω"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml
index d2af473..a95e7f1 100644
--- a/packages/DocumentsUI/res/values-en-rGB/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Save"</string>
     <string name="menu_share" msgid="3075149983979628146">"Share"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Delete"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Select \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selected"</string>
     <string name="sort_name" msgid="9183560467917256779">"By name"</string>
     <string name="sort_date" msgid="586080032956151448">"By date modified"</string>
diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml
index d2af473..a95e7f1 100644
--- a/packages/DocumentsUI/res/values-en-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Save"</string>
     <string name="menu_share" msgid="3075149983979628146">"Share"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Delete"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Select \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selected"</string>
     <string name="sort_name" msgid="9183560467917256779">"By name"</string>
     <string name="sort_date" msgid="586080032956151448">"By date modified"</string>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index daf18cf..4a3ff33 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Guardar"</string>
     <string name="menu_share" msgid="3075149983979628146">"Compartir"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Seleccionar \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> seleccionado(s)"</string>
     <string name="sort_name" msgid="9183560467917256779">"Por nombre"</string>
     <string name="sort_date" msgid="586080032956151448">"Por fecha de modificación"</string>
diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml
index 573ee41..1682542 100644
--- a/packages/DocumentsUI/res/values-es/strings.xml
+++ b/packages/DocumentsUI/res/values-es/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Guardar"</string>
     <string name="menu_share" msgid="3075149983979628146">"Compartir"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Selecciona \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"Seleccionado: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="sort_name" msgid="9183560467917256779">"Por nombre"</string>
     <string name="sort_date" msgid="586080032956151448">"Por fecha de modificación"</string>
diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml
index dae965a0..5412956 100644
--- a/packages/DocumentsUI/res/values-et-rEE/strings.xml
+++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Salvesta"</string>
     <string name="menu_share" msgid="3075149983979628146">"Jaga"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Kustuta"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Kataloogi „<xliff:g id="DIRECTORY">^1</xliff:g>” valimine"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> on valitud"</string>
     <string name="sort_name" msgid="9183560467917256779">"Nime järgi"</string>
     <string name="sort_date" msgid="586080032956151448">"Muutmiskuupäeva järgi"</string>
diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml
index a646eda..c922b37 100644
--- a/packages/DocumentsUI/res/values-fa/strings.xml
+++ b/packages/DocumentsUI/res/values-fa/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"ذخیره"</string>
     <string name="menu_share" msgid="3075149983979628146">"اشتراک‌گذاری"</string>
     <string name="menu_delete" msgid="8138799623850614177">"حذف"</string>
-    <string name="menu_select" msgid="8711270657353563424">"انتخاب «<xliff:g id="DIRECTORY">^1</xliff:g>»"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> انتخاب شد"</string>
     <string name="sort_name" msgid="9183560467917256779">"بر اساس نام"</string>
     <string name="sort_date" msgid="586080032956151448">"بر اساس تاریخ اصلاح"</string>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index aa118ed..5e40ecd 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Tallenna"</string>
     <string name="menu_share" msgid="3075149983979628146">"Jaa"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Poista"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Valitse <xliff:g id="DIRECTORY">^1</xliff:g>"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> valittua"</string>
     <string name="sort_name" msgid="9183560467917256779">"Nimen mukaan"</string>
     <string name="sort_date" msgid="586080032956151448">"Muokkauspäivän mukaan"</string>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index b370a1e..a837379 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Enregistrer"</string>
     <string name="menu_share" msgid="3075149983979628146">"Partager"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Supprimer"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Sélectionner « <xliff:g id="DIRECTORY">^1</xliff:g> »"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> sélectionné(s)"</string>
     <string name="sort_name" msgid="9183560467917256779">"Par nom"</string>
     <string name="sort_date" msgid="586080032956151448">"Par date de modification"</string>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index 070b130..ff9aeda 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Enregistrer"</string>
     <string name="menu_share" msgid="3075149983979628146">"Partager"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Supprimer"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Sélectionner \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> élément(s) sélectionné(s)"</string>
     <string name="sort_name" msgid="9183560467917256779">"Par nom"</string>
     <string name="sort_date" msgid="586080032956151448">"Par date de modification"</string>
diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml
index 66c707e..8d7fcba 100644
--- a/packages/DocumentsUI/res/values-hi/strings.xml
+++ b/packages/DocumentsUI/res/values-hi/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"सहेजें"</string>
     <string name="menu_share" msgid="3075149983979628146">"साझा करें"</string>
     <string name="menu_delete" msgid="8138799623850614177">"हटाएं"</string>
-    <string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" चुनें"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> चयनित"</string>
     <string name="sort_name" msgid="9183560467917256779">"नाम के अनुसार"</string>
     <string name="sort_date" msgid="586080032956151448">"बदलाव के दिनांक के अनुसार"</string>
diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml
index 3438e73..73c2f04 100644
--- a/packages/DocumentsUI/res/values-hr/strings.xml
+++ b/packages/DocumentsUI/res/values-hr/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Spremi"</string>
     <string name="menu_share" msgid="3075149983979628146">"Dijeli"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Izbriši"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Odaberi \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"Odabrano: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="sort_name" msgid="9183560467917256779">"Po korisniku"</string>
     <string name="sort_date" msgid="586080032956151448">"Po datumu izmjene"</string>
diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml
index 2af559b..db7854b 100644
--- a/packages/DocumentsUI/res/values-hu/strings.xml
+++ b/packages/DocumentsUI/res/values-hu/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Mentés"</string>
     <string name="menu_share" msgid="3075149983979628146">"Megosztás"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Törlés"</string>
-    <string name="menu_select" msgid="8711270657353563424">"A(z) „<xliff:g id="DIRECTORY">^1</xliff:g>” mappa kiválasztása"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> kiválasztva"</string>
     <string name="sort_name" msgid="9183560467917256779">"Név szerint"</string>
     <string name="sort_date" msgid="586080032956151448">"Módosítás dátuma szerint"</string>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index 67a1f7e..c683f3e 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Պահել"</string>
     <string name="menu_share" msgid="3075149983979628146">"Համօգտագործել"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Ջնջել"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Ընտրել «<xliff:g id="DIRECTORY">^1</xliff:g>»"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> ընտրված"</string>
     <string name="sort_name" msgid="9183560467917256779">"Ըստ անվան"</string>
     <string name="sort_date" msgid="586080032956151448">"Ըստ փոփոխման ամսաթվի"</string>
diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml
index 62057c7..519b936 100644
--- a/packages/DocumentsUI/res/values-in/strings.xml
+++ b/packages/DocumentsUI/res/values-in/strings.xml
@@ -22,14 +22,13 @@
     <string name="menu_create_dir" msgid="5947289605844398389">"Buat folder"</string>
     <string name="menu_grid" msgid="6878021334497835259">"Tampilan kisi"</string>
     <string name="menu_list" msgid="7279285939892417279">"Tampilan daftar"</string>
-    <string name="menu_sort" msgid="7677740407158414452">"Urutkan menurut"</string>
+    <string name="menu_sort" msgid="7677740407158414452">"Sortir menurut"</string>
     <string name="menu_search" msgid="3816712084502856974">"Telusuri"</string>
     <string name="menu_settings" msgid="6008033148948428823">"Setelan"</string>
     <string name="menu_open" msgid="432922957274920903">"Buka"</string>
     <string name="menu_save" msgid="2394743337684426338">"Simpan"</string>
     <string name="menu_share" msgid="3075149983979628146">"Bagikan"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Hapus"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Pilih \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> dipilih"</string>
     <string name="sort_name" msgid="9183560467917256779">"Menurut nama"</string>
     <string name="sort_date" msgid="586080032956151448">"Menurut tanggal diubah"</string>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index bec4d00..28323b6 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Salva"</string>
     <string name="menu_share" msgid="3075149983979628146">"Condividi"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Elimina"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Seleziona \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selezionati"</string>
     <string name="sort_name" msgid="9183560467917256779">"Per nome"</string>
     <string name="sort_date" msgid="586080032956151448">"Per data di modifica"</string>
@@ -39,7 +38,7 @@
     <string name="save_error" msgid="6167009778003223664">"Impossibile salvare il documento"</string>
     <string name="create_error" msgid="3735649141335444215">"Impossibile creare la cartella"</string>
     <string name="query_error" msgid="1222448261663503501">"Impossibile chiedere documenti"</string>
-    <string name="root_recent" msgid="4470053704320518133">"Recenti"</string>
+    <string name="root_recent" msgid="4470053704320518133">"Recente"</string>
     <string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> liberi"</string>
     <string name="root_type_service" msgid="2178854894416775409">"Servizi di archiviazione"</string>
     <string name="root_type_shortcut" msgid="3318760609471618093">"Scorciatoie"</string>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index c8a3fb9..712c060 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"שמור"</string>
     <string name="menu_share" msgid="3075149983979628146">"שתף"</string>
     <string name="menu_delete" msgid="8138799623850614177">"מחק"</string>
-    <string name="menu_select" msgid="8711270657353563424">"בחר ב-\"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> נבחרו"</string>
     <string name="sort_name" msgid="9183560467917256779">"לפי שם"</string>
     <string name="sort_date" msgid="586080032956151448">"לפי תאריך שינוי"</string>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index 1475005..996496d 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"保存"</string>
     <string name="menu_share" msgid="3075149983979628146">"共有"</string>
     <string name="menu_delete" msgid="8138799623850614177">"削除"</string>
-    <string name="menu_select" msgid="8711270657353563424">"「<xliff:g id="DIRECTORY">^1</xliff:g>」を選択"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g>件選択済み"</string>
     <string name="sort_name" msgid="9183560467917256779">"名前順"</string>
     <string name="sort_date" msgid="586080032956151448">"更新日順"</string>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index c90768f..f3e1274 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"შენახვა"</string>
     <string name="menu_share" msgid="3075149983979628146">"გაზიარება"</string>
     <string name="menu_delete" msgid="8138799623850614177">"წაშლა"</string>
-    <string name="menu_select" msgid="8711270657353563424">"„<xliff:g id="DIRECTORY">^1</xliff:g>“-ის არჩევა"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> მონიშნული"</string>
     <string name="sort_name" msgid="9183560467917256779">"სახელით"</string>
     <string name="sort_date" msgid="586080032956151448">"ცვლილების თარიღით"</string>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index e8944ec..e632209 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -20,16 +20,15 @@
     <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>
     <string name="menu_settings" msgid="6008033148948428823">"ការ​កំណត់"</string>
     <string name="menu_open" msgid="432922957274920903">"បើក"</string>
     <string name="menu_save" msgid="2394743337684426338">"រក្សាទុក"</string>
-    <string name="menu_share" msgid="3075149983979628146">"ចែករំលែក"</string>
+    <string name="menu_share" msgid="3075149983979628146">"ចែករំលែក​"</string>
     <string name="menu_delete" msgid="8138799623850614177">"លុប"</string>
-    <string name="menu_select" msgid="8711270657353563424">"ជ្រើស \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"បាន​ជ្រើស <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="sort_name" msgid="9183560467917256779">"តាម​ឈ្មោះ"</string>
     <string name="sort_date" msgid="586080032956151448">"តាម​កាលបរិច្ឆេទ​បាន​កែប្រែ"</string>
@@ -48,7 +47,7 @@
     <string name="pref_advanced_devices" msgid="903257239609301276">"បង្ហាញ​ឧបករណ៍​កម្រិត​ខ្ពស់"</string>
     <string name="pref_file_size" msgid="2826879315743961459">"បង្ហាញ​ទំហំ​ឯកសារ"</string>
     <string name="pref_device_size" msgid="3542106883278997222">"បង្ហាញ​ទំហំ​ឧបករណ៍"</string>
-    <string name="empty" msgid="7858882803708117596">"គ្មានធាតុ"</string>
+    <string name="empty" msgid="7858882803708117596">"គ្មានធាតុ​"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"មិន​អាច​បើក​ឯកសារ"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"មិន​អាច​លុប​ឯកសារ​មួយ​ចំនួន"</string>
     <string name="share_via" msgid="8966594246261344259">"ចែករំលែក​តាម"</string>
diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml
index 5996e66..2cd0d44 100644
--- a/packages/DocumentsUI/res/values-ko/strings.xml
+++ b/packages/DocumentsUI/res/values-ko/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"저장"</string>
     <string name="menu_share" msgid="3075149983979628146">"공유"</string>
     <string name="menu_delete" msgid="8138799623850614177">"삭제"</string>
-    <string name="menu_select" msgid="8711270657353563424">"\'<xliff:g id="DIRECTORY">^1</xliff:g>\' 선택"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g>개 선택됨"</string>
     <string name="sort_name" msgid="9183560467917256779">"이름순"</string>
     <string name="sort_date" msgid="586080032956151448">"수정된 날짜순"</string>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index 8452ae1..9a6f32f 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"ບັນທຶກ"</string>
     <string name="menu_share" msgid="3075149983979628146">"ແບ່ງປັນ"</string>
     <string name="menu_delete" msgid="8138799623850614177">"ລຶບ"</string>
-    <string name="menu_select" msgid="8711270657353563424">"ເລືອກ​ \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"ເລືອກແລ້ວ <xliff:g id="COUNT">%1$d</xliff:g> ລາຍການ"</string>
     <string name="sort_name" msgid="9183560467917256779">"ຕາມຊື່"</string>
     <string name="sort_date" msgid="586080032956151448">"ຕາມວັນທີທີ່ແກ້ໄຂ"</string>
diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml
index 8ec3e0b..f861b99 100644
--- a/packages/DocumentsUI/res/values-lt/strings.xml
+++ b/packages/DocumentsUI/res/values-lt/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Išsaugoti"</string>
     <string name="menu_share" msgid="3075149983979628146">"Bendrinti"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Ištrinti"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Pasirinkti katalogą „<xliff:g id="DIRECTORY">^1</xliff:g>“"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"Pasirinkta: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="sort_name" msgid="9183560467917256779">"Pagal pavadinimą"</string>
     <string name="sort_date" msgid="586080032956151448">"Pagal keitimo datą"</string>
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index caaf8ec..651a59fe0d 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Saglabāt"</string>
     <string name="menu_share" msgid="3075149983979628146">"Kopīgot"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Dzēst"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Atlasīt “<xliff:g id="DIRECTORY">^1</xliff:g>”"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"Atlasīts: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="sort_name" msgid="9183560467917256779">"Pēc nosaukuma"</string>
     <string name="sort_date" msgid="586080032956151448">"Pēc pārveidošanas datuma"</string>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
index 3d90cc1..22c9fcd 100644
--- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml
+++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Хадгалах"</string>
     <string name="menu_share" msgid="3075149983979628146">"Хуваалцах"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Устгах"</string>
-    <string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\"-г сонгох"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> сонгогдсон"</string>
     <string name="sort_name" msgid="9183560467917256779">"Нэрээр"</string>
     <string name="sort_date" msgid="586080032956151448">"Өөрчлөгдсөн огноогоор"</string>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index 9ea7119..7e09c57 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Simpan"</string>
     <string name="menu_share" msgid="3075149983979628146">"Kongsi"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Padam"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Pilih \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> dipilih"</string>
     <string name="sort_name" msgid="9183560467917256779">"Mengikut nama"</string>
     <string name="sort_date" msgid="586080032956151448">"Diubah suai mengikut tarikh"</string>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index 492fde7..8831bd8 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Lagre"</string>
     <string name="menu_share" msgid="3075149983979628146">"Del"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Slett"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Velg <xliff:g id="DIRECTORY">^1</xliff:g>"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> valgt"</string>
     <string name="sort_name" msgid="9183560467917256779">"Etter navn"</string>
     <string name="sort_date" msgid="586080032956151448">"«Etter dato» endret"</string>
diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml
index a8cf114..08862e8 100644
--- a/packages/DocumentsUI/res/values-nl/strings.xml
+++ b/packages/DocumentsUI/res/values-nl/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Opslaan"</string>
     <string name="menu_share" msgid="3075149983979628146">"Delen"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Verwijderen"</string>
-    <string name="menu_select" msgid="8711270657353563424">"<xliff:g id="DIRECTORY">^1</xliff:g> selecteren"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> geselecteerd"</string>
     <string name="sort_name" msgid="9183560467917256779">"Op naam"</string>
     <string name="sort_date" msgid="586080032956151448">"Op aanpassingsdatum"</string>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index ead40e9..f4e5582 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Zapisz"</string>
     <string name="menu_share" msgid="3075149983979628146">"Udostępnij"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Usuń"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Zaznacz „<xliff:g id="DIRECTORY">^1</xliff:g>”"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"Wybrano: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="sort_name" msgid="9183560467917256779">"Według nazwy"</string>
     <string name="sort_date" msgid="586080032956151448">"Według daty edycji"</string>
@@ -45,8 +44,8 @@
     <string name="root_type_shortcut" msgid="3318760609471618093">"Skróty"</string>
     <string name="root_type_device" msgid="7121342474653483538">"Urządzenia"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Więcej aplikacji"</string>
-    <string name="pref_advanced_devices" msgid="903257239609301276">"Pokaż urządzenia zaawansowane"</string>
-    <string name="pref_file_size" msgid="2826879315743961459">"Pokaż rozmiar pliku"</string>
+    <string name="pref_advanced_devices" msgid="903257239609301276">"Wyświetl urządzenia zaawansowane"</string>
+    <string name="pref_file_size" msgid="2826879315743961459">"Wyświetl rozmiar pliku"</string>
     <string name="pref_device_size" msgid="3542106883278997222">"Wyświetl rozmiar urządzenia"</string>
     <string name="empty" msgid="7858882803708117596">"Brak elementów"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Nie można otworzyć pliku"</string>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index 0003c05..1c1ba8b 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Guardar"</string>
     <string name="menu_share" msgid="3075149983979628146">"Partilhar"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Selecionar \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selecionado(s)"</string>
     <string name="sort_name" msgid="9183560467917256779">"Por nome"</string>
     <string name="sort_date" msgid="586080032956151448">"Por data de modificação"</string>
@@ -45,7 +44,7 @@
     <string name="root_type_shortcut" msgid="3318760609471618093">"Atalhos"</string>
     <string name="root_type_device" msgid="7121342474653483538">"Dispositivos"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Mais aplicações"</string>
-    <string name="pref_advanced_devices" msgid="903257239609301276">"Ver dispositivos avançados"</string>
+    <string name="pref_advanced_devices" msgid="903257239609301276">"Apresentar dispositivos avançados"</string>
     <string name="pref_file_size" msgid="2826879315743961459">"Apresentar tamanho do ficheiro"</string>
     <string name="pref_device_size" msgid="3542106883278997222">"Apresentar tamanho do dispositivo"</string>
     <string name="empty" msgid="7858882803708117596">"Sem itens"</string>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index 4a5c72a..78fcaf8 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Salvar"</string>
     <string name="menu_share" msgid="3075149983979628146">"Compartilhar"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Excluir"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Selecionar \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selecionados"</string>
     <string name="sort_name" msgid="9183560467917256779">"Por nome"</string>
     <string name="sort_date" msgid="586080032956151448">"Por data de modificação"</string>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index 0dfa11d4..5fd44c8 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Salvați"</string>
     <string name="menu_share" msgid="3075149983979628146">"Distribuiți"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Ștergeți"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Selectați „<xliff:g id="DIRECTORY">^1</xliff:g>”"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selectate"</string>
     <string name="sort_name" msgid="9183560467917256779">"După nume"</string>
     <string name="sort_date" msgid="586080032956151448">"După data modificării"</string>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index f86a4af..85fd70e0 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Сохранить"</string>
     <string name="menu_share" msgid="3075149983979628146">"Поделиться"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Удалить"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Выбрать папку \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"Выбрано: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="sort_name" msgid="9183560467917256779">"По названию"</string>
     <string name="sort_date" msgid="586080032956151448">"По дате изменения"</string>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index 5d03df6..2a96b1a 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Uložiť"</string>
     <string name="menu_share" msgid="3075149983979628146">"Zdieľať"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Odstrániť"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Vyberte adresár <xliff:g id="DIRECTORY">^1</xliff:g>"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"Vybraté: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="sort_name" msgid="9183560467917256779">"Podľa názvu"</string>
     <string name="sort_date" msgid="586080032956151448">"Podľa dátumu zmeny"</string>
@@ -45,7 +44,7 @@
     <string name="root_type_shortcut" msgid="3318760609471618093">"Skratky"</string>
     <string name="root_type_device" msgid="7121342474653483538">"Zariadenia"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Ďalšie aplikácie"</string>
-    <string name="pref_advanced_devices" msgid="903257239609301276">"Zobraziť pokročilé zariadenia"</string>
+    <string name="pref_advanced_devices" msgid="903257239609301276">"Zobraziť rozšírené zariadenia"</string>
     <string name="pref_file_size" msgid="2826879315743961459">"Zobraziť veľkosť súboru"</string>
     <string name="pref_device_size" msgid="3542106883278997222">"Zobraziť veľkosť zariadenia"</string>
     <string name="empty" msgid="7858882803708117596">"Žiadne položky"</string>
diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml
index b3e52dd43..f984a0a 100644
--- a/packages/DocumentsUI/res/values-sl/strings.xml
+++ b/packages/DocumentsUI/res/values-sl/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Shrani"</string>
     <string name="menu_share" msgid="3075149983979628146">"Skupna raba"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Izbriši"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Izbira mape »<xliff:g id="DIRECTORY">^1</xliff:g>«"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"Št. izbranih: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="sort_name" msgid="9183560467917256779">"Po imenu"</string>
     <string name="sort_date" msgid="586080032956151448">"Po datumu spremembe"</string>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index 892dbce..eb0b197 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Сачувај"</string>
     <string name="menu_share" msgid="3075149983979628146">"Дели"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Избриши"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Изабери „<xliff:g id="DIRECTORY">^1</xliff:g>“"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"Изабрано је <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="sort_name" msgid="9183560467917256779">"Према имену"</string>
     <string name="sort_date" msgid="586080032956151448">"Према датуму измене"</string>
diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml
index fd6457d..7aa5c50 100644
--- a/packages/DocumentsUI/res/values-sv/strings.xml
+++ b/packages/DocumentsUI/res/values-sv/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Spara"</string>
     <string name="menu_share" msgid="3075149983979628146">"Dela"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Ta bort"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Välj <xliff:g id="DIRECTORY">^1</xliff:g>"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"Har valt <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="sort_name" msgid="9183560467917256779">"Efter namn"</string>
     <string name="sort_date" msgid="586080032956151448">"Efter ändringsdatum"</string>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index 0948c71..299fda7 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Hifadhi"</string>
     <string name="menu_share" msgid="3075149983979628146">"Shiriki"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Futa"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Chagua \" <xliff:g id="DIRECTORY">^1</xliff:g> \""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> zimechaguliwa"</string>
     <string name="sort_name" msgid="9183560467917256779">"Kwa jina"</string>
     <string name="sort_date" msgid="586080032956151448">"Kwa tarehe viliporekebishwa"</string>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index 4bf3e4f..6ac8810 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"บันทึก"</string>
     <string name="menu_share" msgid="3075149983979628146">"แชร์"</string>
     <string name="menu_delete" msgid="8138799623850614177">"ลบ"</string>
-    <string name="menu_select" msgid="8711270657353563424">"เลือก \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"เลือกไว้ <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="sort_name" msgid="9183560467917256779">"ตามชื่อ"</string>
     <string name="sort_date" msgid="586080032956151448">"ตามวันที่ที่ปรับเปลี่ยน"</string>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index 8ef8aa5..e0fd8c8 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"I-save"</string>
     <string name="menu_share" msgid="3075149983979628146">"Ibahagi"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Tanggalin"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Piliin ang \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> ang pinili"</string>
     <string name="sort_name" msgid="9183560467917256779">"Ayon sa pangalan"</string>
     <string name="sort_date" msgid="586080032956151448">"Ayon sa petsa ng pagbago"</string>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index 93586d0..699a5cd 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Kaydet"</string>
     <string name="menu_share" msgid="3075149983979628146">"Paylaş"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Sil"</string>
-    <string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" dizinini seç"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> tane seçildi"</string>
     <string name="sort_name" msgid="9183560467917256779">"Ada göre"</string>
     <string name="sort_date" msgid="586080032956151448">"Değişiklik tarihine göre"</string>
diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml
index 8f8865b..f87b6a2 100644
--- a/packages/DocumentsUI/res/values-uk/strings.xml
+++ b/packages/DocumentsUI/res/values-uk/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Зберегти"</string>
     <string name="menu_share" msgid="3075149983979628146">"Поділитися"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Видалити"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Вибрати каталог \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"Вибрано <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="sort_name" msgid="9183560467917256779">"За назвою"</string>
     <string name="sort_date" msgid="586080032956151448">"За датою змінення"</string>
diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml
index 8b8ff1f..41e29fa 100644
--- a/packages/DocumentsUI/res/values-vi/strings.xml
+++ b/packages/DocumentsUI/res/values-vi/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Lưu"</string>
     <string name="menu_share" msgid="3075149983979628146">"Chia sẻ"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Xóa"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Chọn \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"Đã chọn <xliff:g id="COUNT">%1$d</xliff:g>"</string>
     <string name="sort_name" msgid="9183560467917256779">"Theo tên"</string>
     <string name="sort_date" msgid="586080032956151448">"Theo ngày sửa đổi"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index 68ab5f8..742cda7 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"保存"</string>
     <string name="menu_share" msgid="3075149983979628146">"分享"</string>
     <string name="menu_delete" msgid="8138799623850614177">"删除"</string>
-    <string name="menu_select" msgid="8711270657353563424">"选择“<xliff:g id="DIRECTORY">^1</xliff:g>”"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"已选择<xliff:g id="COUNT">%1$d</xliff:g>项"</string>
     <string name="sort_name" msgid="9183560467917256779">"按名称"</string>
     <string name="sort_date" msgid="586080032956151448">"按修改日期"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index afd8b63..67ed587 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"儲存"</string>
     <string name="menu_share" msgid="3075149983979628146">"分享"</string>
     <string name="menu_delete" msgid="8138799623850614177">"刪除"</string>
-    <string name="menu_select" msgid="8711270657353563424">"選取「<xliff:g id="DIRECTORY">^1</xliff:g>」"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"已選取 <xliff:g id="COUNT">%1$d</xliff:g> 個"</string>
     <string name="sort_name" msgid="9183560467917256779">"按名稱"</string>
     <string name="sort_date" msgid="586080032956151448">"按修改日期"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
index 2e77f21..269583a 100644
--- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
@@ -17,7 +17,7 @@
 <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="2783841764617238354">"文件"</string>
-    <string name="title_open" msgid="4353228937663917801">"開啟檔案"</string>
+    <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>
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"儲存"</string>
     <string name="menu_share" msgid="3075149983979628146">"共用"</string>
     <string name="menu_delete" msgid="8138799623850614177">"刪除"</string>
-    <string name="menu_select" msgid="8711270657353563424">"選取「<xliff:g id="DIRECTORY">^1</xliff:g>」"</string>
     <string name="mode_selected_count" msgid="459111894725594625">"已選取 <xliff:g id="COUNT">%1$d</xliff:g> 個項目"</string>
     <string name="sort_name" msgid="9183560467917256779">"依名稱"</string>
     <string name="sort_date" msgid="586080032956151448">"依修改日期"</string>
@@ -39,7 +38,7 @@
     <string name="save_error" msgid="6167009778003223664">"無法儲存文件"</string>
     <string name="create_error" msgid="3735649141335444215">"無法建立資料夾"</string>
     <string name="query_error" msgid="1222448261663503501">"無法查詢文件"</string>
-    <string name="root_recent" msgid="4470053704320518133">"最近存取過"</string>
+    <string name="root_recent" msgid="4470053704320518133">"最近使用過的項目"</string>
     <string name="root_available_bytes" msgid="8568452858617033281">"可用空間:<xliff:g id="SIZE">%1$s</xliff:g>"</string>
     <string name="root_type_service" msgid="2178854894416775409">"儲存空間服務"</string>
     <string name="root_type_shortcut" msgid="3318760609471618093">"捷徑"</string>
@@ -48,7 +47,7 @@
     <string name="pref_advanced_devices" msgid="903257239609301276">"顯示進階裝置"</string>
     <string name="pref_file_size" msgid="2826879315743961459">"顯示檔案大小"</string>
     <string name="pref_device_size" msgid="3542106883278997222">"顯示裝置大小"</string>
-    <string name="empty" msgid="7858882803708117596">"沒有任何項目"</string>
+    <string name="empty" msgid="7858882803708117596">"沒有項目"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"無法開啟檔案"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"無法刪除部分文件"</string>
     <string name="share_via" msgid="8966594246261344259">"分享方式:"</string>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index 55e2c75..bedd2cdf 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -29,7 +29,6 @@
     <string name="menu_save" msgid="2394743337684426338">"Londoloza"</string>
     <string name="menu_share" msgid="3075149983979628146">"Yabelana"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Susa"</string>
-    <string name="menu_select" msgid="8711270657353563424">"Khetha i-\"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
     <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> okukhethiwe"</string>
     <string name="sort_name" msgid="9183560467917256779">"Ngegama"</string>
     <string name="sort_date" msgid="586080032956151448">"Ngedethi yokuguqula"</string>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index b2b2bd8..9069a55 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -436,6 +436,8 @@
         @Override
         public boolean onCreateActionMode(ActionMode mode, Menu menu) {
             mode.getMenuInflater().inflate(R.menu.mode_directory, menu);
+            mode.setTitle(getResources()
+                    .getString(R.string.mode_selected_count, mCurrentView.getCheckedItemCount()));
             return true;
         }
 
diff --git a/packages/ExternalStorageProvider/res/values-sk/strings.xml b/packages/ExternalStorageProvider/res/values-sk/strings.xml
index 9be7b79..fd424c8 100644
--- a/packages/ExternalStorageProvider/res/values-sk/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sk/strings.xml
@@ -17,6 +17,6 @@
 <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="7123375275748530234">"Externý ukladací priestor"</string>
-    <string name="root_internal_storage" msgid="827844243068584127">"Interné úložisko"</string>
+    <string name="root_internal_storage" msgid="827844243068584127">"Interný ukladací priestor"</string>
     <string name="root_documents" msgid="4051252304075469250">"Dokumenty"</string>
 </resources>
diff --git a/packages/FusedLocation/res/values-fr-rCA/strings.xml b/packages/FusedLocation/res/values-fr-rCA/strings.xml
index c7d33af..0d2cccc 100644
--- a/packages/FusedLocation/res/values-fr-rCA/strings.xml
+++ b/packages/FusedLocation/res/values-fr-rCA/strings.xml
@@ -1,5 +1,5 @@
 <?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="app_label" msgid="5379477904423203699">"Tables de fusion"</string>
+    <string name="app_label" msgid="5379477904423203699">"Fused Location"</string>
 </resources>
diff --git a/packages/InputDevices/res/raw/keyboard_layout_czech.kcm b/packages/InputDevices/res/raw/keyboard_layout_czech.kcm
index f710a8e..dc614db 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_czech.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_czech.kcm
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 #
-# Czech keyboard layout.
+# Czech (EU - qwerty) keyboard layout.
 #
 
 type OVERLAY
@@ -26,6 +26,8 @@
     label:                              ';'
     base:                               ';'
     shift:                              '\u00b0'
+    ralt:                               '\u0060'
+    shift+ralt:                         '\u007e'
 }
 
 key 1 {
@@ -38,6 +40,7 @@
 key 2 {
     label:                              '2'
     base:                               '\u011b'
+    capslock:                           '\u011a'
     shift:                              '2'
     ralt:                               '@'
 }
@@ -45,6 +48,7 @@
 key 3 {
     label:                              '3'
     base:                               '\u0161'
+    capslock:                           '\u0160'
     shift:                              '3'
     ralt:                               '#'
 }
@@ -52,6 +56,7 @@
 key 4 {
     label:                              '4'
     base:                               '\u010d'
+    capslock:                           '\u010c'
     shift:                              '4'
     ralt:                               '$'
 }
@@ -59,6 +64,7 @@
 key 5 {
     label:                              '5'
     base:                               '\u0159'
+    capslock:                           '\u0158'
     shift:                              '5'
     ralt:                               '%'
 }
@@ -66,6 +72,7 @@
 key 6 {
     label:                              '6'
     base:                               '\u017e'
+    capslock:                           '\u017d'
     shift:                              '6'
     ralt:                               '^'
 }
@@ -73,6 +80,7 @@
 key 7 {
     label:                              '7'
     base:                               '\u00fd'
+    capslock:                           '\u00dd'
     shift:                              '7'
     ralt:                               '&'
 }
@@ -80,6 +88,7 @@
 key 8 {
     label:                              '8'
     base:                               '\u00e1'
+    capslock:                           '\u00c1'
     shift:                              '8'
     ralt:                               '*'
 }
@@ -87,6 +96,7 @@
 key 9 {
     label:                              '9'
     base:                               '\u00ed'
+    capslock:                           '\u00cd'
     shift:                              '9'
     ralt:                               '('
 }
@@ -94,6 +104,7 @@
 key 0 {
     label:                              '0'
     base:                               '\u00e9'
+    capslock:                           '\u00c9'
     shift:                              '0'
     ralt:                               ')'
 }
@@ -180,6 +191,7 @@
 key LEFT_BRACKET {
     label:                              '\u00fa'
     base:                               '\u00fa'
+    capslock:                           '\u00da'
     shift:                              '/'
     ralt:                               '['
     ralt+shift:                         '{'
@@ -252,6 +264,7 @@
 key SEMICOLON {
     label:                              '\u016f'
     base:                               '\u016f'
+    capslock:                           '\u016e'
     shift:                              '"'
     ralt:                               ';'
     ralt+shift:                         ':'
@@ -261,8 +274,8 @@
     label:                              '\u00a7'
     base:                               '\u00a7'
     shift:                              '!'
-    ralt:                               '\''
-    ralt+shift:                         '"'
+    ralt:                               '\u00a4'
+    ralt+shift:                         '\u005e'
 }
 
 key BACKSLASH {
@@ -279,6 +292,8 @@
     label:                              '\\'
     base:                               '\\'
     shift:                              '|'
+    ralt:                               '\u00df'
+    shift+ralt:                         '\u02dd'
 }
 
 key Z {
@@ -330,6 +345,7 @@
     base:                               ','
     shift:                              '?'
     ralt:                               '<'
+    shift+ralt:                         '\u00d7'
 }
 
 key PERIOD {
@@ -337,6 +353,7 @@
     base:                               '.'
     shift:                              ':'
     ralt:                               '>'
+    shift+ralt:                         '\u00f7'
 }
 
 key SLASH {
diff --git a/packages/InputDevices/res/raw/keyboard_layout_english_us_intl.kcm b/packages/InputDevices/res/raw/keyboard_layout_english_us_intl.kcm
index 0fabf02..66c1c98 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_english_us_intl.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_english_us_intl.kcm
@@ -122,7 +122,7 @@
     base:                               'q'
     shift, capslock:                    'Q'
     ralt:                               '\u00e4'
-    shift+ralt:                         '\u00c4'
+    shift+ralt, capslock+ralt:          '\u00c4'
 }
 
 key W {
@@ -130,7 +130,7 @@
     base:                               'w'
     shift, capslock:                    'W'
     ralt:                               '\u00e5'
-    shift+ralt:                         '\u00c5'
+    shift+ralt, capslock+ralt:          '\u00c5'
 }
 
 key E {
@@ -138,7 +138,7 @@
     base:                               'e'
     shift, capslock:                    'E'
     ralt:                               '\u00e9'
-    shift+ralt:                         '\u00c9'
+    shift+ralt, capslock+ralt:          '\u00c9'
 }
 
 key R {
@@ -153,7 +153,7 @@
     base:                               't'
     shift, capslock:                    'T'
     ralt:                               '\u00fe'
-    shift+ralt:                         '\u00de'
+    shift+ralt, capslock+ralt:          '\u00de'
 }
 
 key Y {
@@ -161,7 +161,7 @@
     base:                               'y'
     shift, capslock:                    'Y'
     ralt:                               '\u00fc'
-    shift+ralt:                         '\u00dc'
+    shift+ralt, capslock+ralt:          '\u00dc'
 }
 
 key U {
@@ -169,7 +169,7 @@
     base:                               'u'
     shift, capslock:                    'U'
     ralt:                               '\u00fa'
-    shift+ralt:                         '\u00da'
+    shift+ralt, capslock+ralt:          '\u00da'
 }
 
 key I {
@@ -177,7 +177,7 @@
     base:                               'i'
     shift, capslock:                    'I'
     ralt:                               '\u00ed'
-    shift+ralt:                         '\u00cd'
+    shift+ralt, capslock+ralt:          '\u00cd'
 }
 
 key O {
@@ -185,7 +185,7 @@
     base:                               'o'
     shift, capslock:                    'O'
     ralt:                               '\u00f3'
-    shift+ralt:                         '\u00d3'
+    shift+ralt, capslock+ralt:          '\u00d3'
 }
 
 key P {
@@ -193,7 +193,7 @@
     base:                               'p'
     shift, capslock:                    'P'
     ralt:                               '\u00f6'
-    shift+ralt:                         '\u00d6'
+    shift+ralt, capslock+ralt:          '\u00d6'
 }
 
 key LEFT_BRACKET {
@@ -225,7 +225,7 @@
     base:                               'a'
     shift, capslock:                    'A'
     ralt:                               '\u00e1'
-    shift+ralt:                         '\u00c1'
+    shift+ralt, ralt+capslock:          '\u00c1'
 }
 
 key S {
@@ -241,7 +241,7 @@
     base:                               'd'
     shift, capslock:                    'D'
     ralt:                               '\u00f0'
-    shift+ralt:                         '\u00d0'
+    shift+ralt, capslock+ralt:          '\u00d0'
 }
 
 key F {
@@ -279,7 +279,7 @@
     base:                               'l'
     shift, capslock:                    'L'
     ralt:                               '\u00f8'
-    shift+ralt:                         '\u00d8'
+    shift+ralt, capslock+ralt:          '\u00d8'
 }
 
 key SEMICOLON {
@@ -313,7 +313,7 @@
     base:                               'z'
     shift, capslock:                    'Z'
     ralt:                               '\u00e6'
-    shift+ralt:                         '\u00c6'
+    shift+ralt, capslock+ralt:          '\u00c6'
 }
 
 key X {
@@ -347,7 +347,7 @@
     base:                               'n'
     shift, capslock:                    'N'
     ralt:                               '\u00f1'
-    shift+ralt:                         '\u00d1'
+    shift+ralt, capslock+ralt:          '\u00d1'
 }
 
 key M {
@@ -362,7 +362,7 @@
     base:                               ','
     shift:                              '<'
     ralt:                               '\u00e7'
-    shift+ralt:                         '\u00c7'
+    shift+ralt, capslock+ralt:          '\u00c7'
 }
 
 key PERIOD {
diff --git a/packages/InputDevices/res/raw/keyboard_layout_slovak.kcm b/packages/InputDevices/res/raw/keyboard_layout_slovak.kcm
index 70c1fa4..2eb0f63 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_slovak.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_slovak.kcm
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 #
-# Slovak keyboard layout.
+# Slovak (EU - qwerty) keyboard layout.
 #
 
 type OVERLAY
@@ -26,94 +26,90 @@
     label:                              ';'
     base:                               ';'
     shift:                              '\u00b0'
-    ralt:                               '`'
-    ralt+shift:                         '~'
 }
 
 key 1 {
     label:                              '1'
     base:                               '+'
     shift:                              '1'
-    ralt:                               '!'
+    ralt:                               '~'
 }
 
 key 2 {
     label:                              '2'
     base:                               '\u013e'
     shift:                              '2'
-    ralt:                               '@'
+    ralt:                               '\u02c7'
 }
 
 key 3 {
     label:                              '3'
     base:                               '\u0161'
     shift:                              '3'
-    ralt:                               '#'
+    ralt:                               '\u0302'
 }
 
 key 4 {
     label:                              '4'
     base:                               '\u010d'
     shift:                              '4'
-    ralt:                               '$'
+    ralt:                               '\u02d8'
 }
 
 key 5 {
     label:                              '5'
     base:                               '\u0165'
     shift:                              '5'
-    ralt:                               '%'
+    ralt:                               '\u00b0'
 }
 
 key 6 {
     label:                              '6'
     base:                               '\u017e'
     shift:                              '6'
-    ralt:                               '^'
+    ralt:                               '\u02db'
 }
 
 key 7 {
     label:                              '7'
     base:                               '\u00fd'
     shift:                              '7'
-    ralt:                               '&'
+    ralt:                               '\u0300'
 }
 
 key 8 {
     label:                              '8'
     base:                               '\u00e1'
     shift:                              '8'
-    ralt:                               '*'
+    ralt:                               '\u02d9'
 }
 
 key 9 {
     label:                              '9'
     base:                               '\u00ed'
     shift:                              '9'
-    ralt:                               '('
+    ralt:                               '\u0301'
 }
 
 key 0 {
     label:                              '0'
     base:                               '\u00e9'
     shift:                              '0'
-    ralt:                               ')'
+    ralt:                               '\u02dd'
 }
 
 key MINUS {
     label:                              '='
     base:                               '='
     shift:                              '%'
-    ralt:                               '-'
-    ralt+shift:                         '_'
+    ralt:                               '\u0308'
 }
 
 key EQUALS {
     label:                              '\u00b4'
     base:                               '\u0301'
     shift:                              '\u030c'
-    ralt:                               '='
-    ralt+shift:                         '+'
+    ralt:                               '\u00b8'
 }
 
 ### ROW 2
@@ -179,22 +175,21 @@
     label:                              'P'
     base:                               'p'
     shift, capslock:                    'P'
+    ralt:                               '\''
 }
 
 key LEFT_BRACKET {
     label:                              '\u00fa'
     base:                               '\u00fa'
     shift:                              '/'
-    ralt:                               '['
-    ralt+shift:                         '{'
+    ralt:                               '\u00f7'
 }
 
 key RIGHT_BRACKET {
     label:                              '\u00e4'
     base:                               '\u00e4'
     shift:                              '('
-    ralt:                               ']'
-    ralt+shift:                         '}'
+    ralt:                               '\u00d7'
 }
 
 ### ROW 3
@@ -209,24 +204,28 @@
     label:                              'S'
     base:                               's'
     shift, capslock:                    'S'
+    ralt:                               '\u0111'
 }
 
 key D {
     label:                              'D'
     base:                               'd'
     shift, capslock:                    'D'
+    ralt:                               '\u0110'
 }
 
 key F {
     label:                              'F'
     base:                               'f'
     shift, capslock:                    'F'
+    ralt:                               '['
 }
 
 key G {
     label:                              'G'
     base:                               'g'
     shift, capslock:                    'G'
+    ralt:                               ']'
 }
 
 key H {
@@ -245,64 +244,65 @@
     label:                              'K'
     base:                               'k'
     shift, capslock:                    'K'
+    ralt:                               '\u0142'
 }
 
 key L {
     label:                              'L'
     base:                               'l'
     shift, capslock:                    'L'
+    ralt:                               '\u0141'
 }
 
 key SEMICOLON {
     label:                              '\u00f4'
     base:                               '\u00f4'
     shift:                              '"'
-    ralt:                               ';'
-    ralt+shift:                         ':'
+    ralt:                               '$'
 }
 
 key APOSTROPHE {
     label:                              '\u00a7'
     base:                               '\u00a7'
     shift:                              '!'
-    ralt:                               '\''
-    ralt+shift:                         '"'
+    ralt:                               '\u00df'
 }
 
 key BACKSLASH {
     label:                              '\u0148'
     base:                               '\u0148'
     shift:                              ')'
-    ralt:                               '\\'
-    ralt+shift:                         '|'
+    ralt:                               '\u00a4'
 }
 
 ### ROW 4
 
 key PLUS {
-    label:                              '\\'
-    base:                               '\\'
-    shift:                              '|'
-    ralt:                               '&'
-    ralt+shift:                         '*'
+    label:                              '&'
+    base:                               '&'
+    shift:                              '*'
+    ralt:                               '<'
 }
 
 key Z {
     label:                              'Z'
     base:                               'z'
     shift, capslock:                    'Z'
+    ralt:                               '>'
 }
 
 key X {
     label:                              'X'
     base:                               'x'
     shift, capslock:                    'X'
+    ralt:                               '#'
 }
 
 key C {
     label:                              'C'
     base:                               'c'
     shift, capslock:                    'C'
+    ralt:                               '&'
 }
 
 key V {
@@ -316,12 +316,14 @@
     label:                              'B'
     base:                               'b'
     shift, capslock:                    'B'
+    ralt:                               '{'
 }
 
 key N {
     label:                              'N'
     base:                               'n'
     shift, capslock:                    'N'
+    ralt:                               '}'
 }
 
 key M {
@@ -348,6 +350,5 @@
     label:                              '-'
     base:                               '-'
     shift:                              '_'
-    ralt:                               '/'
-    ralt+shift:                         '?'
+    ralt:                               '*'
 }
diff --git a/packages/InputDevices/res/raw/keyboard_layout_swiss_french.kcm b/packages/InputDevices/res/raw/keyboard_layout_swiss_french.kcm
index a75d154..9e20462 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_swiss_french.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_swiss_french.kcm
@@ -56,12 +56,14 @@
     label:                              '4'
     base:                               '4'
     shift:                              '\u00e7'
+    ralt:                               '\u00b0'
 }
 
 key 5 {
     label:                              '5'
     base:                               '5'
     shift:                              '%'
+    ralt:                               '\u00a7'
 }
 
 key 6 {
diff --git a/packages/InputDevices/res/raw/keyboard_layout_swiss_german.kcm b/packages/InputDevices/res/raw/keyboard_layout_swiss_german.kcm
index ae93f4b..7fbd1a9 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_swiss_german.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_swiss_german.kcm
@@ -56,12 +56,14 @@
     label:                              '4'
     base:                               '4'
     shift:                              '\u00e7'
+    ralt:                               '\u00b0'
 }
 
 key 5 {
     label:                              '5'
     base:                               '5'
     shift:                              '%'
+    ralt:                               '\u00a7'
 }
 
 key 6 {
@@ -178,6 +180,8 @@
     label:                              '\u00fc'
     base:                               '\u00fc'
     shift:                              '\u00e8'
+    capslock:                           '\u00dc'
+    capslock+shift:                     '\u00c8'
     ralt:                               '['
 }
 
@@ -248,12 +252,16 @@
     label:                              '\u00f6'
     base:                               '\u00f6'
     shift:                              '\u00e9'
+    capslock:                           '\u00d6'
+    capslock+shift:                     '\u00c9'
 }
 
 key APOSTROPHE {
     label:                              '\u00e4'
     base:                               '\u00e4'
     shift:                              '\u00e0'
+    capslock:                           '\u00c4'
+    capslock+shift:                     '\u00c0'
     ralt:                               '{'
 }
 
diff --git a/packages/InputDevices/res/values-af/strings.xml b/packages/InputDevices/res/values-af/strings.xml
index ddaf706..13fcbb4 100644
--- a/packages/InputDevices/res/values-af/strings.xml
+++ b/packages/InputDevices/res/values-af/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Sloweens"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turks"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Oekraïens"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabies"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grieks"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreeus"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litaus"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spaans (Latyn)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-am/strings.xml b/packages/InputDevices/res/values-am/strings.xml
index 09b65e0..d475772 100644
--- a/packages/InputDevices/res/values-am/strings.xml
+++ b/packages/InputDevices/res/values-am/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"ስሎቫኒያ"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"ቱርክኛ"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ዩክሬን"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"አረብኛ"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"ግሪክኛ"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"ዕብራስጥ"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"ሊቱዌኒያኛ"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ስፓኒሽ (ላቲን)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ar/strings.xml b/packages/InputDevices/res/values-ar/strings.xml
index 4c5cccc..903d978 100644
--- a/packages/InputDevices/res/values-ar/strings.xml
+++ b/packages/InputDevices/res/values-ar/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"السلوفينية"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"التركية"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"الأوكرانية"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"العربية"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"اليونانية"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"العبرية"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"الليتوانية"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"الإسبانية (اللاتينية)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-bg/strings.xml b/packages/InputDevices/res/values-bg/strings.xml
index cc3eb36..0c413a4 100644
--- a/packages/InputDevices/res/values-bg/strings.xml
+++ b/packages/InputDevices/res/values-bg/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"словенски"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"турски"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"украински"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Арабска клавиатурна подредба"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Гръцка клавиатурна подредба"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Ивритска клавиатурна подредба"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Литовска клавиатурна подредба"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Исп. клав. подредба (Лат. Америка)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ca/strings.xml b/packages/InputDevices/res/values-ca/strings.xml
index 2c8521c..2021b8f 100644
--- a/packages/InputDevices/res/values-ca/strings.xml
+++ b/packages/InputDevices/res/values-ca/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Eslovè"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turc"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraïnès"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Àrab"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grec"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreu"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituà"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espanyol (llatí)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-cs/strings.xml b/packages/InputDevices/res/values-cs/strings.xml
index 9b65eed..33b420e 100644
--- a/packages/InputDevices/res/values-cs/strings.xml
+++ b/packages/InputDevices/res/values-cs/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"slovinské"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"turecké"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukrajinské"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"arabština"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"řečtina"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"hebrejština"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litevština"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"španělština (Latinská Amerika)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-da/strings.xml b/packages/InputDevices/res/values-da/strings.xml
index 8b423ab..fc07db2 100644
--- a/packages/InputDevices/res/values-da/strings.xml
+++ b/packages/InputDevices/res/values-da/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovensk"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Tyrkisk"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainsk"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabisk"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Græsk"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebræisk"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litauisk"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spansk (latinamerika)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-de/strings.xml b/packages/InputDevices/res/values-de/strings.xml
index b5a5870..b5c3b50 100644
--- a/packages/InputDevices/res/values-de/strings.xml
+++ b/packages/InputDevices/res/values-de/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slowenisch"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Türkisch"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainisch"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabisch"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Griechisch"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebräisch"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litauisch"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanisch (Lateinisch)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-el/strings.xml b/packages/InputDevices/res/values-el/strings.xml
index 976f370..f5d57a0 100644
--- a/packages/InputDevices/res/values-el/strings.xml
+++ b/packages/InputDevices/res/values-el/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Σλοβενικά"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Τουρκικά"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ουκρανικά"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Αραβικά"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Ελληνικά"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Εβραϊκά"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Λιθουανικά"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Ισπανικά (Λατινικής Αμερικής)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-en-rGB/strings.xml b/packages/InputDevices/res/values-en-rGB/strings.xml
index 50a98b26..2d794a6 100644
--- a/packages/InputDevices/res/values-en-rGB/strings.xml
+++ b/packages/InputDevices/res/values-en-rGB/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovenian"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turkish"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainian"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabic"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Greek"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrew"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lithuanian"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-en-rIN/strings.xml b/packages/InputDevices/res/values-en-rIN/strings.xml
index 50a98b26..2d794a6 100644
--- a/packages/InputDevices/res/values-en-rIN/strings.xml
+++ b/packages/InputDevices/res/values-en-rIN/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovenian"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turkish"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainian"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabic"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Greek"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrew"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lithuanian"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-es-rUS/strings.xml b/packages/InputDevices/res/values-es-rUS/strings.xml
index b842a3b..2d61b80 100644
--- a/packages/InputDevices/res/values-es-rUS/strings.xml
+++ b/packages/InputDevices/res/values-es-rUS/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Esloveno"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turco"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraniano"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Árabe"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Griego"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreo"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituano"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Español (latino)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-es/strings.xml b/packages/InputDevices/res/values-es/strings.xml
index 5dc85a0..82ea4d6 100644
--- a/packages/InputDevices/res/values-es/strings.xml
+++ b/packages/InputDevices/res/values-es/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Esloveno"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turco"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraniano"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Árabe"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Griego"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreo"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituano"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Español (Latinoamérica)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-et-rEE/strings.xml b/packages/InputDevices/res/values-et-rEE/strings.xml
index 4ffdb37..5b4fa3b 100644
--- a/packages/InputDevices/res/values-et-rEE/strings.xml
+++ b/packages/InputDevices/res/values-et-rEE/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Sloveenia"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Türgi"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukraina"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Araabia"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Kreeka"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Heebrea"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Leedu"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Hispaania (Ladina-Ameerika)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-fa/strings.xml b/packages/InputDevices/res/values-fa/strings.xml
index fd6f54b..06c7f3a 100644
--- a/packages/InputDevices/res/values-fa/strings.xml
+++ b/packages/InputDevices/res/values-fa/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"اسلوونیایی"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"ترکی"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"اوکراینی"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"عربی"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"یونانی"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"عبری"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"لیتوانیایی"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"اسپانیایی (لاتین)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-fi/strings.xml b/packages/InputDevices/res/values-fi/strings.xml
index b7ec183..428eb30 100644
--- a/packages/InputDevices/res/values-fi/strings.xml
+++ b/packages/InputDevices/res/values-fi/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"sloveeni"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"turkki"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukraina"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"arabia"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"kreikka"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"heprea"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"liettua"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"espanja (Latinalainen Amerikka)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-fr-rCA/strings.xml b/packages/InputDevices/res/values-fr-rCA/strings.xml
index 18600ed..c947634 100644
--- a/packages/InputDevices/res/values-fr-rCA/strings.xml
+++ b/packages/InputDevices/res/values-fr-rCA/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovène"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turc"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainien"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabe"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grec"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hébreu"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituanien"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espagnol (latin)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-fr/strings.xml b/packages/InputDevices/res/values-fr/strings.xml
index e3ca49c..4ad4ffa 100644
--- a/packages/InputDevices/res/values-fr/strings.xml
+++ b/packages/InputDevices/res/values-fr/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovène"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turc"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainien"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabe"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grec"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hébreu"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituanien"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espagnol (latin)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-hi/strings.xml b/packages/InputDevices/res/values-hi/strings.xml
index a1a4ef2..8e1864e 100644
--- a/packages/InputDevices/res/values-hi/strings.xml
+++ b/packages/InputDevices/res/values-hi/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"स्लोवेनियाई"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"तुर्की"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"यूक्रेनियाई"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"अरबी"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"ग्रीक"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"हिब्रू"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"लिथुआनियाई"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"स्पेनिश (लैटिन)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-hr/strings.xml b/packages/InputDevices/res/values-hr/strings.xml
index 512ffd7..6217bf0 100644
--- a/packages/InputDevices/res/values-hr/strings.xml
+++ b/packages/InputDevices/res/values-hr/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"slovenska"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"turska"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukrajinska"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"arapski"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"grčki"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"hebrejski"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litavski"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"španjolski (Latinska Amerika)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-hu/strings.xml b/packages/InputDevices/res/values-hu/strings.xml
index 645e597..0cdbfb2 100644
--- a/packages/InputDevices/res/values-hu/strings.xml
+++ b/packages/InputDevices/res/values-hu/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"szlovén"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"török"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukrán"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"arab"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"görög"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"héber"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litván"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"spanyol (latin-amerikai)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-hy-rAM/strings.xml b/packages/InputDevices/res/values-hy-rAM/strings.xml
index 282dc82..bc5bbfc 100644
--- a/packages/InputDevices/res/values-hy-rAM/strings.xml
+++ b/packages/InputDevices/res/values-hy-rAM/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Սլովեներեն"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Թուրքերեն"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ուկրաիներեն"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Արաբերեն"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Հունարեն"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Եբրայերեն"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Լիտվերեն"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Իսպաներեն (Լատինական)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-in/strings.xml b/packages/InputDevices/res/values-in/strings.xml
index a7fc330..11e2dd0a 100644
--- a/packages/InputDevices/res/values-in/strings.xml
+++ b/packages/InputDevices/res/values-in/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovenia"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turki"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukraina"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arab"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Yunani"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Ibrani"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lithuania"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanyol (Latin)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-it/strings.xml b/packages/InputDevices/res/values-it/strings.xml
index e8fe310..334318e 100644
--- a/packages/InputDevices/res/values-it/strings.xml
+++ b/packages/InputDevices/res/values-it/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Sloveno"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turco"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraino"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabo"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Greco"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Ebraico"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituano"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spagnolo (America Latina)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-iw/strings.xml b/packages/InputDevices/res/values-iw/strings.xml
index d2673d9..a989391 100644
--- a/packages/InputDevices/res/values-iw/strings.xml
+++ b/packages/InputDevices/res/values-iw/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"סלובנית"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"טורקית"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"אוקראינית"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"ערבית"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"יוונית"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"עברית"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"ליטאית"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ספרדית (לטינית)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ja/strings.xml b/packages/InputDevices/res/values-ja/strings.xml
index 86cd30e..950b727 100644
--- a/packages/InputDevices/res/values-ja/strings.xml
+++ b/packages/InputDevices/res/values-ja/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"スロベニア語"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"トルコ語"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ウクライナ語"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"アラビア語"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"ギリシャ語"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"ヘブライ語"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"リトアニア語"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"スペイン語(中南米)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ka-rGE/strings.xml b/packages/InputDevices/res/values-ka-rGE/strings.xml
index 14ebee8..6e507aa 100644
--- a/packages/InputDevices/res/values-ka-rGE/strings.xml
+++ b/packages/InputDevices/res/values-ka-rGE/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"სლოვენური"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"თურქული"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"უკრაინული"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"არაბული"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"ბერძნული"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"ებრაული"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"ლიტვური"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ესპანური (ლათინური)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-km-rKH/strings.xml b/packages/InputDevices/res/values-km-rKH/strings.xml
index 569f273..9a8c99b 100644
--- a/packages/InputDevices/res/values-km-rKH/strings.xml
+++ b/packages/InputDevices/res/values-km-rKH/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"ស្លូវ៉ានី"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"ទួរគី"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"អ៊ុយក្រែន"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"អារ៉ាប់"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"ក្រិក"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"អ៊ីស្រាអែល"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"លីទុយអានី"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"អេស្ប៉ាញ (ឡាតាំង​)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ko/strings.xml b/packages/InputDevices/res/values-ko/strings.xml
index dbbe6ea..8071586 100644
--- a/packages/InputDevices/res/values-ko/strings.xml
+++ b/packages/InputDevices/res/values-ko/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"슬로베니아어"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"터키어"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"우크라이나어"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"아랍어"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"그리스어"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"히브리어"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"리투아니아어"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"스페인어(라틴)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-lo-rLA/strings.xml b/packages/InputDevices/res/values-lo-rLA/strings.xml
index eaf5026..2c97e11 100644
--- a/packages/InputDevices/res/values-lo-rLA/strings.xml
+++ b/packages/InputDevices/res/values-lo-rLA/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"ສະໂລເວນຽນ"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"ເຕີກິສ"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ຢູເຄຣນຽນ"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"ອາຣັບ"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"ກ​ຣີກ"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"ຮີບຣິວ"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"​ລິ​ທົວ​ນຽນ"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"​ສະ​ແປນ​ນິດ (ລາ​ຕິນ)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-lt/strings.xml b/packages/InputDevices/res/values-lt/strings.xml
index 2fcacde..c0ed159 100644
--- a/packages/InputDevices/res/values-lt/strings.xml
+++ b/packages/InputDevices/res/values-lt/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovėnų k."</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turkų k."</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainiečių k."</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabų"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Graikų"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrajų"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lietuvių"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Ispanų (Lotynų Amerika)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-lv/strings.xml b/packages/InputDevices/res/values-lv/strings.xml
index 921c881..07a8654 100644
--- a/packages/InputDevices/res/values-lv/strings.xml
+++ b/packages/InputDevices/res/values-lv/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovēņu"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turku"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukraiņu"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arābu"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grieķu"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Ivrits"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lietuviešu"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spāņu (latīņu)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-mn-rMN/strings.xml b/packages/InputDevices/res/values-mn-rMN/strings.xml
index c99339e..ec6cccb 100644
--- a/packages/InputDevices/res/values-mn-rMN/strings.xml
+++ b/packages/InputDevices/res/values-mn-rMN/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Словени"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Турк"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Украйн"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Араб"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Грек"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Еврей"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Литви"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Испани (Латин)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ms-rMY/strings.xml b/packages/InputDevices/res/values-ms-rMY/strings.xml
index 32041d0..486f048 100644
--- a/packages/InputDevices/res/values-ms-rMY/strings.xml
+++ b/packages/InputDevices/res/values-ms-rMY/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Bahasa Slovenia"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Bahasa Turki"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Bahasa Ukraine"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Bahasa Arab"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Bahasa Greek"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Bahasa Ibrani"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Bahasa Lithuania"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Bahasa Sepanyol (Latin)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-nb/strings.xml b/packages/InputDevices/res/values-nb/strings.xml
index e880981..b646061 100644
--- a/packages/InputDevices/res/values-nb/strings.xml
+++ b/packages/InputDevices/res/values-nb/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovensk"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Tyrkisk"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainsk"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabisk"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Gresk"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebraisk"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litauisk"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spansk (latinsk)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-nl/strings.xml b/packages/InputDevices/res/values-nl/strings.xml
index 92a9fcf..56d84c9 100644
--- a/packages/InputDevices/res/values-nl/strings.xml
+++ b/packages/InputDevices/res/values-nl/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Sloveens"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turks"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Oekraïens"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabisch"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grieks"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreeuws"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litouws"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spaans (Latijns-Amerika)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-pl/strings.xml b/packages/InputDevices/res/values-pl/strings.xml
index f84252a..4522215 100644
--- a/packages/InputDevices/res/values-pl/strings.xml
+++ b/packages/InputDevices/res/values-pl/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Słoweński"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turecki"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukraiński"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"arabski"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"grecki"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"hebrajski"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litewski"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"hiszpański (Ameryka Łacińska)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-pt-rPT/strings.xml b/packages/InputDevices/res/values-pt-rPT/strings.xml
index 670badd..9a639cd 100644
--- a/packages/InputDevices/res/values-pt-rPT/strings.xml
+++ b/packages/InputDevices/res/values-pt-rPT/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Esloveno"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turco"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraniano"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Árabe"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grego"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebraico"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituano"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espanhol (América Latina)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-pt/strings.xml b/packages/InputDevices/res/values-pt/strings.xml
index 71274aa..05a0cd0 100644
--- a/packages/InputDevices/res/values-pt/strings.xml
+++ b/packages/InputDevices/res/values-pt/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Esloveno"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turco"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraniano"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Árabe"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grego"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebraico"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituano"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espanhol (América Latina)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ro/strings.xml b/packages/InputDevices/res/values-ro/strings.xml
index 151c11d..895d8f6 100644
--- a/packages/InputDevices/res/values-ro/strings.xml
+++ b/packages/InputDevices/res/values-ro/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovenă"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turcă"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraineană"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabă"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Greacă"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Ebraică"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituaniană"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spaniolă (America Latină)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-ru/strings.xml b/packages/InputDevices/res/values-ru/strings.xml
index 585a215..a4cbfd7 100644
--- a/packages/InputDevices/res/values-ru/strings.xml
+++ b/packages/InputDevices/res/values-ru/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"словенский"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"турецкий"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"украинский"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Арабский"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Греческий"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Иврит"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Литовский"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Испанский (Латинская Америка)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-sk/strings.xml b/packages/InputDevices/res/values-sk/strings.xml
index d14c204..01ab042 100644
--- a/packages/InputDevices/res/values-sk/strings.xml
+++ b/packages/InputDevices/res/values-sk/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"slovinské"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"turecké"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukrajinské"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabčina"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Gréčtina"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrejčina"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litovčina"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Španielčina (Latinská Amerika)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-sl/strings.xml b/packages/InputDevices/res/values-sl/strings.xml
index b8fc823e..30ff3c4 100644
--- a/packages/InputDevices/res/values-sl/strings.xml
+++ b/packages/InputDevices/res/values-sl/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"slovenska"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"turška"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukrajinska"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"arabščina"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"grščina"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"hebrejščina"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litovščina"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"španščina (Latinska Amerika)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-sr/strings.xml b/packages/InputDevices/res/values-sr/strings.xml
index 45e0b4b..d23ac00 100644
--- a/packages/InputDevices/res/values-sr/strings.xml
+++ b/packages/InputDevices/res/values-sr/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"словеначка"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"турска"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"украјинска"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"арапски"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"грчки"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"хебрејски"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"литвански"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"шпански (Латинска Америка)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-sv/strings.xml b/packages/InputDevices/res/values-sv/strings.xml
index ce20bff..25a5ae8 100644
--- a/packages/InputDevices/res/values-sv/strings.xml
+++ b/packages/InputDevices/res/values-sv/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovenskt"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turkiskt"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainskt"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabiska"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grekiska"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreiska"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litauiska"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanska (latinamerikansk)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-sw/strings.xml b/packages/InputDevices/res/values-sw/strings.xml
index 38bc83a..65ab96a1 100644
--- a/packages/InputDevices/res/values-sw/strings.xml
+++ b/packages/InputDevices/res/values-sw/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Kislovenia"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Kituruki"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Kiukrania"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Kiarabu"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Kigiriki"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Kiyahudi"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Kilithuania"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Kihispania (Kilatini)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-th/strings.xml b/packages/InputDevices/res/values-th/strings.xml
index 8951281..0cc7d47 100644
--- a/packages/InputDevices/res/values-th/strings.xml
+++ b/packages/InputDevices/res/values-th/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"สโลวีเนีย"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"ตุรกี"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ยูเครน"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"ภาษาอารบิค"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"กรีก"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"ฮิบรู"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"ลิทัวเนีย"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"สเปน (ละติน)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-tl/strings.xml b/packages/InputDevices/res/values-tl/strings.xml
index c551e20..08f34d2 100644
--- a/packages/InputDevices/res/values-tl/strings.xml
+++ b/packages/InputDevices/res/values-tl/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovenian"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turkish"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainian"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabic"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Greek"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrew"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lithuanian"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-tr/strings.xml b/packages/InputDevices/res/values-tr/strings.xml
index d828e78..f7c1262 100644
--- a/packages/InputDevices/res/values-tr/strings.xml
+++ b/packages/InputDevices/res/values-tr/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovence"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Türkçe"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukraynaca"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arapça"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Yunanca"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"İbranice"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litvanca"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"İspanyolca (Latin)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-uk/strings.xml b/packages/InputDevices/res/values-uk/strings.xml
index b4b9923..ee6ffc7 100644
--- a/packages/InputDevices/res/values-uk/strings.xml
+++ b/packages/InputDevices/res/values-uk/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"словенська"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"турецька"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"українська"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Арабська"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Грецька"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Іврит"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Литовська"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Іспанська (латиниця)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-vi/strings.xml b/packages/InputDevices/res/values-vi/strings.xml
index 18aa989..7a65e45 100644
--- a/packages/InputDevices/res/values-vi/strings.xml
+++ b/packages/InputDevices/res/values-vi/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Tiếng Sloven"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Tiếng Thổ Nhĩ Kỳ"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Tiếng Ukraina"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Tiếng Ả rập"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Tiếng Hy Lạp"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Tiếng Do Thái"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Tiếng Lithuania"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Tiếng Tây Ban Nha (La tinh)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-zh-rCN/strings.xml b/packages/InputDevices/res/values-zh-rCN/strings.xml
index 8d76f92..85b1c84 100644
--- a/packages/InputDevices/res/values-zh-rCN/strings.xml
+++ b/packages/InputDevices/res/values-zh-rCN/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"斯洛文尼亚语"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"土耳其语"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"乌克兰语"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"阿拉伯语"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"希腊语"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"希伯来语"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"立陶宛语"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"西班牙语(拉丁美洲)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-zh-rHK/strings.xml b/packages/InputDevices/res/values-zh-rHK/strings.xml
index 031f294..839c546 100644
--- a/packages/InputDevices/res/values-zh-rHK/strings.xml
+++ b/packages/InputDevices/res/values-zh-rHK/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"斯洛文尼亞文"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"土耳其文"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"烏克蘭文"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"阿拉伯文"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"希臘文"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"希伯來文"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"立陶宛文"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"西班牙文 (拉丁美洲)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-zh-rTW/strings.xml b/packages/InputDevices/res/values-zh-rTW/strings.xml
index 76cb6a2..ba9f132 100644
--- a/packages/InputDevices/res/values-zh-rTW/strings.xml
+++ b/packages/InputDevices/res/values-zh-rTW/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"斯洛維尼亞文"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"土耳其文"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"烏克蘭文"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"阿拉伯文"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"希臘文"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"希伯來文"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"立陶宛文"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"西班牙文 (拉丁美洲)"</string>
 </resources>
diff --git a/packages/InputDevices/res/values-zu/strings.xml b/packages/InputDevices/res/values-zu/strings.xml
index 3e4ad67..fbf1074 100644
--- a/packages/InputDevices/res/values-zu/strings.xml
+++ b/packages/InputDevices/res/values-zu/strings.xml
@@ -34,9 +34,4 @@
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Isi-Slovenian"</string>
     <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Isi-Turkish"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Isi-Ukrainian"</string>
-    <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Isi-Arabic"</string>
-    <string name="keyboard_layout_greek" msgid="7289253560162386040">"Isi-Greek"</string>
-    <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Isi-Hebrew"</string>
-    <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Isi-Lithuanian"</string>
-    <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Isi-Spanish (Latin)"</string>
 </resources>
diff --git a/packages/Keyguard/res/layout/keyguard_bouncer.xml b/packages/Keyguard/res/layout/keyguard_bouncer.xml
index 8716ebc..975a139 100644
--- a/packages/Keyguard/res/layout/keyguard_bouncer.xml
+++ b/packages/Keyguard/res/layout/keyguard_bouncer.xml
@@ -19,7 +19,7 @@
     android:layout_height="match_parent">
 
     <View android:id="@+id/bouncer_background"
-        android:background="#aa000000"
+        android:background="#cc000000"
         android:clickable="true"
         android:layout_width="match_parent"
         android:layout_height="match_parent"/>
diff --git a/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml b/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml
index 0e2b33a..e167817 100644
--- a/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml
@@ -92,7 +92,7 @@
            >
            <view class="com.android.keyguard.NumPadKey"
                android:id="@+id/key1"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
@@ -101,7 +101,7 @@
                />
            <view class="com.android.keyguard.NumPadKey"
                android:id="@+id/key2"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
@@ -110,7 +110,7 @@
                />
            <view class="com.android.keyguard.NumPadKey"
                android:id="@+id/key3"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
@@ -126,7 +126,7 @@
            >
            <view class="com.android.keyguard.NumPadKey"
                android:id="@+id/key4"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
@@ -135,7 +135,7 @@
                />
            <view class="com.android.keyguard.NumPadKey"
                android:id="@+id/key5"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
@@ -144,7 +144,7 @@
                />
            <view class="com.android.keyguard.NumPadKey"
                android:id="@+id/key6"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
@@ -160,7 +160,7 @@
            >
            <view class="com.android.keyguard.NumPadKey"
                android:id="@+id/key7"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
@@ -169,7 +169,7 @@
                />
            <view class="com.android.keyguard.NumPadKey"
                android:id="@+id/key8"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
@@ -178,7 +178,7 @@
                />
            <view class="com.android.keyguard.NumPadKey"
                android:id="@+id/key9"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
@@ -199,7 +199,7 @@
                />
            <view class="com.android.keyguard.NumPadKey"
                android:id="@+id/key0"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
@@ -208,7 +208,7 @@
                />
            <ImageButton
                android:id="@+id/key_enter"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
diff --git a/packages/Keyguard/res/layout/keyguard_sim_puk_view.xml b/packages/Keyguard/res/layout/keyguard_sim_puk_view.xml
index 88049a7..ac798ca 100644
--- a/packages/Keyguard/res/layout/keyguard_sim_puk_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_sim_puk_view.xml
@@ -93,7 +93,7 @@
            >
            <view class="com.android.keyguard.NumPadKey"
                android:id="@+id/key1"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
@@ -102,7 +102,7 @@
                />
            <view class="com.android.keyguard.NumPadKey"
                android:id="@+id/key2"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
@@ -111,7 +111,7 @@
                />
            <view class="com.android.keyguard.NumPadKey"
                android:id="@+id/key3"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
@@ -127,7 +127,7 @@
            >
            <view class="com.android.keyguard.NumPadKey"
                android:id="@+id/key4"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
@@ -136,7 +136,7 @@
                />
            <view class="com.android.keyguard.NumPadKey"
                android:id="@+id/key5"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
@@ -145,7 +145,7 @@
                />
            <view class="com.android.keyguard.NumPadKey"
                android:id="@+id/key6"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
@@ -161,7 +161,7 @@
            >
            <view class="com.android.keyguard.NumPadKey"
                android:id="@+id/key7"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
@@ -170,7 +170,7 @@
                />
            <view class="com.android.keyguard.NumPadKey"
                android:id="@+id/key8"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
@@ -179,7 +179,7 @@
                />
            <view class="com.android.keyguard.NumPadKey"
                android:id="@+id/key9"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
@@ -200,7 +200,7 @@
                />
            <view class="com.android.keyguard.NumPadKey"
                android:id="@+id/key0"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
@@ -209,7 +209,7 @@
                />
            <ImageButton
                android:id="@+id/key_enter"
-               style="@style/Widget.Button.NumPadKey"
+               style="@style/Widget.Button.NumPadKey.Sim"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="1"
diff --git a/packages/Keyguard/res/layout/keyguard_status_view.xml b/packages/Keyguard/res/layout/keyguard_status_view.xml
index 546ddd4..0d943ed 100644
--- a/packages/Keyguard/res/layout/keyguard_status_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_status_view.xml
@@ -28,7 +28,7 @@
     androidprv:layout_maxWidth="@dimen/keyguard_security_width"
     androidprv:layout_maxHeight="@dimen/keyguard_security_height"
     android:gravity="center_horizontal|top"
-    android:layout_marginTop="32dp"
+    android:layout_marginTop="48dp"
     android:layout_marginBottom="32dp"
     android:contentDescription="@string/keyguard_accessibility_status">
     <LinearLayout
diff --git a/packages/Keyguard/res/values-af/strings.xml b/packages/Keyguard/res/values-af/strings.xml
index a046dc5..2667ed2 100644
--- a/packages/Keyguard/res/values-af/strings.xml
+++ b/packages/Keyguard/res/values-af/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Voer PIN-kode in"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Voer SIM PUK- en nuwe PIN-kode in"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK-kode"</string>
diff --git a/packages/Keyguard/res/values-am/strings.xml b/packages/Keyguard/res/values-am/strings.xml
index 0bb7993..fd4cf78 100644
--- a/packages/Keyguard/res/values-am/strings.xml
+++ b/packages/Keyguard/res/values-am/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"ፒን ኮድ ተይብ"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"የሲም PUK እና አዲሱን ፒን ኮድ ይተይቡ"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"የሲም PUK ኮድ"</string>
@@ -28,7 +27,7 @@
     <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">"ለመክፈት ፒን ተይብ"</string>
-    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ትክክል ያልሆነ ፒን  ኮድ።"</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>
@@ -83,7 +82,7 @@
     <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_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>
diff --git a/packages/Keyguard/res/values-ar/strings.xml b/packages/Keyguard/res/values-ar/strings.xml
index eac3216..83d4b93 100644
--- a/packages/Keyguard/res/values-ar/strings.xml
+++ b/packages/Keyguard/res/values-ar/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"‏اكتب رمز رمز PIN"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"‏أدخل رمز PUK لبطاقة SIM ورمز \"رقم التعريف الشخصي\" الجديد"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"‏رمز PUK لبطاقة SIM"</string>
diff --git a/packages/Keyguard/res/values-bg/strings.xml b/packages/Keyguard/res/values-bg/strings.xml
index ad4285a..641adbd 100644
--- a/packages/Keyguard/res/values-bg/strings.xml
+++ b/packages/Keyguard/res/values-bg/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Въведете ПИН кода"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Въведете PUK за SIM картата и новия ПИН код"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK код за SIM картата"</string>
diff --git a/packages/Keyguard/res/values-ca/strings.xml b/packages/Keyguard/res/values-ca/strings.xml
index 7e40709..8b81086 100644
--- a/packages/Keyguard/res/values-ca/strings.xml
+++ b/packages/Keyguard/res/values-ca/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Bloqueig de teclat"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Introdueix el codi PIN"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Escriu el PUK de la SIM i el codi PIN nou."</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Codi PUK de la SIM"</string>
diff --git a/packages/Keyguard/res/values-cs/strings.xml b/packages/Keyguard/res/values-cs/strings.xml
index 53cc707..e4ed02a 100644
--- a/packages/Keyguard/res/values-cs/strings.xml
+++ b/packages/Keyguard/res/values-cs/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Uzamčení kláves"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Zadejte kód PIN"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Zadejte kód PUK SIM karty a nový kód PIN."</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Kód PUK SIM karty"</string>
diff --git a/packages/Keyguard/res/values-da/strings.xml b/packages/Keyguard/res/values-da/strings.xml
index cf1aad9..f8f0a6f 100644
--- a/packages/Keyguard/res/values-da/strings.xml
+++ b/packages/Keyguard/res/values-da/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Tastaturlås"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Indtast pinkode"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Indtast PUK-koden til SIM-kortet og den nye pinkode"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK-kode til SIM-kort"</string>
diff --git a/packages/Keyguard/res/values-de/strings.xml b/packages/Keyguard/res/values-de/strings.xml
index 14df237..edbbffd 100644
--- a/packages/Keyguard/res/values-de/strings.xml
+++ b/packages/Keyguard/res/values-de/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"PIN-Code eingeben"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Geben Sie den PUK-Code der SIM-Karte und den neuen PIN-Code ein."</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK-Code der SIM-Karte"</string>
diff --git a/packages/Keyguard/res/values-el/strings.xml b/packages/Keyguard/res/values-el/strings.xml
index 63d8409..be07dcd 100644
--- a/packages/Keyguard/res/values-el/strings.xml
+++ b/packages/Keyguard/res/values-el/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Πληκτρολογήστε τον κωδικό αριθμό PIN"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Πληκτρολογήστε τον κωδικό PUK της κάρτας SIM και τον νέο κωδικό PIN"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Κωδικός PUK κάρτας SIM"</string>
diff --git a/packages/Keyguard/res/values-en-rGB/strings.xml b/packages/Keyguard/res/values-en-rGB/strings.xml
index ecc850d..f0d81b8 100644
--- a/packages/Keyguard/res/values-en-rGB/strings.xml
+++ b/packages/Keyguard/res/values-en-rGB/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Type PIN code"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Type SIM PUK and new PIN code"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK code"</string>
diff --git a/packages/Keyguard/res/values-en-rIN/strings.xml b/packages/Keyguard/res/values-en-rIN/strings.xml
index ecc850d..f0d81b8 100644
--- a/packages/Keyguard/res/values-en-rIN/strings.xml
+++ b/packages/Keyguard/res/values-en-rIN/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Type PIN code"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Type SIM PUK and new PIN code"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK code"</string>
diff --git a/packages/Keyguard/res/values-es-rUS/strings.xml b/packages/Keyguard/res/values-es-rUS/strings.xml
index c6d63ba..38beca3 100644
--- a/packages/Keyguard/res/values-es-rUS/strings.xml
+++ b/packages/Keyguard/res/values-es-rUS/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Bloqueo de teclado"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Ingresa el código PIN"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Escribe el código PUK de la tarjeta SIM y un nuevo código PIN."</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Código PUK de la tarjeta SIM"</string>
diff --git a/packages/Keyguard/res/values-es/strings.xml b/packages/Keyguard/res/values-es/strings.xml
index 8a78399..a93b10d 100644
--- a/packages/Keyguard/res/values-es/strings.xml
+++ b/packages/Keyguard/res/values-es/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Bloqueo"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Introduce el código PIN."</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Escribe el PUK de la tarjeta SIM y un nuevo código PIN"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Código PUK de la tarjeta SIM"</string>
diff --git a/packages/Keyguard/res/values-et-rEE/strings.xml b/packages/Keyguard/res/values-et-rEE/strings.xml
index b837f01..90bd829 100644
--- a/packages/Keyguard/res/values-et-rEE/strings.xml
+++ b/packages/Keyguard/res/values-et-rEE/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Klahvilukk"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Sisestage PIN-kood"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Sisestage SIM-i PUK- ja uus PIN-kood"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM-i PUK-kood"</string>
diff --git a/packages/Keyguard/res/values-fa/strings.xml b/packages/Keyguard/res/values-fa/strings.xml
index 5d1c487..b4a4c61 100644
--- a/packages/Keyguard/res/values-fa/strings.xml
+++ b/packages/Keyguard/res/values-fa/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"پین کد را وارد کنید"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"‏PUK سیم کارت و کد پین جدید را تایپ کنید"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"‏کد PUK سیم کارت"</string>
diff --git a/packages/Keyguard/res/values-fi/strings.xml b/packages/Keyguard/res/values-fi/strings.xml
index bdf6677..e079ffa 100644
--- a/packages/Keyguard/res/values-fi/strings.xml
+++ b/packages/Keyguard/res/values-fi/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Näppäinvahti"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Anna PIN-koodi"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Anna SIM-kortin PUK-koodi ja uusi PIN-koodi"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM-kortin PUK-koodi"</string>
diff --git a/packages/Keyguard/res/values-fr-rCA/strings.xml b/packages/Keyguard/res/values-fr-rCA/strings.xml
index e77927c..59f27aa 100644
--- a/packages/Keyguard/res/values-fr-rCA/strings.xml
+++ b/packages/Keyguard/res/values-fr-rCA/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Verrouillage du clavier"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Saisissez le NIP."</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Entrez le code PUK et le nouveau NIP de la carte SIM"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Code PUK de la carte SIM"</string>
diff --git a/packages/Keyguard/res/values-fr/strings.xml b/packages/Keyguard/res/values-fr/strings.xml
index 41be1eb..b910dd4 100644
--- a/packages/Keyguard/res/values-fr/strings.xml
+++ b/packages/Keyguard/res/values-fr/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Protection des touches"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Saisissez le code PIN."</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Saisissez la clé PUK et le nouveau code PIN de la carte SIM."</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Clé PUK de la carte SIM"</string>
diff --git a/packages/Keyguard/res/values-hi/strings.xml b/packages/Keyguard/res/values-hi/strings.xml
index c963beb..8c94eb3 100644
--- a/packages/Keyguard/res/values-hi/strings.xml
+++ b/packages/Keyguard/res/values-hi/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"पिन कोड लिखें"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"सिम PUK और नया PIN कोड लिखें"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"सिम PUK कोड"</string>
diff --git a/packages/Keyguard/res/values-hr/strings.xml b/packages/Keyguard/res/values-hr/strings.xml
index 6bbdd51..3843549 100644
--- a/packages/Keyguard/res/values-hr/strings.xml
+++ b/packages/Keyguard/res/values-hr/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Zaštita tipkovnice"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Unesite PIN kôd"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Unesite PUK i novi PIN kôd SIM kartice"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK kôd SIM kartice"</string>
diff --git a/packages/Keyguard/res/values-hu/strings.xml b/packages/Keyguard/res/values-hu/strings.xml
index 9706874..bf6f528 100644
--- a/packages/Keyguard/res/values-hu/strings.xml
+++ b/packages/Keyguard/res/values-hu/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Billentyűzár"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Írja be a PIN kódot"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Írja be a SIM kártya PUK kódját, majd az új PIN kódot"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM kártya PUK kódja"</string>
diff --git a/packages/Keyguard/res/values-hy-rAM/strings.xml b/packages/Keyguard/res/values-hy-rAM/strings.xml
index 60c626d..ff87920 100644
--- a/packages/Keyguard/res/values-hy-rAM/strings.xml
+++ b/packages/Keyguard/res/values-hy-rAM/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Մուտքագրեք PIN կոդը"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Մուտքագրեք SIM PUK-ը և նոր PIN կոդը"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK կոդը"</string>
diff --git a/packages/Keyguard/res/values-in/strings.xml b/packages/Keyguard/res/values-in/strings.xml
index 9ea5a29..9e19472 100644
--- a/packages/Keyguard/res/values-in/strings.xml
+++ b/packages/Keyguard/res/values-in/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Ketik kode PIN"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Ketik kode PIN baru dan PUK SIM"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Kode PUK SIM"</string>
diff --git a/packages/Keyguard/res/values-it/strings.xml b/packages/Keyguard/res/values-it/strings.xml
index 2a481e6..7212e5e 100644
--- a/packages/Keyguard/res/values-it/strings.xml
+++ b/packages/Keyguard/res/values-it/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Inserisci il codice PIN"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Digita il PUK della SIM e il nuovo codice PIN"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Codice PUK della SIM"</string>
diff --git a/packages/Keyguard/res/values-iw/strings.xml b/packages/Keyguard/res/values-iw/strings.xml
index a6a3192..12b45e4 100644
--- a/packages/Keyguard/res/values-iw/strings.xml
+++ b/packages/Keyguard/res/values-iw/strings.xml
@@ -20,7 +20,6 @@
 
 <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="keyguard_password_enter_puk_code" msgid="3035856550289724338">"‏הקלד קוד PUK של כרטיס SIM וקוד PIN חדש"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"‏קוד PUK של כרטיס SIM"</string>
diff --git a/packages/Keyguard/res/values-ja/strings.xml b/packages/Keyguard/res/values-ja/strings.xml
index b683a9d..5106271 100644
--- a/packages/Keyguard/res/values-ja/strings.xml
+++ b/packages/Keyguard/res/values-ja/strings.xml
@@ -20,7 +20,6 @@
 
 <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="keyguard_password_enter_puk_code" msgid="3035856550289724338">"PUKと新しいPINコードを入力"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUKコード"</string>
diff --git a/packages/Keyguard/res/values-ka-rGE/strings.xml b/packages/Keyguard/res/values-ka-rGE/strings.xml
index 4414096..3d7af75 100644
--- a/packages/Keyguard/res/values-ka-rGE/strings.xml
+++ b/packages/Keyguard/res/values-ka-rGE/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"აკრიფეთ PIN კოდი"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"დაბეჭდეთ SIM-ის PUK კოდი და ახალი PIN კოდი"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK კოდი"</string>
diff --git a/packages/Keyguard/res/values-km-rKH/strings.xml b/packages/Keyguard/res/values-km-rKH/strings.xml
index a2e54a7..f78b93d 100644
--- a/packages/Keyguard/res/values-km-rKH/strings.xml
+++ b/packages/Keyguard/res/values-km-rKH/strings.xml
@@ -20,7 +20,6 @@
 
 <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="keyguard_password_enter_puk_code" msgid="3035856550289724338">"បញ្ចូល​លេខ​កូដ PUK  និង​​ PIN ថ្មី​របស់​ស៊ីម"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"លេខ​កូដ PUK ស៊ីម"</string>
@@ -83,7 +82,7 @@
     <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_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>
@@ -120,7 +119,7 @@
     <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_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>
diff --git a/packages/Keyguard/res/values-ko/strings.xml b/packages/Keyguard/res/values-ko/strings.xml
index cde2b1c..2a7200c 100644
--- a/packages/Keyguard/res/values-ko/strings.xml
+++ b/packages/Keyguard/res/values-ko/strings.xml
@@ -20,7 +20,6 @@
 
 <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="keyguard_password_enter_puk_code" msgid="3035856550289724338">"SIM PUK 및 새 PIN 코드 입력"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK 코드"</string>
diff --git a/packages/Keyguard/res/values-lo-rLA/strings.xml b/packages/Keyguard/res/values-lo-rLA/strings.xml
index 0571768..81c10181 100644
--- a/packages/Keyguard/res/values-lo-rLA/strings.xml
+++ b/packages/Keyguard/res/values-lo-rLA/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"ພິມລະຫັດ PIN"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"ປະເພດ PUK ຂອງ SIM ແລະລະຫັດ PIN ໃໝ່"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"ລະຫັດ PUK ຂອງ SIM"</string>
diff --git a/packages/Keyguard/res/values-lt/strings.xml b/packages/Keyguard/res/values-lt/strings.xml
index 0fd6605..ff3034a 100644
--- a/packages/Keyguard/res/values-lt/strings.xml
+++ b/packages/Keyguard/res/values-lt/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Klaviatūros apsauga"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Įveskite PIN kodą"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Įveskite SIM kortelės PUK kodą ir naują PIN kodą"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM kortelės PUK kodas"</string>
diff --git a/packages/Keyguard/res/values-lv/strings.xml b/packages/Keyguard/res/values-lv/strings.xml
index 2bcde1d..539f91d 100644
--- a/packages/Keyguard/res/values-lv/strings.xml
+++ b/packages/Keyguard/res/values-lv/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Taustiņslēgs"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Ievadiet PIN kodu."</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Ievadiet SIM kartes PUK kodu un jaunu PIN kodu."</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM kartes PUK kods"</string>
diff --git a/packages/Keyguard/res/values-mn-rMN/strings.xml b/packages/Keyguard/res/values-mn-rMN/strings.xml
index 7bb819d..e1b833e 100644
--- a/packages/Keyguard/res/values-mn-rMN/strings.xml
+++ b/packages/Keyguard/res/values-mn-rMN/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</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>
diff --git a/packages/Keyguard/res/values-ms-rMY/strings.xml b/packages/Keyguard/res/values-ms-rMY/strings.xml
index b4c1b46..a6845bc 100644
--- a/packages/Keyguard/res/values-ms-rMY/strings.xml
+++ b/packages/Keyguard/res/values-ms-rMY/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Pengawal kekunci"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Taip kod PIN"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Taip PUK SIM dan kod PIN baharu"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Kod PUK SIM"</string>
diff --git a/packages/Keyguard/res/values-nb/strings.xml b/packages/Keyguard/res/values-nb/strings.xml
index 801e03d..71138a5 100644
--- a/packages/Keyguard/res/values-nb/strings.xml
+++ b/packages/Keyguard/res/values-nb/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Tastaturlås"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Skriv inn PIN-kode"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Skriv inn PUK-koden for SIM-kortet og en ny PIN-kode"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK-koden for SIM-kortet"</string>
diff --git a/packages/Keyguard/res/values-nl/strings.xml b/packages/Keyguard/res/values-nl/strings.xml
index 195f950..34149c9 100644
--- a/packages/Keyguard/res/values-nl/strings.xml
+++ b/packages/Keyguard/res/values-nl/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Toetsblokkering"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Pincode typen"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Typ de pukcode voor de simkaart en de nieuwe pincode"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Pukcode voor simkaart"</string>
diff --git a/packages/Keyguard/res/values-pl/strings.xml b/packages/Keyguard/res/values-pl/strings.xml
index 165b2c4..cfcbc46 100644
--- a/packages/Keyguard/res/values-pl/strings.xml
+++ b/packages/Keyguard/res/values-pl/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Blokada klawiszy"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Wpisz kod PIN."</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Wpisz PUK i nowy kod PIN karty SIM"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Kod PUK karty SIM"</string>
diff --git a/packages/Keyguard/res/values-pt-rPT/strings.xml b/packages/Keyguard/res/values-pt-rPT/strings.xml
index 332a943..abd4fcd 100644
--- a/packages/Keyguard/res/values-pt-rPT/strings.xml
+++ b/packages/Keyguard/res/values-pt-rPT/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Escreva o código PIN"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Introduzir PUK do cartão SIM e o novo código PIN"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Código PUK do cartão SIM"</string>
diff --git a/packages/Keyguard/res/values-pt/strings.xml b/packages/Keyguard/res/values-pt/strings.xml
index a97b1b6..24d78e5 100644
--- a/packages/Keyguard/res/values-pt/strings.xml
+++ b/packages/Keyguard/res/values-pt/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Bloqueio do teclado"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Insira o código PIN"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Digite o PUK do SIM e o novo código PIN."</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Código PUK do SIM"</string>
diff --git a/packages/Keyguard/res/values-rm/strings.xml b/packages/Keyguard/res/values-rm/strings.xml
index 4d71f27..ee26a3d 100644
--- a/packages/Keyguard/res/values-rm/strings.xml
+++ b/packages/Keyguard/res/values-rm/strings.xml
@@ -20,8 +20,6 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- no translation found for app_name (719438068451601849) -->
-    <skip />
     <!-- no translation found for keyguard_password_enter_pin_code (3037685796058495017) -->
     <skip />
     <!-- no translation found for keyguard_password_enter_puk_code (3035856550289724338) -->
diff --git a/packages/Keyguard/res/values-ro/strings.xml b/packages/Keyguard/res/values-ro/strings.xml
index 58bc337..1c7e88f 100644
--- a/packages/Keyguard/res/values-ro/strings.xml
+++ b/packages/Keyguard/res/values-ro/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Blocarea tastaturii"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Introduceţi codul PIN"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Introduceți codul PUK pentru cardul SIM și codul PIN nou"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Codul PUK pentru cardul SIM"</string>
diff --git a/packages/Keyguard/res/values-ru/strings.xml b/packages/Keyguard/res/values-ru/strings.xml
index 866abc0..304f474 100644
--- a/packages/Keyguard/res/values-ru/strings.xml
+++ b/packages/Keyguard/res/values-ru/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Введите PIN-код"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Введите PUK-код и новый PIN-код"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK-код"</string>
diff --git a/packages/Keyguard/res/values-sk/strings.xml b/packages/Keyguard/res/values-sk/strings.xml
index 45e4288..cdf8ca9 100644
--- a/packages/Keyguard/res/values-sk/strings.xml
+++ b/packages/Keyguard/res/values-sk/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Zámka klávesnice"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Zadajte kód PIN"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Zadajte kód PUK karty SIM a nový kód PIN"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Kód PUK karty SIM"</string>
@@ -36,7 +35,7 @@
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Pripojte nabíjačku."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Telefón odomknete stlačením tlačidla Menu."</string>
     <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Sieť je zablokovaná"</string>
-    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Nie je vložená karta SIM"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Nie je vložená karta SIM."</string>
     <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"V tablete nie je žiadna karta SIM."</string>
     <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"V telefóne nie je žiadna karta SIM."</string>
     <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Vložte kartu SIM."</string>
diff --git a/packages/Keyguard/res/values-sl/strings.xml b/packages/Keyguard/res/values-sl/strings.xml
index cf72e47..b0ec84e 100644
--- a/packages/Keyguard/res/values-sl/strings.xml
+++ b/packages/Keyguard/res/values-sl/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Vnesite kodo PIN"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Vnesite kodo PUK in novo kodo PIN kartice SIM"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Koda PUK kartice SIM"</string>
diff --git a/packages/Keyguard/res/values-sr/strings.xml b/packages/Keyguard/res/values-sr/strings.xml
index bd08eae..2bdd8f5 100644
--- a/packages/Keyguard/res/values-sr/strings.xml
+++ b/packages/Keyguard/res/values-sr/strings.xml
@@ -20,7 +20,6 @@
 
 <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="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Унесите SIM PUK кôд и нови PIN кôд"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK кôд"</string>
@@ -119,7 +118,7 @@
     <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_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>
diff --git a/packages/Keyguard/res/values-sv/strings.xml b/packages/Keyguard/res/values-sv/strings.xml
index 1214100..e446f61 100644
--- a/packages/Keyguard/res/values-sv/strings.xml
+++ b/packages/Keyguard/res/values-sv/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Ange PIN-kod"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Ange PUK-koden och en ny pinkod för SIM-kortet"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK-kod för SIM-kortet"</string>
diff --git a/packages/Keyguard/res/values-sw/strings.xml b/packages/Keyguard/res/values-sw/strings.xml
index fc1ce17..1d60a13 100644
--- a/packages/Keyguard/res/values-sw/strings.xml
+++ b/packages/Keyguard/res/values-sw/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Kilinda vitufe"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Ingiza msimbo wa PIN"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Chapa PUK ya SIM na msimbo mpya wa PIN"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Msimbo wa PUK ya SIM"</string>
diff --git a/packages/Keyguard/res/values-th/strings.xml b/packages/Keyguard/res/values-th/strings.xml
index 34d97c2..a44f9fe 100644
--- a/packages/Keyguard/res/values-th/strings.xml
+++ b/packages/Keyguard/res/values-th/strings.xml
@@ -20,7 +20,6 @@
 
 <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="keyguard_password_enter_puk_code" msgid="3035856550289724338">"พิมพ์ PUK และรหัส PIN ใหม่"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"รหัส PUK ของซิม"</string>
diff --git a/packages/Keyguard/res/values-tl/strings.xml b/packages/Keyguard/res/values-tl/strings.xml
index 9d97d22..6516766 100644
--- a/packages/Keyguard/res/values-tl/strings.xml
+++ b/packages/Keyguard/res/values-tl/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"I-type ang PIN code"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"I-type ang SIM PUK at bagong PIN code"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK code ng SIM"</string>
diff --git a/packages/Keyguard/res/values-tr/strings.xml b/packages/Keyguard/res/values-tr/strings.xml
index 1d8b982..aed8a47 100644
--- a/packages/Keyguard/res/values-tr/strings.xml
+++ b/packages/Keyguard/res/values-tr/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"PIN kodunu yazın"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"SIM PUK kodunu ve yeni bir PIN kodu yazın."</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK kodu"</string>
diff --git a/packages/Keyguard/res/values-uk/strings.xml b/packages/Keyguard/res/values-uk/strings.xml
index 16cf6cf..5e355e4 100644
--- a/packages/Keyguard/res/values-uk/strings.xml
+++ b/packages/Keyguard/res/values-uk/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Введіть PIN-код"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Введіть PUK-код і новий PIN-код SIM-карти"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK-код SIM-карти"</string>
diff --git a/packages/Keyguard/res/values-vi/strings.xml b/packages/Keyguard/res/values-vi/strings.xml
index 00693aa5..19eb4c5 100644
--- a/packages/Keyguard/res/values-vi/strings.xml
+++ b/packages/Keyguard/res/values-vi/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Khóa bàn phím"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Nhập mã PIN"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Nhập mã PIN mới và mã PUK của SIM"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Mã PUK của SIM"</string>
@@ -76,7 +75,7 @@
     <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_hide_bouncer" msgid="7896992171878309358">"Quá trình khởi 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="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
diff --git a/packages/Keyguard/res/values-zh-rCN/strings.xml b/packages/Keyguard/res/values-zh-rCN/strings.xml
index 1c014c3..18578e4 100644
--- a/packages/Keyguard/res/values-zh-rCN/strings.xml
+++ b/packages/Keyguard/res/values-zh-rCN/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"输入 PIN 码"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"请输入 SIM 卡 PUK 码和新的 PIN 码"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM 卡 PUK 码"</string>
diff --git a/packages/Keyguard/res/values-zh-rHK/strings.xml b/packages/Keyguard/res/values-zh-rHK/strings.xml
index 1b621d6..010ad2f 100644
--- a/packages/Keyguard/res/values-zh-rHK/strings.xml
+++ b/packages/Keyguard/res/values-zh-rHK/strings.xml
@@ -20,7 +20,6 @@
 
 <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="keyguard_password_enter_puk_code" msgid="3035856550289724338">"請輸入 SIM PUK 碼和新 PIN 碼"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK 碼"</string>
diff --git a/packages/Keyguard/res/values-zh-rTW/strings.xml b/packages/Keyguard/res/values-zh-rTW/strings.xml
index 6e632ef..d81cc16 100644
--- a/packages/Keyguard/res/values-zh-rTW/strings.xml
+++ b/packages/Keyguard/res/values-zh-rTW/strings.xml
@@ -20,7 +20,6 @@
 
 <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="keyguard_password_enter_puk_code" msgid="3035856550289724338">"輸入 SIM 卡 PUK 碼和新 PIN 碼"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM 卡 PUK 碼"</string>
diff --git a/packages/Keyguard/res/values-zu/strings.xml b/packages/Keyguard/res/values-zu/strings.xml
index 95d3474..b205634 100644
--- a/packages/Keyguard/res/values-zu/strings.xml
+++ b/packages/Keyguard/res/values-zu/strings.xml
@@ -20,7 +20,6 @@
 
 <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">"Ukhiye wokugada"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Faka ikhodi ye-PIN"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Thayipha i-PUK ye-SIM nekhodi yephinikhodi entsha"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Ikhodi ye-PUK ye-SIM"</string>
diff --git a/packages/Keyguard/res/values/styles.xml b/packages/Keyguard/res/values/styles.xml
index b54ac50..5ab00d2 100644
--- a/packages/Keyguard/res/values/styles.xml
+++ b/packages/Keyguard/res/values/styles.xml
@@ -33,6 +33,10 @@
         <item name="android:paddingLeft">20dp</item>
         <item name="android:paddingRight">6dp</item>
     </style>
+    <style name="Widget.Button.NumPadKey.Sim" >
+        <item name="android:paddingTop">3dp</item>
+        <item name="android:paddingBottom">4dp</item>
+    </style>
     <style name="TextAppearance.NumPadKey"
             parent="@android:style/TextAppearance">
         <item name="android:textSize">34dp</item>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index 4b386b6..2d17b7b 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -68,13 +68,6 @@
         mEnableHaptics = mLockPatternUtils.isTactileFeedbackEnabled();
     }
 
-    @Override
-    public void onWindowFocusChanged(boolean hasWindowFocus) {
-        if (hasWindowFocus) {
-            reset();
-        }
-    }
-
     public void reset() {
         // start fresh
         mPasswordEntry.setText("");
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index b4308c6..98122fc 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -231,15 +231,6 @@
         mLockPatternView.setOnPatternListener(null);
     }
 
-    @Override
-    public void onWindowFocusChanged(boolean hasWindowFocus) {
-        super.onWindowFocusChanged(hasWindowFocus);
-        if (hasWindowFocus) {
-            // when timeout dialog closes we want to update our state
-            reset();
-        }
-    }
-
     private class UnlockPatternListener implements LockPatternView.OnPatternListener {
 
         public void onPatternStart() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index ba67a82..d6351df 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -99,6 +99,7 @@
     private static final int MSG_SCREEN_TURNED_ON = 319;
     private static final int MSG_SCREEN_TURNED_OFF = 320;
     private static final int MSG_NFC_UNLOCK = 321;
+    private static final int MSG_KEYGUARD_BOUNCER_CHANGED = 322;
 
     private static KeyguardUpdateMonitor sInstance;
 
@@ -111,6 +112,7 @@
     private int mRingMode;
     private int mPhoneState;
     private boolean mKeyguardIsVisible;
+    private boolean mBouncer;
     private boolean mBootCompleted;
 
     // Device provisioning state
@@ -155,7 +157,7 @@
                     handleRingerModeChange(msg.arg1);
                     break;
                 case MSG_PHONE_STATE_CHANGED:
-                    handlePhoneStateChanged((String)msg.obj);
+                    handlePhoneStateChanged((String) msg.obj);
                     break;
                 case MSG_CLOCK_VISIBILITY_CHANGED:
                     handleClockVisibilityChanged();
@@ -167,7 +169,7 @@
                     handleDevicePolicyManagerStateChanged();
                     break;
                 case MSG_USER_SWITCHING:
-                    handleUserSwitching(msg.arg1, (IRemoteCallback)msg.obj);
+                    handleUserSwitching(msg.arg1, (IRemoteCallback) msg.obj);
                     break;
                 case MSG_USER_SWITCH_COMPLETE:
                     handleUserSwitchComplete(msg.arg1);
@@ -178,6 +180,9 @@
                 case MSG_KEYGUARD_VISIBILITY_CHANGED:
                     handleKeyguardVisibilityChanged(msg.arg1);
                     break;
+                case MSG_KEYGUARD_BOUNCER_CHANGED:
+                    handleKeyguardBouncerChanged(msg.arg1);
+                    break;
                 case MSG_BOOT_COMPLETED:
                     handleBootCompleted();
                     break;
@@ -887,6 +892,22 @@
     }
 
     /**
+     * Handle {@link #MSG_KEYGUARD_BOUNCER_CHANGED}
+     * @see #sendKeyguardBouncerChanged(boolean)
+     */
+    private void handleKeyguardBouncerChanged(int bouncer) {
+        if (DEBUG) Log.d(TAG, "handleKeyguardBouncerChanged(" + bouncer + ")");
+        boolean isBouncer = (bouncer == 1);
+        mBouncer = isBouncer;
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onKeyguardBouncerChanged(isBouncer);
+            }
+        }
+    }
+
+    /**
      * Handle {@link #MSG_REPORT_EMERGENCY_CALL_ACTION}
      */
     private void handleReportEmergencyCallAction() {
@@ -902,6 +923,13 @@
         return mKeyguardIsVisible;
     }
 
+    /**
+     * @return if the keyguard is currently in bouncer mode.
+     */
+    public boolean isKeyguardBouncer() {
+        return mBouncer;
+    }
+
     public boolean isSwitchingUser() {
         return mSwitchingUser;
     }
@@ -1021,6 +1049,16 @@
         message.sendToTarget();
     }
 
+    /**
+     * @see #handleKeyguardBouncerChanged(int)
+     */
+    public void sendKeyguardBouncerChanged(boolean showingBouncer) {
+        if (DEBUG) Log.d(TAG, "sendKeyguardBouncerChanged(" + showingBouncer + ")");
+        Message message = mHandler.obtainMessage(MSG_KEYGUARD_BOUNCER_CHANGED);
+        message.arg1 = showingBouncer ? 1 : 0;
+        message.sendToTarget();
+    }
+
     public void reportClockVisible(boolean visible) {
         mClockVisible = visible;
         mHandler.obtainMessage(MSG_CLOCK_VISIBILITY_CHANGED).sendToTarget();
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 862931e..91a024f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -87,6 +87,12 @@
     }
 
     /**
+     * Called when the keyguard enters or leaves bouncer mode.
+     * @param bouncer if true, keyguard is now in bouncer mode.
+     */
+    public void onKeyguardBouncerChanged(boolean bouncer) { }
+
+    /**
      * Called when visibility of lockscreen clock changes, such as when
      * obscured by a widget.
      */
@@ -168,9 +174,9 @@
 
     /**
      * Called when the screen turns off
-     * @param why {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER},
-     *   {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT} or
-     *   {@link WindowManagerPolicy#OFF_BECAUSE_OF_PROX_SENSOR}.
+     * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_ADMIN},
+     * {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER}, or
+     * {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT}.
      */
     public void onScreenTurnedOff(int why) { }
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
index d8e5b8a..a9206e7 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
@@ -297,7 +297,7 @@
      * @param event The key event
      * @return whether the event was consumed as a media key.
      */
-    private boolean interceptMediaKey(KeyEvent event) {
+    public boolean interceptMediaKey(KeyEvent event) {
         final int keyCode = event.getKeyCode();
         if (event.getAction() == KeyEvent.ACTION_DOWN) {
             switch (keyCode) {
diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml
index d86acb8..3b94d6d 100644
--- a/packages/PrintSpooler/res/values-am/strings.xml
+++ b/packages/PrintSpooler/res/values-am/strings.xml
@@ -58,7 +58,7 @@
     <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>
-    <string name="cancel" msgid="4373674107267141885">"ይቅር"</string>
+    <string name="cancel" msgid="4373674107267141885">"ሰርዝ"</string>
     <string name="restart" msgid="2472034227037808749">"እንደገና ጀምር"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"ከአታሚ ጋር ምንም ግንኙነት የለም"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"አይታወቅም"</string>
diff --git a/packages/PrintSpooler/res/values-da/strings.xml b/packages/PrintSpooler/res/values-da/strings.xml
index 1a871f8..74190b4 100644
--- a/packages/PrintSpooler/res/values-da/strings.xml
+++ b/packages/PrintSpooler/res/values-da/strings.xml
@@ -69,8 +69,8 @@
     <item msgid="2762241247228983754">"Farve"</item>
   </string-array>
   <string-array name="orientation_labels">
-    <item msgid="4061931020926489228">"Stående"</item>
-    <item msgid="3199660090246166812">"Liggende"</item>
+    <item msgid="4061931020926489228">"Portræt"</item>
+    <item msgid="3199660090246166812">"Landskab"</item>
   </string-array>
   <string-array name="page_options_labels">
     <item msgid="7421377442011699994">"Alle"</item>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index 17fabdc..cfb557e 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -33,7 +33,7 @@
     <string name="page_count_unknown" msgid="6058852665954511124">"Pages"</string>
     <string name="generating_print_job" msgid="3119608742651698916">"Génération tâche impression…"</string>
     <string name="save_as_pdf" msgid="5718454119847596853">"Enregistrer au format .PDF"</string>
-    <string name="all_printers" msgid="5018829726861876202">"Toutes les imprim."</string>
+    <string name="all_printers" msgid="5018829726861876202">"Toutes les imprimantes…"</string>
     <string name="print_dialog" msgid="32628687461331979">"Boîte de dialogue d\'impression"</string>
     <string name="search" msgid="5421724265322228497">"Rechercher"</string>
     <string name="all_printers_label" msgid="3178848870161526399">"Toutes les imprimantes"</string>
diff --git a/packages/PrintSpooler/res/values-ja/strings.xml b/packages/PrintSpooler/res/values-ja/strings.xml
index d3f4f85..f8be5c7 100644
--- a/packages/PrintSpooler/res/values-ja/strings.xml
+++ b/packages/PrintSpooler/res/values-ja/strings.xml
@@ -23,7 +23,7 @@
     <string name="label_destination" msgid="9132510997381599275">"印刷先"</string>
     <string name="label_copies" msgid="3634531042822968308">"部数"</string>
     <string name="label_paper_size" msgid="8681895607876809323">"用紙サイズ"</string>
-    <string name="label_color" msgid="1108690305218188969">"カラー選択"</string>
+    <string name="label_color" msgid="1108690305218188969">"カラー"</string>
     <string name="label_orientation" msgid="2853142581990496477">"方向"</string>
     <string name="label_pages" msgid="6300874667546617333">"ページ(<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
     <string name="pages_range_example" msgid="8558694453556945172">"例: 1-5,8,11-13"</string>
@@ -66,7 +66,7 @@
     <string name="print_error_default_message" msgid="8568506918983980567">"印刷ジョブを生成できませんでした"</string>
   <string-array name="color_mode_labels">
     <item msgid="7602948745415174937">"モノクロ"</item>
-    <item msgid="2762241247228983754">"カラー"</item>
+    <item msgid="2762241247228983754">"色"</item>
   </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"縦向き"</item>
diff --git a/packages/PrintSpooler/res/values-km-rKH/strings.xml b/packages/PrintSpooler/res/values-km-rKH/strings.xml
index c89f9bf..ba3c042 100644
--- a/packages/PrintSpooler/res/values-km-rKH/strings.xml
+++ b/packages/PrintSpooler/res/values-km-rKH/strings.xml
@@ -60,7 +60,7 @@
   </plurals>
     <string name="cancel" msgid="4373674107267141885">"បោះបង់"</string>
     <string name="restart" msgid="2472034227037808749">"ចាប់ផ្ដើម​ឡើងវិញ"</string>
-    <string name="no_connection_to_printer" msgid="2159246915977282728">"គ្មាន​​​ការ​ភ្ជាប់​ទៅ​ម៉ាស៊ីន​បោះពុម្ព"</string>
+    <string name="no_connection_to_printer" msgid="2159246915977282728">"គ្មាន​​​ការ​ភ្ជាប់​ទៅ​ម៉ាស៊ីន​បោះពុម្ព​"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"មិន​ស្គាល់"</string>
     <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – មិន​អាច​ប្រើ​បាន"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"មិន​អាច​បង្កើត​ការ​ងារ​បោះពុម្ព"</string>
diff --git a/packages/PrintSpooler/res/values-sl/strings.xml b/packages/PrintSpooler/res/values-sl/strings.xml
index e299508..5d4fe94 100644
--- a/packages/PrintSpooler/res/values-sl/strings.xml
+++ b/packages/PrintSpooler/res/values-sl/strings.xml
@@ -69,7 +69,7 @@
     <item msgid="2762241247228983754">"Barvno"</item>
   </string-array>
   <string-array name="orientation_labels">
-    <item msgid="4061931020926489228">"Pokončno"</item>
+    <item msgid="4061931020926489228">"Navpično"</item>
     <item msgid="3199660090246166812">"Ležeče"</item>
   </string-array>
   <string-array name="page_options_labels">
diff --git a/packages/PrintSpooler/res/values-sw/strings.xml b/packages/PrintSpooler/res/values-sw/strings.xml
index a84e9b3..55c8687 100644
--- a/packages/PrintSpooler/res/values-sw/strings.xml
+++ b/packages/PrintSpooler/res/values-sw/strings.xml
@@ -31,7 +31,7 @@
     <string name="install_for_print_preview" msgid="6366303997385509332">"Sakinisha kitazamaji cha PDF kwa onyesho la kuchungulia"</string>
     <string name="printing_app_crashed" msgid="854477616686566398">"Programu ya kuchapisha imeacha kufanya kazi"</string>
     <string name="page_count_unknown" msgid="6058852665954511124">"Kurasa"</string>
-    <string name="generating_print_job" msgid="3119608742651698916">"Inaleta kazi ya kuchapisha"</string>
+    <string name="generating_print_job" msgid="3119608742651698916">"Inazanzisha kazi ya kuchapisha"</string>
     <string name="save_as_pdf" msgid="5718454119847596853">"Hifadhi kama PDF"</string>
     <string name="all_printers" msgid="5018829726861876202">"Printa zote..."</string>
     <string name="print_dialog" msgid="32628687461331979">"Chapisha mazungumzo"</string>
@@ -63,7 +63,7 @@
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Hakuna muunganisho kwa printa"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"haijulikani"</string>
     <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> - haipatikani"</string>
-    <string name="print_error_default_message" msgid="8568506918983980567">"Haikuweza kuleta kazi ya kuchapisha"</string>
+    <string name="print_error_default_message" msgid="8568506918983980567">"Haikuweza kuunda kazi ya kuchapisha"</string>
   <string-array name="color_mode_labels">
     <item msgid="7602948745415174937">"Nyeusi na Nyeupe"</item>
     <item msgid="2762241247228983754">"Rangi"</item>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 59b486f..bf97fc0 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -189,4 +189,7 @@
     <!-- Default for Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, 1==on -->
     <integer name="def_heads_up_enabled">1</integer>
 
+    <!-- Default for Settings.Global.DEVICE_NAME $1=BRAND $2=MODEL-->
+    <string name="def_device_name">%1$s %2$s</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 58086c4..909c32e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -31,6 +31,7 @@
 import android.media.AudioManager;
 import android.media.AudioService;
 import android.net.ConnectivityManager;
+import android.os.Build;
 import android.os.Environment;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -69,7 +70,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 101;
+    private static final int DATABASE_VERSION = 102;
 
     private Context mContext;
     private int mUserHandle;
@@ -1614,6 +1615,23 @@
             upgradeVersion = 101;
         }
 
+        if (upgradeVersion == 101) {
+            if (mUserHandle == UserHandle.USER_OWNER) {
+                db.beginTransaction();
+                SQLiteStatement stmt = null;
+                try {
+                    stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
+                            + " VALUES(?,?);");
+                    loadSetting(stmt, Settings.Global.DEVICE_NAME, getDefaultDeviceName());
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                    if (stmt != null) stmt.close();
+                }
+            }
+            upgradeVersion = 102;
+        }
+
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
@@ -2342,6 +2360,8 @@
             loadIntegerSetting(stmt, Global.HEADS_UP_NOTIFICATIONS_ENABLED,
                     R.integer.def_heads_up_enabled);
 
+            loadSetting(stmt, Settings.Global.DEVICE_NAME, getDefaultDeviceName());
+
             // --- New global settings start here
         } finally {
             if (stmt != null) stmt.close();
@@ -2398,4 +2418,9 @@
         }
         return defaultValue;
     }
+
+    private String getDefaultDeviceName() {
+        return mContext.getResources().getString(R.string.def_device_name, Build.BRAND,
+                Build.MODEL);
+    }
 }
diff --git a/packages/Shell/res/values-el/strings.xml b/packages/Shell/res/values-el/strings.xml
index 9b1eb7b..3669f78 100644
--- a/packages/Shell/res/values-el/strings.xml
+++ b/packages/Shell/res/values-el/strings.xml
@@ -18,7 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="3701846017049540910">"Κέλυφος"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Η λήψη της αναφοράς ήταν επιτυχής"</string>
-    <string name="bugreport_finished_text" msgid="3559904746859400732">"Αγγίξτε για να μοιραστείτε τη αναφορά σφαλμάτων"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Αγγίξτε για κοινή χρήση της αναφοράς σας σφαλμάτων"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Οι αναφορές σφαλμάτων περιέχουν δεδομένα από τα διάφορα αρχεία καταγραφής του συστήματος, συμπεριλαμβανομένων προσωπικών και ιδιωτικών πληροφοριών. Να μοιράζεστε αναφορές σφαλμάτων μόνο με εφαρμογές και άτομα που εμπιστεύεστε."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Εμφάνιση αυτού του μηνύματος την επόμενη φορά"</string>
 </resources>
diff --git a/packages/Shell/res/values-sk/strings.xml b/packages/Shell/res/values-sk/strings.xml
index 59c3ccf..99f36f9 100644
--- a/packages/Shell/res/values-sk/strings.xml
+++ b/packages/Shell/res/values-sk/strings.xml
@@ -17,8 +17,8 @@
 <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">"Prostredie"</string>
-    <string name="bugreport_finished_title" msgid="2293711546892863898">"Hlásenie o chybách bolo vytvorené"</string>
-    <string name="bugreport_finished_text" msgid="3559904746859400732">"Hlásenie o chybách môžete zdielať klepnutím"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Správa o chybách sa zaznamenala"</string>
+    <string name="bugreport_finished_text" msgid="3559904746859400732">"Dotykom môžete zdieľať správu o chybách"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Správy o chybách obsahujú údaje z rôznych súborov denníkov systému vrátane osobných a súkromných informácií. Zdieľajte ich iba s dôveryhodnými aplikáciami a ľuďmi."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Zobraziť túto správu nabudúce"</string>
 </resources>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 327df8d..6b62c25 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -98,6 +98,9 @@
     <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
     <uses-permission android:name="android.permission.TRUST_LISTENER" />
 
+    <!-- Recents -->
+    <uses-permission android:name="android.permission.BIND_APPWIDGET" />
+
     <!-- Wifi Display -->
     <uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
 
@@ -138,7 +141,7 @@
                 android:exported="true" />
 
         <receiver android:name=".BootReceiver" androidprv:primaryUserOnly="true">
-            <intent-filter>
+            <intent-filter android:priority="1000">
                 <action android:name="android.intent.action.BOOT_COMPLETED" />
             </intent-filter>
         </receiver>
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_camera_alt_24dp.png b/packages/SystemUI/res/drawable-hdpi/ic_camera_alt_24dp.png
new file mode 100644
index 0000000..253c73792
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_camera_alt_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_ime_switcher_default.png b/packages/SystemUI/res/drawable-hdpi/ic_ime_switcher_default.png
new file mode 100644
index 0000000..369c88d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_ime_switcher_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-hdpi/ic_lock_24dp.png
new file mode 100644
index 0000000..c779437
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_lock_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png
deleted file mode 100644
index 54dde82..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png
deleted file mode 100644
index 3c0dc4e..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png
deleted file mode 100644
index 3b1944d..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png
deleted file mode 100644
index 693abf5..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_phone_24dp.png b/packages/SystemUI/res/drawable-hdpi/ic_phone_24dp.png
new file mode 100644
index 0000000..a6a6448
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_phone_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_auto_rotate.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_auto_rotate.png
deleted file mode 100644
index 63acea0..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_auto_rotate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_contrast_alpha.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_contrast_alpha.png
deleted file mode 100644
index 0f9dfc7..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_contrast_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_rotation_locked.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_rotation_locked.png
deleted file mode 100644
index f3dc08f..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_rotation_locked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.png
deleted file mode 100644
index c6f03c4..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_clear_normal.png
deleted file mode 100644
index c526433..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_clear_normal.png
deleted file mode 100644
index d13bc69..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_clear_normal.png
deleted file mode 100644
index a137a80..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_clear_normal.png
deleted file mode 100644
index 8da7945..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_camera_alt_24dp.png b/packages/SystemUI/res/drawable-mdpi/ic_camera_alt_24dp.png
new file mode 100644
index 0000000..ee1187b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_camera_alt_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_ime_switcher_default.png b/packages/SystemUI/res/drawable-mdpi/ic_ime_switcher_default.png
new file mode 100644
index 0000000..7d97eb5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_ime_switcher_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-mdpi/ic_lock_24dp.png
new file mode 100644
index 0000000..98ba690
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_lock_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png
deleted file mode 100644
index 7cb52e3..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png
deleted file mode 100644
index 8010ce7..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png
deleted file mode 100644
index 807f607..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png
deleted file mode 100644
index 15340d3..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_phone_24dp.png b/packages/SystemUI/res/drawable-mdpi/ic_phone_24dp.png
new file mode 100644
index 0000000..2286bb4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_phone_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_auto_rotate.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_auto_rotate.png
deleted file mode 100644
index ac6c1cf0..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_auto_rotate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_contrast_alpha.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_contrast_alpha.png
deleted file mode 100644
index a4dd087..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_contrast_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_rotation_locked.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_rotation_locked.png
deleted file mode 100644
index 3b7a284..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_rotation_locked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_camera.png
deleted file mode 100644
index 1c2d7aa..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_camera.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_camera_alt_24dp.png b/packages/SystemUI/res/drawable-xhdpi/ic_camera_alt_24dp.png
new file mode 100644
index 0000000..268eba0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_camera_alt_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_ime_switcher_default.png b/packages/SystemUI/res/drawable-xhdpi/ic_ime_switcher_default.png
new file mode 100644
index 0000000..900801a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_ime_switcher_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-xhdpi/ic_lock_24dp.png
new file mode 100644
index 0000000..61947ea
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_lock_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png
deleted file mode 100644
index b9afa44..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png
deleted file mode 100644
index 6d46fdd..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png
deleted file mode 100644
index e562bc2..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png
deleted file mode 100644
index e3cc9b0..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_phone_24dp.png b/packages/SystemUI/res/drawable-xhdpi/ic_phone_24dp.png
new file mode 100644
index 0000000..cd9ff60
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_phone_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_auto_rotate.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_auto_rotate.png
deleted file mode 100644
index c553bc2..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_auto_rotate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_contrast_alpha.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_contrast_alpha.png
deleted file mode 100644
index 9331e52..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_contrast_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_rotation_locked.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_rotation_locked.png
deleted file mode 100644
index b6daaf3..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_rotation_locked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_camera.png
deleted file mode 100644
index fbd4d6b..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_camera.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_camera_alt_24dp.png b/packages/SystemUI/res/drawable-xxhdpi/ic_camera_alt_24dp.png
new file mode 100644
index 0000000..9175118
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_camera_alt_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_ime_switcher_default.png b/packages/SystemUI/res/drawable-xxhdpi/ic_ime_switcher_default.png
new file mode 100644
index 0000000..6c8222e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_ime_switcher_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-xxhdpi/ic_lock_24dp.png
new file mode 100644
index 0000000..0b563b1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_lock_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_clear_normal.png
deleted file mode 100644
index afdee8f..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_open_normal.png
deleted file mode 100644
index 7742207..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_open_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_quicksettings_normal.png
deleted file mode 100644
index a2e8fe1..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_quicksettings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png
deleted file mode 100644
index e15981a..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_phone_24dp.png b/packages/SystemUI/res/drawable-xxhdpi/ic_phone_24dp.png
new file mode 100644
index 0000000..3c546e5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_phone_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_auto_rotate.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_auto_rotate.png
deleted file mode 100644
index b6cfaec..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_auto_rotate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_contrast_alpha.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_contrast_alpha.png
deleted file mode 100644
index 82c3842..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_contrast_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_rotation_locked.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_rotation_locked.png
deleted file mode 100644
index 8e37884..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_rotation_locked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_camera.png
deleted file mode 100644
index 86df881..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_camera.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_camera_alt_24dp.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_camera_alt_24dp.png
new file mode 100644
index 0000000..20e26b8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_camera_alt_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_lock_24dp.png
new file mode 100644
index 0000000..3600ee6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_lock_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_phone_24dp.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_phone_24dp.png
new file mode 100644
index 0000000..4f7da0a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_phone_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_notifications.xml b/packages/SystemUI/res/drawable/ic_notifications.xml
deleted file mode 100644
index 97a7623..0000000
--- a/packages/SystemUI/res/drawable/ic_notifications.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true"
-         android:drawable="@drawable/ic_notify_open_normal" />
-    <item
-         android:drawable="@drawable/ic_notify_open_normal" />
-</selector>
-
diff --git a/packages/SystemUI/res/drawable/ic_notify_clear.xml b/packages/SystemUI/res/drawable/ic_notify_clear.xml
deleted file mode 100644
index 2163198..0000000
--- a/packages/SystemUI/res/drawable/ic_notify_clear.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true"
-        android:drawable="@drawable/ic_notify_clear_normal" />
-    <item android:drawable="@drawable/ic_notify_clear_normal" />
-</selector>
diff --git a/packages/SystemUI/res/drawable/ic_notify_quicksettings.xml b/packages/SystemUI/res/drawable/ic_notify_quicksettings.xml
deleted file mode 100644
index 7cf3175..0000000
--- a/packages/SystemUI/res/drawable/ic_notify_quicksettings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true"
-         android:drawable="@drawable/ic_notify_quicksettings_normal" />
-    <item
-         android:drawable="@drawable/ic_notify_quicksettings_normal" />
-</selector>
-
diff --git a/packages/SystemUI/res/drawable/ic_notify_settings.xml b/packages/SystemUI/res/drawable/ic_notify_settings.xml
deleted file mode 100644
index 9303ca4..0000000
--- a/packages/SystemUI/res/drawable/ic_notify_settings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true"
-         android:drawable="@drawable/ic_notify_settings_normal" />
-    <item
-         android:drawable="@drawable/ic_notify_settings_normal" />
-</selector>
-
diff --git a/packages/SystemUI/res/drawable/ic_qs_airplane.xml b/packages/SystemUI/res/drawable/ic_qs_airplane.xml
new file mode 100644
index 0000000..ffe571f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_airplane.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M10.2,9.0"/>
+    <path
+        android:fill="#FF000000"
+        android:pathData="M21.0,16.0l0.0,-2.0l-8.0,-5.0L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5L10.0,9.0l-8.0,5.0l0.0,2.0l8.0,-2.5L10.0,19.0l-2.0,1.5L8.0,22.0l3.5,-1.0l3.5,1.0l0.0,-1.5L13.0,19.0l0.0,-5.5L21.0,16.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
new file mode 100644
index 0000000..22d0dcf
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M17.7,7.7L12.0,2.0l-1.0,0.0l0.0,7.6L6.4,5.0L5.0,6.4l5.6,5.6L5.0,17.6L6.4,19.0l4.6,-4.6L11.0,22.0l1.0,0.0l5.7,-5.7L13.4,12.0L17.7,7.7zM13.0,5.8l1.9,1.9L13.0,9.6L13.0,5.8zM14.9,16.3L13.0,18.2l0.0,-3.8L14.9,16.3z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bugreport.xml b/packages/SystemUI/res/drawable/ic_qs_bugreport.xml
new file mode 100644
index 0000000..2dfe183
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_bugreport.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M20.0,8.0l-2.8,0.0c-0.5,-0.8 -1.1,-1.5 -1.8,-2.0L17.0,4.4L15.6,3.0l-2.2,2.2C13.0,5.1 12.5,5.0 12.0,5.0s-1.0,0.1 -1.4,0.2L8.4,3.0L7.0,4.4L8.6,6.0C7.9,6.5 7.3,7.2 6.8,8.0L4.0,8.0l0.0,2.0l2.1,0.0C6.0,10.3 6.0,10.7 6.0,11.0l0.0,1.0L4.0,12.0l0.0,2.0l2.0,0.0l0.0,1.0c0.0,0.3 0.0,0.7 0.1,1.0L4.0,16.0l0.0,2.0l2.8,0.0c1.0,1.8 3.0,3.0 5.2,3.0s4.2,-1.2 5.2,-3.0L20.0,18.0l0.0,-2.0l-2.1,0.0c0.1,-0.3 0.1,-0.7 0.1,-1.0l0.0,-1.0l2.0,0.0l0.0,-2.0l-2.0,0.0l0.0,-1.0c0.0,-0.3 0.0,-0.7 -0.1,-1.0L20.0,10.0L20.0,8.0zM14.0,16.0l-4.0,0.0l0.0,-2.0l4.0,0.0L14.0,16.0zM14.0,12.0l-4.0,0.0l0.0,-2.0l4.0,0.0L14.0,12.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast.xml b/packages/SystemUI/res/drawable/ic_qs_cast.xml
new file mode 100644
index 0000000..6f2840b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_cast.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M21.0,3.0L3.0,3.0C1.9,3.0 1.0,3.9 1.0,5.0l0.0,3.0l2.0,0.0L3.0,5.0l18.0,0.0l0.0,14.0l-7.0,0.0l0.0,2.0l7.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L23.0,5.0C23.0,3.9 22.1,3.0 21.0,3.0zM1.0,18.0l0.0,3.0l3.0,0.0C4.0,19.3 2.7,18.0 1.0,18.0zM1.0,14.0l0.0,2.0c2.8,0.0 5.0,2.2 5.0,5.0l2.0,0.0C8.0,17.1 4.9,14.0 1.0,14.0zM1.0,10.0l0.0,2.0c5.0,0.0 9.0,4.0 9.0,9.0l2.0,0.0C12.0,14.9 7.1,10.0 1.0,10.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_close.xml b/packages/SystemUI/res/drawable/ic_qs_close.xml
new file mode 100644
index 0000000..c2c72c8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_close.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M19.0,6.4l-1.3999996,-1.4000001 -5.6000004,5.6000004 -5.6,-5.6000004 -1.4000001,1.4000001 5.6000004,5.6 -5.6000004,5.6000004 1.4000001,1.3999996 5.6,-5.6000004 5.6000004,5.6000004 1.3999996,-1.3999996 -5.6000004,-5.6000004z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_contrast_off.xml b/packages/SystemUI/res/drawable/ic_qs_contrast_off.xml
deleted file mode 100644
index 5f65d8a..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_contrast_off.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_qs_contrast_alpha"
-    android:tint="@color/ic_qs_off" />
diff --git a/packages/SystemUI/res/drawable/ic_qs_contrast_on.xml b/packages/SystemUI/res/drawable/ic_qs_contrast_on.xml
deleted file mode 100644
index a018929..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_contrast_on.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_qs_contrast_alpha"
-    android:tint="@color/ic_qs_on" />
diff --git a/packages/SystemUI/res/drawable/ic_qs_hotspot.xml b/packages/SystemUI/res/drawable/ic_qs_hotspot.xml
new file mode 100644
index 0000000..965e3c1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_hotspot.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M12.0,11.0c-1.1,0.0 -2.0,0.9 -2.0,2.0c0.0,1.1 0.9,2.0 2.0,2.0c1.1,0.0 2.0,-0.9 2.0,-2.0C14.0,11.9 13.1,11.0 12.0,11.0zM18.0,13.0c0.0,-3.3 -2.7,-6.0 -6.0,-6.0c-3.3,0.0 -6.0,2.7 -6.0,6.0c0.0,2.2 1.2,4.1 3.0,5.2l1.0,-1.7c-1.2,-0.7 -2.0,-2.0 -2.0,-3.4c0.0,-2.2 1.8,-4.0 4.0,-4.0s4.0,1.8 4.0,4.0c0.0,1.5 -0.8,2.8 -2.0,3.4l1.0,1.7C16.8,17.1 18.0,15.2 18.0,13.0zM12.0,3.0C6.5,3.0 2.0,7.5 2.0,13.0c0.0,3.7 2.0,6.9 5.0,8.6l1.0,-1.7c-2.4,-1.4 -4.0,-4.0 -4.0,-6.9c0.0,-4.4 3.6,-8.0 8.0,-8.0s8.0,3.6 8.0,8.0c0.0,3.0 -1.6,5.5 -4.0,6.9l1.0,1.7c3.0,-1.7 5.0,-5.0 5.0,-8.6C22.0,7.5 17.5,3.0 12.0,3.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_invert_colors.xml b/packages/SystemUI/res/drawable/ic_qs_invert_colors.xml
new file mode 100644
index 0000000..7c92052
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_invert_colors.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M18.939,7.244c-5.887,-5.885 -6.214,-6.214 -6.222,-6.222l-0.707,-0.737L5.088,7.207c-2.914,2.915 -3.74,6.629 -2.266,10.19c1.541,3.719 5.312,6.316 9.174,6.317l0.0,0.0c3.861,-0.001 7.636,-2.603 9.179,-6.328C22.646,13.834 21.832,10.138 18.939,7.244zM4.67,16.632c-1.149,-2.776 -0.481,-5.696 1.832,-8.011l5.494,-5.492c0.0,0.002 0.002,0.003 0.003,0.004l0.0,18.582c-0.001,0.0 -0.002,0.0 -0.003,0.0C8.922,21.714 5.91,19.624 4.67,16.632z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location.xml b/packages/SystemUI/res/drawable/ic_qs_location.xml
new file mode 100644
index 0000000..e6e98a0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_location.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M12.0,2.0C8.1,2.0 5.0,5.1 5.0,9.0c0.0,5.2 7.0,13.0 7.0,13.0s7.0,-7.8 7.0,-13.0C19.0,5.1 15.9,2.0 12.0,2.0zM12.0,11.5c-1.4,0.0 -2.5,-1.1 -2.5,-2.5s1.1,-2.5 2.5,-2.5c1.4,0.0 2.5,1.1 2.5,2.5S13.4,11.5 12.0,11.5z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_minus.xml b/packages/SystemUI/res/drawable/ic_qs_minus.xml
new file mode 100644
index 0000000..8323e89
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_minus.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M7.0,11.0l0.0,2.0l10.0,0.0l0.0,-2.0L7.0,11.0zM12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,20.0c-4.4,0.0 -8.0,-3.6 -8.0,-8.0s3.6,-8.0 8.0,-8.0c4.4,0.0 8.0,3.6 8.0,8.0S16.4,20.0 12.0,20.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_plus.xml b/packages/SystemUI/res/drawable/ic_qs_plus.xml
new file mode 100644
index 0000000..84cd72a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_plus.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M13.0,7.0l-2.0,0.0l0.0,4.0L7.0,11.0l0.0,2.0l4.0,0.0l0.0,4.0l2.0,0.0l0.0,-4.0l4.0,0.0l0.0,-2.0l-4.0,0.0L13.0,7.0zM12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,20.0c-4.4,0.0 -8.0,-3.6 -8.0,-8.0s3.6,-8.0 8.0,-8.0c4.4,0.0 8.0,3.6 8.0,8.0S16.4,20.0 12.0,20.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
new file mode 100644
index 0000000..fa6f20c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M3.0,9.0c0.0,0.0 0.0,6.0 0.0,6.0l4.0,0.0l5.0,5.0L12.0,4.0L7.0,9.0L3.0,9.0zM16.5,12.0c0.0,-1.8 -1.0,-3.3 -2.5,-4.0L14.0,16.0C15.5,15.3 16.5,13.8 16.5,12.0zM14.0,3.2l0.0,2.1c2.9,0.9 5.0,3.5 5.0,6.7s-2.1,5.8 -5.0,6.7l0.0,2.1c4.0,-0.9 7.0,-4.5 7.0,-8.8S18.0,4.1 14.0,3.2z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
new file mode 100644
index 0000000..0665196
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M16.5,12.0c0.0,-1.8 -1.0,-3.3 -2.5,-4.0l0.0,2.2l2.5,2.5C16.5,12.4 16.5,12.2 16.5,12.0zM19.0,12.0c0.0,0.9 -0.2,1.8 -0.5,2.6l1.5,1.5c0.7,-1.2 1.0,-2.7 1.0,-4.2c0.0,-4.3 -3.0,-7.9 -7.0,-8.8l0.0,2.1C16.9,6.2 19.0,8.8 19.0,12.0zM4.3,3.0L3.0,4.3L7.7,9.0L3.0,9.0c0.0,0.0 0.0,6.0 0.0,6.0l4.0,0.0l5.0,5.0l0.0,-6.7l4.3,4.3c-0.7,0.5 -1.4,0.9 -2.3,1.2l0.0,2.1c1.4,-0.3 2.6,-0.9 3.7,-1.8l2.0,2.0l1.3,-1.3l-9.0,-9.0L4.3,3.0zM12.0,4.0L9.9,6.1L12.0,8.2L12.0,4.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml
new file mode 100644
index 0000000..299a2ef
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_zen.xml b/packages/SystemUI/res/drawable/ic_qs_zen.xml
new file mode 100644
index 0000000..059c068
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_zen.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FF000000"
+        android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,16.0l0.0,-5.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0L18.0,16.0zM14.0,9.8l-2.8,3.4L14.0,13.200001L14.0,15.0L9.0,15.0l0.0,-1.8l2.8,-3.4L9.0,9.799999L9.0,8.0l5.0,0.0L14.0,9.8z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_01.xml b/packages/SystemUI/res/drawable/ic_rotate_24_01.xml
new file mode 100644
index 0000000..a6c2cf8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_01.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M10.25,1.75c-0.6,-0.6 -1.5,-0.6 -2.1,0.0l-6.4,6.4c-0.6,0.6 -0.6,1.5 0.0,2.1l12.0,12.0c0.6,0.6 1.5,0.6 2.1,0.0l6.4,-6.4c0.6,-0.6 0.6,-1.5 0.0,-2.1L10.25,1.75zM14.85,21.25l-12.0,-12.0l6.4,-6.4l12.0,12.0L14.85,21.25z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M16.55,2.5c3.3,1.5 5.6,4.7 6.0,8.5l1.5,0.0c-0.6,-6.2 -5.7,-11.0 -12.0,-11.0c-0.2,0.0 -0.4,0.0 -0.7,0.0l3.8,3.8L16.55,2.5z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M7.55,21.5c-3.3,-1.5 -5.6,-4.7 -6.0,-8.5l-1.4,0.0c0.5,6.2 5.6,11.0 11.9,11.0c0.2,0.0 0.4,0.0 0.7,0.0l-3.8,-3.8L7.55,21.5z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_02.xml b/packages/SystemUI/res/drawable/ic_rotate_24_02.xml
new file mode 100644
index 0000000..4107c46
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_02.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M10.24,2.43C9.67,1.88 8.83,1.88 8.28,2.45L2.34,8.48c-0.56,0.57 -0.55,1.41 0.02,1.96l11.3,11.13c0.57,0.56 1.41,0.55 1.96,-0.02l5.93,-6.03c0.56,-0.57 0.55,-1.41 -0.02,-1.96L10.24,2.43zM14.68,20.62L3.38,9.5l5.93,-6.03l11.3,11.13L14.68,20.62z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M16.91,2.71c3.23,1.64 5.39,4.94 5.62,8.76l1.5,0.07c-0.33,-6.22 -5.21,-11.24 -11.5,-11.52c-0.2,-0.01 -0.4,-0.02 -0.7,-0.03l3.63,3.96L16.91,2.71z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M7.09,21.29c-3.23,-1.64 -5.39,-4.94 -5.62,-8.76l-1.4,-0.06c0.23,6.22 5.11,11.24 11.4,11.51c0.2,0.01 0.4,0.02 0.7,0.03l-3.63,-3.96L7.09,21.29z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_03.xml b/packages/SystemUI/res/drawable/ic_rotate_24_03.xml
new file mode 100644
index 0000000..127296c4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_03.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M11.07,4.12c-0.43,-0.49 -1.11,-0.53 -1.6,-0.1L4.3,8.57C3.81,9.0 3.77,9.68 4.19,10.17l8.54,9.71c0.43,0.49 1.11,0.53 1.6,0.1l5.18,-4.55c0.49,-0.43 0.53,-1.11 0.1,-1.6L11.07,4.12zM13.61,19.17L5.08,9.46l5.18,-4.55l8.54,9.71L13.61,19.17z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M17.72,3.2c3.06,1.94 4.9,5.43 4.77,9.25l1.49,0.21C24.23,6.43 19.84,0.97 13.6,0.11c-0.2,-0.03 -0.4,-0.06 -0.69,-0.1l3.24,4.29L17.72,3.2z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M6.19,20.78c-3.06,-1.94 -4.9,-5.43 -4.77,-9.25l-1.39,-0.19c-0.36,6.21 4.03,11.67 10.27,12.53c0.2,0.03 0.4,0.06 0.69,0.1l-3.24,-4.29L6.19,20.78z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_04.xml b/packages/SystemUI/res/drawable/ic_rotate_24_04.xml
new file mode 100644
index 0000000..d00262a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_04.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M11.88,5.72c-0.3,-0.42 -0.83,-0.51 -1.25,-0.21L6.19,8.69c-0.42,0.3 -0.51,0.83 -0.21,1.25l5.95,8.34c0.3,0.42 0.83,0.51 1.25,0.21l4.45,-3.17c0.42,-0.3 0.51,-0.83 0.21,-1.25L11.88,5.72zM12.68,17.79L6.73,9.45l4.45,-3.17l5.95,8.34L12.68,17.79z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M18.8,4.01c2.79,2.32 4.16,6.01 3.54,9.78l1.45,0.4c1.06,-6.14 -2.59,-12.11 -8.67,-13.78c-0.19,-0.05 -0.39,-0.11 -0.68,-0.18l2.66,4.67L18.8,4.01z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M5.11,19.96c-2.79,-2.32 -4.16,-6.01 -3.54,-9.78L0.21,9.81c-1.15,6.11 2.5,12.09 8.57,13.75c0.19,0.05 0.39,0.11 0.68,0.18L6.8,19.08L5.11,19.96z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_05.xml b/packages/SystemUI/res/drawable/ic_rotate_24_05.xml
new file mode 100644
index 0000000..570f51f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_05.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M15.41,8.14c0.05,-0.42 -0.23,-0.78 -0.65,-0.83l-4.5,-0.54C9.84,6.72 9.48,7.0 9.43,7.42l-1.01,8.44c-0.05,0.42 0.23,0.78 0.65,0.83l4.5,0.54C14.0,17.28 14.35,17.0 14.4,16.58L15.41,8.14zM9.16,15.99l1.01,-8.44l4.5,0.54l-1.01,8.44L9.16,15.99z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M22.35,10.28c0.64,3.57 -0.69,7.28 -3.59,9.77l0.85,1.23c4.76,-4.01 5.82,-10.94 2.24,-16.12c-0.11,-0.16 -0.23,-0.33 -0.4,-0.58l-0.97,5.29L22.35,10.28z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M1.6,13.66c-0.64,-3.57 0.69,-7.28 3.59,-9.77L4.4,2.74c-4.82,3.93 -5.88,10.86 -2.3,16.04c0.11,0.16 0.23,0.33 0.4,0.58l0.97,-5.29L1.6,13.66z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_06.xml b/packages/SystemUI/res/drawable/ic_rotate_24_06.xml
new file mode 100644
index 0000000..aaf9356
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_06.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M15.62,13.08c0.29,-0.1 0.44,-0.39 0.34,-0.69L14.9,9.27c-0.1,-0.29 -0.39,-0.44 -0.69,-0.34l-5.86,1.98c-0.29,0.1 -0.44,0.39 -0.34,0.69l1.06,3.12c0.1,0.29 0.39,0.44 0.69,0.34L15.62,13.08zM8.51,11.44l5.86,-1.98l1.06,3.12l-5.86,1.98L8.51,11.44z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M18.53,20.21c-2.8,2.3 -6.69,2.95 -10.27,1.64L7.6,23.2c5.83,2.2 12.39,-0.26 15.16,-5.92c0.09,-0.18 0.18,-0.36 0.31,-0.63l-5.09,1.73L18.53,20.21z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M5.45,3.76c2.8,-2.3 6.69,-2.95 10.27,-1.64l0.62,-1.26C10.56,-1.42 4.0,1.04 1.22,6.69C1.13,6.87 1.05,7.05 0.91,7.32L6.0,5.59L5.45,3.76z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_07.xml b/packages/SystemUI/res/drawable/ic_rotate_24_07.xml
new file mode 100644
index 0000000..330ce6a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_07.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M12.23,14.48c0.13,0.16 0.35,0.17 0.5,0.04l1.66,-1.4c0.16,-0.13 0.17,-0.35 0.04,-0.5l-2.62,-3.11c-0.13,-0.16 -0.35,-0.17 -0.5,-0.04l-1.66,1.4c-0.16,0.13 -0.17,0.35 -0.04,0.5L12.23,14.48zM11.53,9.73l2.62,3.11l-1.66,1.4l-2.62,-3.11L11.53,9.73z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M6.04,20.63c-3.01,-2.02 -4.75,-5.56 -4.52,-9.37l-1.48,-0.25c-0.43,6.21 3.81,11.79 10.02,12.83c0.2,0.03 0.39,0.07 0.69,0.12l-3.12,-4.37L6.04,20.63z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M18.04,3.37c3.01,2.02 4.75,5.56 4.52,9.37l1.38,0.23c0.53,-6.2 -3.71,-11.77 -9.93,-12.81c-0.2,-0.03 -0.39,-0.07 -0.69,-0.12l3.12,4.37L18.04,3.37z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_08.xml b/packages/SystemUI/res/drawable/ic_rotate_24_08.xml
new file mode 100644
index 0000000..1c7f1a1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_08.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M10.55,12.73c-0.06,0.12 -0.02,0.25 0.1,0.32l1.26,0.68c0.12,0.06 0.25,0.02 0.32,-0.1l1.27,-2.36c0.06,-0.12 0.02,-0.25 -0.1,-0.32l-1.26,-0.68c-0.12,-0.06 -0.25,-0.02 -0.32,0.1L10.55,12.73zM13.29,11.15l-1.27,2.36l-1.26,-0.68l1.27,-2.36L13.29,11.15z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M1.55,12.95C1.18,9.34 2.78,5.74 5.86,3.47L5.1,2.18C0.05,5.83 -1.51,12.66 1.67,18.09c0.1,0.17 0.2,0.35 0.35,0.6l1.36,-5.2L1.55,12.95z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M22.5,11.12c0.37,3.61 -1.23,7.21 -4.31,9.47l0.71,1.21c5.1,-3.56 6.67,-10.39 3.48,-15.83c-0.1,-0.17 -0.2,-0.35 -0.35,-0.6l-1.36,5.2L22.5,11.12z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_09.xml b/packages/SystemUI/res/drawable/ic_rotate_24_09.xml
new file mode 100644
index 0000000..ebfbad6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_09.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:pathData="M11.45,12c0,0.14,0.12,0.25,0.25,0.25l0.06,0l0,-0.5l-0.06,0C11.57,11.75,11.45,11.86,11.45,12z"
+        android:fill="#00000000"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M11.77,11.62l-0.06,0.0c-0.21,0.0 -0.37,0.17 -0.38,0.37c0.0,0.21 0.17,0.37 0.37,0.37l0.06,0.0c0.0,0.07 0.06,0.12 0.12,0.13l0.62,0.0c0.07,0.0 0.12,-0.06 0.13,-0.12l0.0,-0.75c0.0,-0.07 -0.06,-0.12 -0.12,-0.13l-0.62,0.0C11.83,11.5 11.77,11.56 11.77,11.62zM12.33,12.0c0.0,0.07 -0.06,0.12 -0.13,0.12c-0.07,0.0 -0.12,-0.06 -0.12,-0.13c0.0,-0.07 0.06,-0.12 0.13,-0.12C12.28,11.88 12.33,11.93 12.33,12.0zM11.77,11.75l0.0,0.5l-0.06,0.0c-0.14,0.0 -0.26,-0.11 -0.25,-0.25c0.0,-0.14 0.12,-0.25 0.26,-0.25L11.77,11.75z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M3.83,5.44c2.21,-2.87 5.85,-4.38 9.64,-3.9l0.34,-1.46C7.64,-0.75 1.81,3.12 0.37,9.25C0.32,9.45 0.28,9.64 0.21,9.93L4.78,7.1L3.83,5.44zM20.28,18.53c-2.21,2.87 -5.85,4.38 -9.64,3.9l-0.32,1.36c6.15,0.93 11.99,-2.95 13.42,-9.08c0.05,-0.19 0.09,-0.39 0.16,-0.68l-4.57,2.83L20.28,18.53z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_10.xml b/packages/SystemUI/res/drawable/ic_rotate_24_10.xml
new file mode 100644
index 0000000..21dda8c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_10.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:pathData="M10.42,9.96c-0.42,0.42,-0.39,1.12,0.03,1.54l0.19,0.19l1.51,-1.53l-0.19,-0.19       C11.54,9.55,10.84,9.54,10.42,9.96z"
+        android:fill="#00000000"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M12.53,9.78l-0.19,-0.19c-0.63,-0.63 -1.66,-0.62 -2.28,0.02c-0.63,0.63 -0.62,1.66 0.02,2.28l0.19,0.19c-0.21,0.21 -0.21,0.55 0.01,0.76l1.92,1.89c0.21,0.21 0.55,0.21 0.76,-0.01l2.27,-2.3c0.21,-0.21 0.21,-0.55 -0.01,-0.76l-1.92,-1.89C13.08,9.56 12.74,9.56 12.53,9.78zM13.12,12.62c-0.21,0.21 -0.55,0.21 -0.76,0.01c-0.21,-0.21 -0.21,-0.55 -0.01,-0.76c0.21,-0.21 0.55,-0.21 0.76,-0.01C13.33,12.07 13.33,12.41 13.12,12.62zM12.15,10.16l-1.51,1.53l-0.19,-0.19c-0.42,-0.42 -0.45,-1.12 -0.03,-1.54c0.42,-0.42 1.12,-0.41 1.54,0.01L12.15,10.16z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M7.82,2.36c3.3,-1.49 7.23,-1.12 10.35,1.09l0.99,-1.13C14.09,-1.32 7.12,-0.64 2.97,4.1C2.84,4.25 2.71,4.4 2.51,4.62l5.36,-0.36L7.82,2.36zM16.18,21.64c-3.3,1.49 -7.23,1.12 -10.35,-1.09l-0.92,1.05c4.99,3.71 11.97,3.03 16.12,-1.71c0.13,-0.15 0.26,-0.3 0.46,-0.53l-5.36,0.36L16.18,21.64z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_11.xml b/packages/SystemUI/res/drawable/ic_rotate_24_11.xml
new file mode 100644
index 0000000..f4186fe
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_11.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:pathData="M10.53,8.85c-0.7,0.37,-0.95,1.28,-0.58,1.98l0.17,0.32l2.55,-1.36L12.5,9.48       C12.12,8.78,11.23,8.48,10.53,8.85z"
+        android:fill="#00000000"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M13.3,9.46l-0.17,-0.32c-0.56,-1.05 -1.87,-1.45 -2.93,-0.89s-1.45,1.87 -0.89,2.93l0.17,0.32c-0.35,0.19 -0.48,0.62 -0.3,0.98l1.7,3.18c0.19,0.35 0.62,0.48 0.98,0.3l3.82,-2.04c0.35,-0.19 0.48,-0.62 0.3,-0.98l-1.7,-3.18C14.09,9.4 13.65,9.27 13.3,9.46zM12.92,13.34c-0.35,0.19 -0.79,0.06 -0.98,-0.3c-0.19,-0.35 -0.05,-0.79 0.3,-0.98c0.35,-0.19 0.79,-0.05 0.98,0.3C13.41,12.72 13.27,13.15 12.92,13.34zM12.67,9.8l-2.55,1.36l-0.17,-0.32c-0.37,-0.7 -0.13,-1.61 0.58,-1.98c0.7,-0.37 1.59,-0.08 1.97,0.63L12.67,9.8z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M11.48,1.5c3.62,-0.23 7.16,1.5 9.3,4.66l1.32,-0.71C18.65,0.27 11.89,-1.55 6.34,1.42C6.16,1.51 5.98,1.61 5.72,1.75l5.14,1.56L11.48,1.5zM12.52,22.5c-3.62,0.23 -7.16,-1.5 -9.3,-4.66L1.98,18.5c3.37,5.23 10.13,7.06 15.68,4.08c0.18,-0.09 0.35,-0.19 0.62,-0.33l-5.14,-1.56L12.52,22.5z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_12.xml b/packages/SystemUI/res/drawable/ic_rotate_24_12.xml
new file mode 100644
index 0000000..d408e28
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_12.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:pathData="M10.83,8.49c-0.91,0.3,-1.39,1.31,-1.09,2.22l0.13,0.41l3.28,-1.08l-0.13,-0.41       C12.72,8.72,11.73,8.19,10.83,8.49z"
+        android:fill="#00000000"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M13.98,9.77l-0.13,-0.41C13.4,8.0 11.93,7.26 10.57,7.71c-1.36,0.45 -2.1,1.91 -1.65,3.27l0.13,0.41c-0.45,0.15 -0.7,0.64 -0.55,1.09l1.35,4.1c0.15,0.45 0.64,0.7 1.09,0.55l4.92,-1.62c0.45,-0.15 0.7,-0.64 0.55,-1.09l-1.35,-4.1C14.92,9.87 14.43,9.62 13.98,9.77zM12.73,14.27c-0.45,0.15 -0.94,-0.1 -1.09,-0.55c-0.15,-0.45 0.1,-0.94 0.55,-1.09c0.45,-0.15 0.94,0.1 1.09,0.55C13.43,13.64 13.18,14.12 12.73,14.27zM13.16,10.04l-3.28,1.08l-0.13,-0.41c-0.3,-0.91 0.18,-1.92 1.09,-2.22c0.91,-0.3 1.9,0.24 2.19,1.14L13.16,10.04z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M13.55,1.6c3.59,0.48 6.72,2.87 8.21,6.39l1.44,-0.44C20.82,1.8 14.54,-1.31 8.51,0.52c-0.19,0.06 -0.38,0.12 -0.67,0.2l4.74,2.53L13.55,1.6zM10.45,22.4c-3.59,-0.48 -6.72,-2.87 -8.21,-6.39L0.9,16.41c2.28,5.79 8.55,8.9 14.58,7.07c0.19,-0.06 0.38,-0.12 0.67,-0.2l-4.74,-2.53L10.45,22.4z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_13.xml b/packages/SystemUI/res/drawable/ic_rotate_24_13.xml
new file mode 100644
index 0000000..1ac6b39
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_13.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:pathData="M11.17,7.71c-1.09,0.19,-1.8,1.28,-1.61,2.37l0.09,0.49l3.94,-0.7l-0.09,-0.49C13.3,8.3,12.26,7.52,11.17,7.71       z"
+        android:fill="#00000000"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M14.57,9.7l-0.09,-0.49C14.19,7.58 12.63,6.49 11.0,6.78c-1.63,0.29 -2.71,1.85 -2.43,3.48l0.08,0.49c-0.54,0.1 -0.91,0.62 -0.81,1.16l0.87,4.92c0.1,0.54 0.62,0.91 1.16,0.81l5.91,-1.05c0.54,-0.1 0.91,-0.61 0.81,-1.16l-0.87,-4.92C15.63,9.97 15.11,9.61 14.57,9.7zM12.4,14.66c-0.54,0.1 -1.06,-0.27 -1.16,-0.81c-0.1,-0.54 0.27,-1.06 0.81,-1.16s1.06,0.27 1.16,0.81C13.3,14.04 12.94,14.56 12.4,14.66zM13.58,9.88l-3.94,0.7l-0.09,-0.49c-0.19,-1.09 0.52,-2.17 1.61,-2.37s2.13,0.58 2.33,1.67L13.58,9.88z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M14.99,1.92c3.49,0.97 6.26,3.78 7.24,7.48l1.48,-0.23c-1.55,-6.03 -7.32,-9.99 -13.55,-9.02c-0.2,0.03 -0.4,0.06 -0.69,0.11l4.34,3.17L14.99,1.92zM9.01,22.08C5.52,21.1 2.76,18.3 1.78,14.6L0.4,14.82c1.45,6.05 7.22,10.01 13.45,9.04c0.2,-0.03 0.4,-0.06 0.69,-0.11l-4.34,-3.17L9.01,22.08z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_14.xml b/packages/SystemUI/res/drawable/ic_rotate_24_14.xml
new file mode 100644
index 0000000..c43e363c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_14.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:pathData="M11.72,7.61c-1.1,0.08,-1.93,1.08,-1.86,2.18l0.03,0.5l3.99,-0.27l-0.03,-0.5       C13.78,8.42,12.82,7.54,11.72,7.61z"
+        android:fill="#00000000"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M14.88,9.95l-0.03,-0.5c-0.11,-1.65 -1.54,-2.9 -3.2,-2.79C10.0,6.78 8.75,8.21 8.87,9.86l0.03,0.5c-0.55,0.04 -0.97,0.52 -0.93,1.07l0.34,4.99c0.04,0.55 0.52,0.97 1.07,0.93l5.99,-0.41c0.55,-0.04 0.97,-0.51 0.93,-1.07l-0.34,-4.99C15.91,10.33 15.43,9.91 14.88,9.95zM12.2,14.64c-0.55,0.04 -1.03,-0.38 -1.07,-0.93c-0.04,-0.55 0.38,-1.03 0.93,-1.07c0.55,-0.04 1.03,0.38 1.07,0.93C13.16,14.13 12.75,14.61 12.2,14.64zM13.88,10.02l-3.99,0.27l-0.03,-0.5c-0.08,-1.1 0.75,-2.11 1.86,-2.18c1.1,-0.08 2.06,0.81 2.13,1.91L13.88,10.02z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M15.71,2.17c3.41,1.23 5.96,4.23 6.67,7.98l1.5,-0.12c-1.1,-6.13 -6.58,-10.5 -12.86,-9.99c-0.2,0.02 -0.4,0.03 -0.7,0.06l4.1,3.48L15.71,2.17zM8.29,21.83c-3.41,-1.23 -5.96,-4.23 -6.67,-7.98l-1.4,0.11c1.0,6.14 6.48,10.51 12.76,9.99c0.2,-0.02 0.4,-0.03 0.7,-0.06l-4.1,-3.48L8.29,21.83z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_15.xml b/packages/SystemUI/res/drawable/ic_rotate_24_15.xml
new file mode 100644
index 0000000..22fa428
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_15.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:pathData="M12.05,7.7c-1.1,0,-2,0.94,-2,2.05v0.5h4v-0.5C14.05,8.65,13.15,7.7,12.05,7.7z"
+        android:fill="#00000000"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M15.05,10.25l0.0,-0.5c0.0,-1.66 -1.34,-3.0 -3.0,-3.0s-2.99,1.34 -2.99,3.0l-0.01,0.5c-0.55,0.0 -1.0,0.45 -1.0,1.0l0.0,5.0c0.0,0.55 0.45,1.0 1.0,1.0l6.0,0.0c0.55,0.0 1.0,-0.45 1.0,-1.0l0.0,-5.0C16.05,10.7 15.6,10.25 15.05,10.25zM12.05,14.75c-0.55,0.0 -1.0,-0.45 -1.0,-1.0c0.0,-0.55 0.45,-1.0 1.0,-1.0s1.0,0.45 1.0,1.0C13.05,14.3 12.6,14.75 12.05,14.75zM14.05,10.25l-4.0,0.0l0.0,-0.5c0.0,-1.1 0.9,-2.05 2.0,-2.05s2.0,0.94 2.0,2.05L14.05,10.25z"/>
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M16.5,2.5c3.3,1.5 5.6,4.7 6.0,8.5L24.0,11.0C23.4,4.8 18.3,0.0 12.0,0.0c-0.2,0.0 -0.4,0.0 -0.7,0.0l3.8,3.8L16.5,2.5zM7.5,21.5c-3.3,-1.5 -5.6,-4.7 -6.0,-8.5L0.1,13.0C0.6,19.2 5.7,24.0 12.0,24.0c0.2,0.0 0.4,0.0 0.7,0.0l-3.8,-3.8L7.5,21.5z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_locked_anim.xml b/packages/SystemUI/res/drawable/ic_rotate_locked_anim.xml
new file mode 100644
index 0000000..e14a1ce
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_locked_anim.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<animation-list
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:oneshot="true">
+    <item android:drawable="@drawable/ic_rotate_24_01" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_02" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_03" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_04" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_05" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_06" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_07" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_08" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_09" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_10" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_11" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_12" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_13" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_14" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_15" android:duration="16" />
+</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_unlocked_anim.xml b/packages/SystemUI/res/drawable/ic_rotate_unlocked_anim.xml
new file mode 100644
index 0000000..63b8c5f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_unlocked_anim.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<animation-list
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:oneshot="true">
+    <item android:drawable="@drawable/ic_rotate_24_15" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_14" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_13" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_12" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_11" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_10" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_09" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_08" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_07" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_06" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_05" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_04" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_03" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_02" android:duration="16" />
+    <item android:drawable="@drawable/ic_rotate_24_01" android:duration="16" />
+</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_settings_24dp.xml b/packages/SystemUI/res/drawable/ic_settings_24dp.xml
new file mode 100644
index 0000000..a2f7822
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_settings_24dp.xml
@@ -0,0 +1,29 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at"+
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+<size
+android:width="24dp"
+android:height="24dp"/>
+
+    <viewport android:viewportWidth="24.0"
+          android:viewportHeight="24.0"/>
+
+
+<path
+     android:pathData="M19.4,13.0c0.0,-0.3 0.1,-0.6 0.1,-1.0s0.0,-0.7 -0.1,-1.0l2.1,-1.7c0.2,-0.2 0.2,-0.4 0.1,-0.6l-2.0,-3.5C19.5,5.1 19.3,5.0 19.0,5.1l-2.5,1.0c-0.5,-0.4 -1.1,-0.7 -1.7,-1.0l-0.4,-2.6C14.5,2.2 14.2,2.0 14.0,2.0l-4.0,0.0C9.8,2.0 9.5,2.2 9.5,2.4L9.1,5.1C8.5,5.3 8.0,5.7 7.4,6.1L5.0,5.1C4.7,5.0 4.5,5.1 4.3,5.3l-2.0,3.5C2.2,8.9 2.3,9.2 2.5,9.4L4.6,11.0c0.0,0.3 -0.1,0.6 -0.1,1.0s0.0,0.7 0.1,1.0l-2.1,1.7c-0.2,0.2 -0.2,0.4 -0.1,0.6l2.0,3.5C4.5,18.9 4.7,19.0 5.0,18.9l2.5,-1.0c0.5,0.4 1.1,0.7 1.7,1.0l0.4,2.6c0.0,0.2 0.2,0.4 0.5,0.4l4.0,0.0c0.2,0.0 0.5,-0.2 0.5,-0.4l0.4,-2.6c0.6,-0.3 1.2,-0.6 1.7,-1.0l2.5,1.0c0.2,0.1 0.5,0.0 0.6,-0.2l2.0,-3.5c0.1,-0.2 0.1,-0.5 -0.1,-0.6L19.4,13.0zM12.0,15.5c-1.9,0.0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5s3.5,1.6 3.5,3.5S13.9,15.5 12.0,15.5z"
+     android:fill="#ffffffff"
+     />
+
+</vector>
diff --git a/packages/SystemUI/res/drawable/notification_header_bg.xml b/packages/SystemUI/res/drawable/notification_header_bg.xml
new file mode 100644
index 0000000..09d0d7d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/notification_header_bg.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true">
+        <shape>
+            <solid android:color="@color/background_color_1_press" />
+            <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" />
+        </shape>
+    </item>
+    <item>
+        <shape>
+            <solid android:color="@color/background_color_1" />
+            <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" />
+        </shape>
+    </item>
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_panel_background.xml b/packages/SystemUI/res/drawable/qs_panel_background.xml
new file mode 100644
index 0000000..c324976
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_panel_background.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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+        android:insetLeft="@dimen/notification_side_padding"
+        android:insetRight="@dimen/notification_side_padding">
+    <shape>
+        <solid android:color="@color/system_primary_color" />
+        <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" />
+    </shape>
+</inset>
diff --git a/packages/SystemUI/res/drawable/recents_dismiss_dark.xml b/packages/SystemUI/res/drawable/recents_dismiss_dark.xml
new file mode 100644
index 0000000..744795e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_dismiss_dark.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:versionCode="1" >
+
+    <size
+        android:height="16dp"
+        android:width="16dp" />
+
+    <viewport
+        android:viewportHeight="100"
+        android:viewportWidth="100" />
+
+    <path
+        android:name="x"
+        android:pathData="M0,0L100,100M0,100L100,0z"
+        android:stroke="@color/recents_task_bar_dark_dismiss_color"
+        android:strokeWidth="8.0"
+        android:strokeLineCap="square" />
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/recents_dismiss_light.xml b/packages/SystemUI/res/drawable/recents_dismiss_light.xml
new file mode 100644
index 0000000..96bfbe1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_dismiss_light.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:versionCode="1" >
+
+    <size
+        android:height="16dp"
+        android:width="16dp" />
+
+    <viewport
+        android:viewportHeight="100"
+        android:viewportWidth="100" />
+
+
+    <path
+        android:name="x"
+        android:pathData="M0,0L100,100M0,100L100,0z"
+        android:stroke="@color/recents_task_bar_light_dismiss_color"
+        android:strokeWidth="8.0"
+        android:strokeLineCap="square" />
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml b/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml
index aa7256b..5f12706 100644
--- a/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml
+++ b/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml
@@ -43,7 +43,7 @@
 
             <!-- navigation controls -->
             <View
-                android:layout_width="40dp"
+                android:layout_width="@dimen/navigation_extra_key_width"
                 android:layout_height="match_parent"
                 android:layout_weight="0"
                 android:visibility="invisible"
@@ -88,16 +88,29 @@
                 systemui:glowBackground="@drawable/ic_sysbar_highlight"
                 android:contentDescription="@string/accessibility_recent"
                 />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
-                android:layout_width="@dimen/navigation_menu_key_width"
+            <FrameLayout
+                android:layout_width="@dimen/navigation_extra_key_width"
                 android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_menu"
-                systemui:keyCode="82"
-                android:layout_weight="0"
-                android:visibility="invisible"
-                android:contentDescription="@string/accessibility_menu"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight"
-                />
+                android:layout_weight="0" >
+                <com.android.systemui.statusbar.policy.KeyButtonView
+                    android:id="@+id/menu"
+                    android:layout_width="@dimen/navigation_extra_key_width"
+                    android:layout_height="match_parent"
+                    android:contentDescription="@string/accessibility_menu"
+                    android:src="@drawable/ic_sysbar_menu"
+                    android:visibility="invisible"
+                    systemui:glowBackground="@drawable/ic_sysbar_highlight"
+                    systemui:keyCode="82" />
+                <com.android.systemui.statusbar.policy.KeyButtonView
+                    android:id="@+id/ime_switcher"
+                    android:layout_width="@dimen/navigation_extra_key_width"
+                    android:layout_height="match_parent"
+                    android:contentDescription="@string/accessibility_ime_switch_button"
+                    android:scaleType="centerInside"
+                    android:src="@drawable/ic_ime_switcher_default"
+                    android:visibility="invisible"
+                    systemui:glowBackground="@drawable/ic_sysbar_highlight" />
+            </FrameLayout>
         </LinearLayout>
 
         <!-- lights out layout to match exactly -->
@@ -187,16 +200,29 @@
             >
             
             <!-- navigation controls -->
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
-                android:layout_height="40dp"
-                android:layout_width="match_parent"
-                android:src="@drawable/ic_sysbar_menu_land"
-                systemui:keyCode="82"
-                android:layout_weight="0"
-                android:visibility="invisible"
-                android:contentDescription="@string/accessibility_menu"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
-                />
+            <FrameLayout
+                android:layout_width="@dimen/navigation_extra_key_width"
+                android:layout_height="match_parent"
+                android:layout_weight="0" >
+                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
+                    android:layout_height="@dimen/navigation_extra_key_width"
+                    android:layout_width="match_parent"
+                    android:src="@drawable/ic_sysbar_menu_land"
+                    systemui:keyCode="82"
+                    android:layout_weight="0"
+                    android:visibility="invisible"
+                    android:contentDescription="@string/accessibility_menu"
+                    systemui:glowBackground="@drawable/ic_sysbar_highlight_land" />
+                <com.android.systemui.statusbar.policy.KeyButtonView
+                    android:id="@+id/ime_switcher"
+                    android:layout_height="@dimen/navigation_extra_key_width"
+                    android:layout_width="match_parent"
+                    android:contentDescription="@string/accessibility_ime_switch_button"
+                    android:scaleType="centerInside"
+                    android:src="@drawable/ic_ime_switcher_default"
+                    android:visibility="invisible"
+                    systemui:glowBackground="@drawable/ic_sysbar_highlight" />
+            </FrameLayout>
             <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
                 android:layout_height="80dp"
                 android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout-sw600dp/heads_up.xml b/packages/SystemUI/res/layout-sw600dp/heads_up.xml
index 71f7c21..f7035fe 100644
--- a/packages/SystemUI/res/layout-sw600dp/heads_up.xml
+++ b/packages/SystemUI/res/layout-sw600dp/heads_up.xml
@@ -25,7 +25,6 @@
         android:id="@+id/content_holder"
         android:layout_height="wrap_content"
         android:layout_width="@dimen/notification_panel_width"
-        android:layout_marginStart="@dimen/notification_panel_margin_left"
         android:background="@drawable/heads_up_window_bg"
         />
 </com.android.systemui.statusbar.policy.HeadsUpNotificationView>
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
index b9ad799..6a2e3c6 100644
--- a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
+++ b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
@@ -42,7 +42,7 @@
 
             <!-- navigation controls -->
             <View
-                android:layout_width="48dp"
+                android:layout_width="@dimen/navigation_extra_key_width"
                 android:layout_height="match_parent"
                 android:layout_weight="0"
                 android:layout_marginStart="2dp"
@@ -85,17 +85,32 @@
                 android:layout_height="match_parent"
                 android:layout_weight="1"
                 />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
-                android:layout_width="48dp"
+            <FrameLayout
+                android:layout_width="@dimen/navigation_extra_key_width"
                 android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_menu"
-                android:layout_marginEnd="2dp"
-                systemui:keyCode="82"
                 android:layout_weight="0"
-                android:visibility="invisible"
-                android:contentDescription="@string/accessibility_menu"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight"
-                />
+                android:layout_marginEnd="2dp" >
+                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
+                    android:layout_width="@dimen/navigation_extra_key_width"
+                    android:layout_height="match_parent"
+                    android:src="@drawable/ic_sysbar_menu"
+                    android:layout_marginEnd="2dp"
+                    systemui:keyCode="82"
+                    android:visibility="invisible"
+                    android:contentDescription="@string/accessibility_menu"
+                    systemui:glowBackground="@drawable/ic_sysbar_highlight"
+                    />
+                <com.android.systemui.statusbar.policy.KeyButtonView
+                    android:id="@+id/ime_switcher"
+                    android:layout_width="@dimen/navigation_extra_key_width"
+                    android:layout_height="match_parent"
+                    android:layout_marginEnd="2dp"
+                    android:scaleType="centerInside"
+                    android:src="@drawable/ic_ime_switcher_default"
+                    android:visibility="invisible"
+                    android:contentDescription="@string/accessibility_ime_switch_button"
+                    systemui:glowBackground="@drawable/ic_sysbar_highlight" />
+            </FrameLayout>
         </LinearLayout>
 
         <!-- lights out layout to match exactly -->
@@ -184,7 +199,7 @@
 
             <!-- navigation controls -->
             <View
-                android:layout_width="48dp"
+                android:layout_width="@dimen/navigation_extra_key_width"
                 android:layout_height="match_parent"
                 android:layout_weight="0"
                 android:layout_marginStart="2dp"
@@ -227,17 +242,32 @@
                 android:layout_height="match_parent"
                 android:layout_weight="1"
                 />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
-                android:layout_width="48dp"
+            <FrameLayout
+                android:layout_width="@dimen/navigation_extra_key_width"
                 android:layout_height="match_parent"
                 android:layout_marginEnd="2dp"
-                android:src="@drawable/ic_sysbar_menu"
-                systemui:keyCode="82"
-                android:layout_weight="0"
-                android:visibility="invisible"
-                android:contentDescription="@string/accessibility_menu"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight"
-                />
+                android:layout_weight="0" >
+                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
+                    android:layout_width="@dimen/navigation_extra_key_width"
+                    android:layout_height="match_parent"
+                    android:layout_marginEnd="2dp"
+                    android:src="@drawable/ic_sysbar_menu"
+                    systemui:keyCode="82"
+                    android:visibility="invisible"
+                    android:contentDescription="@string/accessibility_menu"
+                    systemui:glowBackground="@drawable/ic_sysbar_highlight"
+                    />
+                <com.android.systemui.statusbar.policy.KeyButtonView
+                    android:id="@+id/ime_switcher"
+                    android:layout_width="@dimen/navigation_extra_key_width"
+                    android:layout_height="match_parent"
+                    android:layout_marginEnd="2dp"
+                    android:src="@drawable/ic_ime_switcher_default"
+                    android:visibility="invisible"
+                    android:contentDescription="@string/accessibility_ime_switch_button"
+                    android:scaleType="centerInside"
+                    systemui:glowBackground="@drawable/ic_sysbar_highlight" />
+            </FrameLayout>
         </LinearLayout>
 
         <!-- lights out layout to match exactly -->
diff --git a/packages/SystemUI/res/layout/flip_settings.xml b/packages/SystemUI/res/layout/flip_settings.xml
deleted file mode 100644
index f3c1b90..0000000
--- a/packages/SystemUI/res/layout/flip_settings.xml
+++ /dev/null
@@ -1,26 +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.systemui.statusbar.phone.QuickSettingsContainerView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/quick_settings_container"
-    android:padding="@dimen/notification_side_padding"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:background="#5f000000"
-    android:animateLayoutChanges="true"
-    android:visibility="gone"
-    android:columnCount="@integer/quick_settings_num_columns" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/heads_up.xml b/packages/SystemUI/res/layout/heads_up.xml
index 3a58b84..7d9cfa1 100644
--- a/packages/SystemUI/res/layout/heads_up.xml
+++ b/packages/SystemUI/res/layout/heads_up.xml
@@ -20,8 +20,7 @@
 <com.android.systemui.statusbar.policy.HeadsUpNotificationView
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_height="wrap_content"
-        android:layout_width="@dimen/notification_panel_width"
+        android:layout_width="match_parent"
         android:id="@+id/content_holder"
-        android:layout_marginStart="@dimen/notification_panel_margin_left"
         android:background="@drawable/notification_panel_bg"
         />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 809adcd..194829d 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -22,15 +22,29 @@
     android:layout_height="match_parent"
     android:layout_width="match_parent"
     >
-    <com.android.systemui.statusbar.policy.KeyButtonView
+    <com.android.systemui.statusbar.phone.SwipeAffordanceView
         android:id="@+id/camera_button"
-        android:layout_height="80dp"
-        android:layout_width="80dp"
-        android:layout_gravity="bottom|right"
-        android:src="@drawable/ic_sysbar_camera"
+        android:layout_height="64dp"
+        android:layout_width="64dp"
+        android:layout_gravity="bottom|end"
+        android:tint="#ffffffff"
+        android:src="@drawable/ic_camera_alt_24dp"
         android:scaleType="center"
         android:contentDescription="@string/accessibility_camera_button"
-        systemui:glowBackground="@drawable/ic_sysbar_highlight_land" />
+        systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
+        systemui:swipeDirection="start"/>
+
+    <com.android.systemui.statusbar.phone.SwipeAffordanceView
+        android:id="@+id/phone_button"
+        android:layout_height="64dp"
+        android:layout_width="64dp"
+        android:layout_gravity="bottom|start"
+        android:tint="#ffffffff"
+        android:src="@drawable/ic_phone_24dp"
+        android:scaleType="center"
+        android:contentDescription="@string/accessibility_phone_button"
+        systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
+        systemui:swipeDirection="end"/>
 
     <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
         android:id="@+id/keyguard_indication_text"
@@ -41,4 +55,14 @@
         android:textStyle="italic"
         android:textAppearance="?android:attr/textAppearanceMedium"/>
 
+    <ImageView
+        android:layout_width="64dp"
+        android:layout_height="64dp"
+        android:layout_gravity="bottom|center_horizontal"
+        android:src="@drawable/ic_lock_24dp"
+        android:scaleType="center"
+        android:alpha="0.7"
+        android:layerType="hardware"
+        android:tint="#ffffffff"/>
+
 </com.android.systemui.statusbar.phone.KeyguardBottomAreaView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index 2398849..7470409 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -88,16 +88,31 @@
                 systemui:glowBackground="@drawable/ic_sysbar_highlight"
                 android:contentDescription="@string/accessibility_recent"
                 />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
-                android:layout_width="@dimen/navigation_menu_key_width"
+            <FrameLayout
+                android:layout_width="@dimen/navigation_extra_key_width"
                 android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_menu"
-                systemui:keyCode="82"
-                android:layout_weight="0"
-                android:visibility="invisible"
-                android:contentDescription="@string/accessibility_menu"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight"
-                />
+                android:layout_weight="0" >
+                <com.android.systemui.statusbar.policy.KeyButtonView
+                    android:id="@+id/menu"
+                    android:layout_width="@dimen/navigation_extra_key_width"
+                    android:layout_height="match_parent"
+                    android:contentDescription="@string/accessibility_menu"
+                    android:src="@drawable/ic_sysbar_menu"
+                    android:visibility="invisible"
+                    systemui:glowBackground="@drawable/ic_sysbar_highlight"
+                    systemui:keyCode="82" />
+
+                <com.android.systemui.statusbar.policy.KeyButtonView
+                    android:id="@+id/ime_switcher"
+                    android:layout_width="@dimen/navigation_extra_key_width"
+                    android:layout_height="match_parent"
+                    android:contentDescription="@string/accessibility_ime_switch_button"
+                    android:scaleType="centerInside"
+                    android:src="@drawable/ic_ime_switcher_default"
+                    android:visibility="invisible"
+                    systemui:glowBackground="@drawable/ic_sysbar_highlight" />
+            </FrameLayout>
+
         </LinearLayout>
 
         <!-- lights out layout to match exactly -->
@@ -190,18 +205,33 @@
             android:id="@+id/nav_buttons"
             android:animateLayoutChanges="true"
             >
-            
+
             <!-- navigation controls -->
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
-                android:layout_height="40dp"
-                android:layout_width="match_parent"
-                android:src="@drawable/ic_sysbar_menu_land"
-                systemui:keyCode="82"
+            <FrameLayout
                 android:layout_weight="0"
-                android:visibility="invisible"
-                android:contentDescription="@string/accessibility_menu"
-                systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
-                />
+                android:layout_width="match_parent"
+                android:layout_height="40dp" >
+                <com.android.systemui.statusbar.policy.KeyButtonView
+                    android:id="@+id/ime_switcher"
+                    android:layout_width="match_parent"
+                    android:layout_height="40dp"
+                    android:contentDescription="@string/accessibility_ime_switch_button"
+                    android:scaleType="centerInside"
+                    android:src="@drawable/ic_ime_switcher_default"
+                    android:visibility="invisible"
+                    systemui:glowBackground="@drawable/ic_sysbar_highlight" />
+
+                <com.android.systemui.statusbar.policy.KeyButtonView
+                    android:id="@+id/menu"
+                    android:layout_width="match_parent"
+                    android:layout_height="40dp"
+                    android:contentDescription="@string/accessibility_menu"
+                    android:src="@drawable/ic_sysbar_menu_land"
+                    android:visibility="invisible"
+                    systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
+                    systemui:keyCode="82" />
+            </FrameLayout>
+
             <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
                 android:layout_height="80dp"
                 android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
new file mode 100644
index 0000000..b24d4ad
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<FrameLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/quick_settings_container"
+        android:paddingLeft="@dimen/notification_side_padding"
+        android:paddingRight="@dimen/notification_side_padding"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@drawable/qs_panel_background" >
+    <com.android.systemui.qs.QSPanel
+            android:id="@+id/quick_settings_panel"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/qs_zen_mode_detail.xml b/packages/SystemUI/res/layout/qs_zen_mode_detail.xml
new file mode 100644
index 0000000..2df6d43
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_zen_mode_detail.xml
@@ -0,0 +1,76 @@
+<?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.systemui.qs.tiles.ZenModeDetail xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/system_secondary_color" >
+
+    <com.android.systemui.qs.QSImageView
+        android:id="@android:id/button1"
+        android:layout_width="64dp"
+        android:layout_height="64dp"
+        android:layout_alignParentStart="true"
+        android:padding="@dimen/quick_settings_panel_padding" />
+
+    <Switch
+        android:id="@android:id/checkbox"
+        android:layout_width="wrap_content"
+        android:layout_height="64dp"
+        android:layout_alignParentEnd="true"
+        android:gravity="center"
+        android:padding="@dimen/quick_settings_panel_padding" />
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="match_parent"
+        android:layout_height="64dp"
+        android:layout_toEndOf="@android:id/button1"
+        android:layout_toStartOf="@android:id/checkbox"
+        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
+        android:gravity="center_vertical"
+        android:paddingStart="@dimen/quick_settings_panel_padding"
+        android:text="@string/zen_mode_title" />
+
+    <View
+        android:id="@android:id/custom"
+        android:layout_width="match_parent"
+        android:layout_height="2dp"
+        android:layout_below="@android:id/title"
+        android:background="#888" />
+
+    <ListView
+        android:id="@android:id/content"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_above="@android:id/button2"
+        android:layout_below="@android:id/custom"
+        android:divider="#00000000"
+        android:dividerHeight="0px" />
+
+    <TextView
+        android:id="@android:id/button2"
+        style="@style/QSBorderless"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentEnd="true"
+        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
+        android:padding="@dimen/quick_settings_panel_padding"
+        android:text="@string/quick_settings_more_settings"
+        android:textAllCaps="true" />
+
+</com.android.systemui.qs.tiles.ZenModeDetail>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml b/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml
new file mode 100644
index 0000000..a5c8903
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml
@@ -0,0 +1,57 @@
+<?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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+
+    <RadioButton
+        android:id="@android:id/checkbox"
+        android:layout_width="32dp"
+        android:layout_height="64dp"
+        android:layout_alignParentStart="true"
+        android:layout_marginStart="@dimen/quick_settings_panel_padding"
+        android:gravity="center" />
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="match_parent"
+        android:layout_height="64dp"
+        android:layout_toEndOf="@android:id/checkbox"
+        android:layout_toStartOf="@android:id/button1"
+        android:ellipsize="end"
+        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
+        android:gravity="center_vertical"
+        android:maxLines="1"
+        android:text="@string/accessibility_back" />
+
+    <com.android.systemui.qs.QSImageView
+        android:id="@android:id/button1"
+        android:layout_width="64dp"
+        android:layout_height="64dp"
+        android:layout_alignParentEnd="true"
+        android:layout_marginEnd="48dp"
+        android:padding="@dimen/quick_settings_panel_padding"
+        android:paddingRight="0px" />
+
+    <com.android.systemui.qs.QSImageView
+        android:id="@android:id/button2"
+        android:layout_width="64dp"
+        android:layout_height="64dp"
+        android:layout_alignParentEnd="true"
+        android:padding="@dimen/quick_settings_panel_padding" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index b7df51d..1efda8c 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -29,7 +29,7 @@
     <com.android.systemui.settings.ToggleSlider
         android:id="@+id/brightness_slider"
         android:layout_width="0dp"
-        android:layout_height="40dp"
+        android:layout_height="44dp"
         android:layout_gravity="center_vertical"
         android:layout_weight="1"
         systemui:text="@string/status_bar_settings_auto_brightness_label" />
diff --git a/packages/SystemUI/res/layout/quick_settings_tile.xml b/packages/SystemUI/res/layout/quick_settings_tile.xml
deleted file mode 100644
index 911f6a2..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile.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.
--->
-<com.android.systemui.statusbar.phone.QuickSettingsTileView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="@dimen/quick_settings_cell_height"
-    android:background="@drawable/qs_tile_background" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_alarm.xml b/packages/SystemUI/res/layout/quick_settings_tile_alarm.xml
deleted file mode 100644
index 493c704..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_alarm.xml
+++ /dev/null
@@ -1,25 +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.
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TextAppearance.QuickSettings.TileView.AllInOne"
-    android:id="@+id/alarm_textview"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:gravity="center"
-    android:drawableTop="@drawable/ic_qs_alarm_on"
-    />
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_basic.xml b/packages/SystemUI/res/layout/quick_settings_tile_basic.xml
deleted file mode 100644
index 16bf49c..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_basic.xml
+++ /dev/null
@@ -1,39 +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.
--->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_gravity="top"
-    android:orientation="vertical">
-    <ImageView
-        android:id="@+id/image"
-        android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
-        android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
-        android:layout_width="@dimen/qs_tile_icon_size"
-        android:layout_height="@dimen/qs_tile_icon_size"
-        android:layout_gravity="top|center_horizontal"
-        android:scaleType="centerInside"
-        />
-    <TextView
-        style="@style/TextAppearance.QuickSettings.TileView"
-        android:id="@+id/text"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top|center_horizontal"
-        android:gravity="top|center_horizontal"
-        />
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_battery.xml b/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
deleted file mode 100644
index 1f39aef..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
+++ /dev/null
@@ -1,41 +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.
--->
-<LinearLayout
-        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:layout_gravity="top"
-        android:orientation="vertical">
-    <com.android.systemui.BatteryMeterView
-            android:id="@+id/image"
-            android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
-            android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
-            android:layout_width="22dp"
-            android:layout_height="32dp"
-            android:padding="3dp"
-            android:layout_gravity="top|center_horizontal"
-            systemui:frameColor="@color/qs_batterymeter_frame_color"
-            />
-    <TextView
-            style="@style/TextAppearance.QuickSettings.TileView"
-            android:id="@+id/text"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_gravity="top|center_horizontal"
-            android:gravity="top|center_horizontal"
-            />
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_ime.xml b/packages/SystemUI/res/layout/quick_settings_tile_ime.xml
deleted file mode 100644
index 1a31efa5..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_ime.xml
+++ /dev/null
@@ -1,26 +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.
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TextAppearance.QuickSettings.TileView.AllInOne"
-    android:id="@+id/ime_textview"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:gravity="center"
-    android:drawableTop="@drawable/ic_qs_ime"
-    android:text="@string/quick_settings_ime_label"
-    />
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_media.xml b/packages/SystemUI/res/layout/quick_settings_tile_media.xml
deleted file mode 100644
index 355176c6..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_media.xml
+++ /dev/null
@@ -1,24 +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.
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TextAppearance.QuickSettings.TileView.AllInOne"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:gravity="center"
-    android:text="@string/quick_settings_media_device_label"
-    android:singleLine="true"
-    />
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_monitoring.xml b/packages/SystemUI/res/layout/quick_settings_tile_monitoring.xml
deleted file mode 100644
index 4fa48eb..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_monitoring.xml
+++ /dev/null
@@ -1,39 +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.
--->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_gravity="top"
-    android:orientation="vertical">
-    <ImageView
-        android:id="@+id/image"
-        android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
-        android:layout_marginBottom="@dimen/qs_cawarn_tile_margin_below_icon"
-        android:layout_width="@dimen/qs_tile_icon_size"
-        android:layout_height="@dimen/qs_tile_icon_size"
-        android:layout_gravity="top|center_horizontal"
-        android:scaleType="centerInside"
-        />
-    <TextView
-        style="@style/TextAppearance.QuickSettings.CaCertWarning"
-        android:id="@+id/text"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top|center_horizontal"
-        android:gravity="top|center_horizontal"
-        />
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml b/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml
deleted file mode 100644
index 6bf31e0..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml
+++ /dev/null
@@ -1,71 +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.
--->
-<RelativeLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_gravity="top">
-    <FrameLayout
-        android:id="@+id/rssi_images"
-        android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
-        android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
-        android:layout_width="@dimen/qs_tile_icon_size"
-        android:layout_height="@dimen/qs_tile_icon_size"
-        android:layout_gravity="top|center_horizontal"
-        android:layout_centerHorizontal="true"
-        >
-        <ImageView
-            android:id="@+id/rssi_image"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_centerInParent="true"
-            />
-        <ImageView
-            android:id="@+id/rssi_overlay_image"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_centerInParent="true"
-            />
-    </FrameLayout>
-    <ImageView
-            android:id="@+id/activity_in"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/ic_qs_signal_in"
-            android:layout_toRightOf="@id/rssi_images"
-            android:layout_alignBottom="@id/rssi_images"
-            />
-    <ImageView
-            android:id="@+id/activity_out"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/ic_qs_signal_out"
-            android:layout_toRightOf="@id/rssi_images"
-            android:layout_alignBottom="@id/rssi_images"
-            />
-    <TextView
-        style="@style/TextAppearance.QuickSettings.TileView"
-        android:id="@+id/rssi_textview"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top|center_horizontal"
-        android:gravity="top|center_horizontal"
-        android:text="@string/quick_settings_rssi_label"
-        android:layout_centerHorizontal="true"
-        android:layout_below="@id/rssi_images"
-        android:textAllCaps="@bool/quick_settings_rssi_tile_capitalization"
-        />
-</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_user.xml b/packages/SystemUI/res/layout/quick_settings_tile_user.xml
deleted file mode 100644
index 80fc685..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_user.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <ImageView
-        android:id="@+id/user_imageview"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:src="@drawable/ic_qs_default_user"
-        android:scaleType="centerCrop"
-        />
-    <TextView
-        style="@style/TextAppearance.QuickSettings.TileView.User"
-        android:id="@+id/user_textview"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_horizontal|bottom"
-        android:gravity="center"
-        android:text="@string/quick_settings_user_label"
-        />
-</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml b/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml
deleted file mode 100644
index e61c595..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml
+++ /dev/null
@@ -1,57 +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.
--->
-<RelativeLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_gravity="top">
-    <ImageView
-        android:id="@+id/image"
-        android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
-        android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
-        android:layout_width="@dimen/qs_tile_icon_size"
-        android:layout_height="@dimen/qs_tile_icon_size"
-        android:layout_gravity="top|center_horizontal"
-        android:layout_centerHorizontal="true"
-        android:scaleType="centerInside"
-        />
-    <ImageView
-            android:id="@+id/activity_in"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/ic_qs_wifi_in"
-            android:layout_toRightOf="@id/image"
-            android:layout_alignBottom="@id/image"
-            />
-    <ImageView
-            android:id="@+id/activity_out"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/ic_qs_wifi_out"
-            android:layout_toRightOf="@id/image"
-            android:layout_alignBottom="@id/image"
-            />
-    <TextView
-        style="@style/TextAppearance.QuickSettings.TileView"
-        android:id="@+id/text"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top|center_horizontal"
-        android:gravity="top|center_horizontal"
-        android:layout_centerHorizontal="true"
-        android:layout_below="@id/image" 
-        />
-</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index ddc0dbf..bda6431 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -58,11 +58,18 @@
             android:textSize="22sp"
             android:textColor="#ffffffff"
             android:text="@string/recents_empty_message"
-            android:fontFamily="sans-serif-thin"
+            android:fontFamily="sans-serif-light"
             android:singleLine="true"
             android:maxLines="2"
             android:ellipsize="marquee"
             android:fadingEdge="horizontal" />
+        <ImageView
+            android:id="@+id/dismiss_task"
+            android:layout_width="@dimen/recents_task_view_application_icon_size"
+            android:layout_height="@dimen/recents_task_view_application_icon_size"
+            android:layout_gravity="center_vertical|end"
+            android:padding="23dp"
+            android:src="@drawable/recents_dismiss_dark" />
     </com.android.systemui.recents.views.TaskBarView>
 </com.android.systemui.recents.views.TaskView>
 
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 1b35537..585658e 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -77,26 +77,24 @@
         <LinearLayout android:id="@+id/system_icon_area"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
-            android:orientation="horizontal">
-
-            <LinearLayout android:id="@+id/statusIcons"
+            android:orientation="horizontal"
+            >
+            <LinearLayout android:id="@+id/system_icons"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
                 android:gravity="center_vertical"
-                android:orientation="horizontal"/>    
-    
-            <LinearLayout
-                android:id="@+id/signal_battery_cluster"
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:paddingStart="2dp"
-                android:orientation="horizontal"
-                android:gravity="center"
                 >
-                <include layout="@layout/signal_cluster_view" 
+                <LinearLayout android:id="@+id/statusIcons"
+                    android:layout_width="wrap_content"
+                    android:layout_height="match_parent"
+                    android:gravity="center_vertical"
+                    android:orientation="horizontal"/>
+
+                <include layout="@layout/signal_cluster_view"
                     android:id="@+id/signal_cluster"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
+                    android:layout_marginStart="2dp"
                     />
                 <!-- battery must be padded below to match assets -->
                 <com.android.systemui.BatteryMeterView
@@ -107,7 +105,6 @@
                     android:layout_marginStart="4dip"
                     />
             </LinearLayout>
-    
             <com.android.systemui.statusbar.policy.Clock
                 android:id="@+id/clock"
                 android:textAppearance="@style/TextAppearance.StatusBar.Clock"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 761ad42..2ec9935 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -22,10 +22,8 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:id="@+id/notification_panel"
-    android:layout_width="0dp"
-    android:layout_height="wrap_content"
-    android:paddingTop="@dimen/notification_panel_padding_top"
-    android:layout_marginStart="@dimen/notification_panel_margin_left"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     >
 
     <include
@@ -37,29 +35,6 @@
         />
 
     <include
-        layout="@layout/status_bar_flip_button"
-        android:id="@+id/keyguard_flipper"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:layout_gravity="right|top"
-        android:layout_marginTop="@dimen/status_bar_height"
-        android:visibility="gone" />
-
-    <com.android.keyguard.CarrierText
-        android:id="@+id/keyguard_carrier_text"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="2dp"
-        android:layout_marginLeft="8dp"
-        android:ellipsize="marquee"
-        android:textAppearance="?android:attr/textAppearanceMedium" />
-
-    <include layout="@layout/status_bar_expanded_header"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/notification_panel_header_height"
-        />
-
-    <include
         layout="@layout/keyguard_status_view"
         android:layout_height="wrap_content"
         android:visibility="gone" />
@@ -74,27 +49,49 @@
         android:visibility="gone"
         />
 
-    <FrameLayout
+    <com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer
+        style="@style/NotificationsQuickSettings"
         android:id="@+id/notification_container_parent"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginBottom="@dimen/close_handle_underlap"
-        >
-        <include
-            layout="@layout/flip_settings"
-            android:layout_marginTop="@dimen/notification_panel_header_height"
+        android:clipToPadding="false"
+        android:clipChildren="false">
+
+        <com.android.systemui.statusbar.phone.ObservableScrollView
+            android:id="@+id/scroll_view"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            />
+            android:layout_height="match_parent"
+            android:visibility="invisible"
+            android:scrollbars="none"
+            android:fillViewport="true">
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical">
+                <include
+                    layout="@layout/qs_panel"
+                    android:layout_marginTop="@dimen/status_bar_header_height_expanded"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"/>
+
+                <!-- A view to reserve space for the collapsed stack -->
+                <View
+                    android:layout_height="@dimen/collapsed_stack_height"
+                    android:layout_width="match_parent"/>
+            </LinearLayout>
+        </com.android.systemui.statusbar.phone.ObservableScrollView>
+
 
         <com.android.systemui.statusbar.stack.NotificationStackScrollLayout
             android:id="@+id/notification_stack_scroller"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            />
-    </FrameLayout>
+            android:layout_height="match_parent"
+            android:layout_marginBottom="@dimen/close_handle_underlap"/>
+
+    </com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer>
+
+    <include layout="@layout/status_bar_expanded_header" />
 
     <include
         layout="@layout/keyguard_bottom_area"
         android:visibility="gone" />
+
 </com.android.systemui.statusbar.phone.NotificationPanelView><!-- end of sliding panel -->
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 8975728..89fa988 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -15,23 +15,35 @@
 ** limitations under the License.
 -->
 
-<LinearLayout
+<!-- Extends RelativeLayout -->
+<com.android.systemui.statusbar.phone.StatusBarHeaderView
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:id="@+id/header"
-    android:layout_width="match_parent"
-    android:layout_height="@dimen/notification_panel_header_height"
-    android:background="@drawable/notification_header_bg"
-    android:orientation="horizontal"
-    android:gravity="center_vertical"
+    style="@style/StatusBarHeader"
+    android:layout_height="@dimen/status_bar_header_height"
+    android:paddingStart="@dimen/notification_side_padding"
+    android:paddingEnd="@dimen/notification_side_padding"
     android:baselineAligned="false"
+    android:elevation="10dp"
     >
+
+    <View
+        android:id="@+id/background"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@drawable/notification_header_bg"
+        android:clickable="true"
+        />
     <RelativeLayout
         android:id="@+id/datetime"
         android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:paddingStart="8dp"
-        android:paddingEnd="8dp"
+        android:layout_height="wrap_content"
+        android:layout_gravity="start"
+        android:paddingTop="16dp"
+        android:paddingBottom="16dp"
+        android:paddingStart="16dp"
+        android:paddingEnd="16dp"
         android:background="@drawable/ic_notify_button_bg"
         android:enabled="false"
         >
@@ -39,10 +51,9 @@
             android:id="@+id/clock"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginEnd="8dp"
             android:singleLine="true"
             android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
-            android:layout_centerVertical="true"
+            systemui:amPmStyle="normal"
             />
 
         <com.android.systemui.statusbar.policy.DateView android:id="@+id/date"
@@ -50,15 +61,47 @@
             android:layout_height="wrap_content"
             android:singleLine="true"
             android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
-            android:layout_toEndOf="@id/clock"
-            android:layout_alignBaseline="@id/clock"
+            android:layout_below="@id/clock"
             />
     </RelativeLayout>
 
-    <Space
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:layout_weight="1"
+    <com.android.keyguard.CarrierText
+        android:id="@+id/keyguard_carrier_text"
+        android:layout_width="wrap_content"
+        android:layout_height="@dimen/status_bar_header_height_keyguard"
+        android:layout_marginLeft="8dp"
+        android:gravity="center_vertical"
+        android:ellipsize="marquee"
+        android:textAppearance="?android:attr/textAppearanceMedium" />
+
+    <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch"
+        android:layout_width="40dp"
+        android:layout_height="@dimen/status_bar_header_height"
+        android:layout_alignParentEnd="true"
+        android:background="@null"
+        android:scaleType="centerInside"
+        android:padding="6dp"
+        />
+
+    <ImageButton android:id="@+id/settings_button"
+        style="@android:style/Widget.Quantum.Button.Borderless"
+        android:layout_toStartOf="@id/multi_user_switch"
+        android:layout_width="56dp"
+        android:layout_height="@dimen/status_bar_header_height"
+        android:src="@drawable/ic_settings_24dp"
+        android:contentDescription="@string/accessibility_desc_quick_settings"/>
+
+    <FrameLayout android:id="@+id/system_icons_container"
+        android:layout_width="wrap_content"
+        android:layout_height="@dimen/status_bar_header_height"
+        android:layout_toStartOf="@id/multi_user_switch"
+        android:layout_marginEnd="4dp"
+        />
+
+    <include
+        layout="@layout/quick_settings_brightness_dialog"
+        android:id="@+id/brightness_container"
+        android:layout_width="match_parent"
         />
 
     <TextView
@@ -74,18 +117,4 @@
         android:padding="2dp"
         />
 
-    <ImageView android:id="@+id/clear_all_button"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:scaleType="center"
-        android:src="@drawable/ic_notify_clear"
-        android:background="@drawable/ic_notify_button_bg"
-        android:contentDescription="@string/accessibility_clear_all"
-        />
-
-    <include layout="@layout/status_bar_flip_button"
-        android:id="@+id/header_flipper"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:layout_marginStart="12dp" />
-</LinearLayout>
+</com.android.systemui.statusbar.phone.StatusBarHeaderView>
diff --git a/packages/SystemUI/res/layout/status_bar_flip_button.xml b/packages/SystemUI/res/layout/status_bar_flip_button.xml
deleted file mode 100644
index b7dff8c..0000000
--- a/packages/SystemUI/res/layout/status_bar_flip_button.xml
+++ /dev/null
@@ -1,36 +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
-  -->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="50dp"
-        android:layout_height="50dp">
-    <ImageView android:id="@+id/settings_button"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:scaleType="center"
-        android:src="@drawable/ic_notify_settings"
-        android:background="@drawable/ic_notify_button_bg"
-        android:contentDescription="@string/accessibility_desc_quick_settings" />
-    <ImageView android:id="@+id/notification_button"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:scaleType="center"
-        android:src="@drawable/ic_notifications"
-        android:background="@drawable/ic_notify_button_bg"
-        android:visibility="gone"
-        android:contentDescription="@string/accessibility_notifications_button" />
-</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
index 2e08bff..30eedee 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
@@ -18,7 +18,7 @@
 <com.android.systemui.statusbar.NotificationOverflowContainer
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="32dp"
+    android:layout_height="40dp"
     android:focusable="true"
     android:clickable="true"
     >
diff --git a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
index e6d7c93..7671c354a 100644
--- a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
+++ b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
@@ -28,6 +28,8 @@
         android:layout_alignParentTop="true"
         android:layout_alignParentBottom="true"
         android:button="@null"
+        android:background="@*android:drawable/switch_track_quantum"
+        android:visibility="gone"
         />
     <com.android.systemui.settings.ToggleSeekBar
         android:id="@+id/slider"
@@ -35,6 +37,7 @@
         android:layout_height="wrap_content"
         android:layout_toEndOf="@id/toggle"
         android:layout_centerVertical="true"
+        android:layout_alignParentStart="true"
         android:layout_alignParentEnd="true"
         android:paddingStart="20dp"
         android:paddingEnd="20dp"
@@ -50,5 +53,6 @@
         android:paddingTop="26dp"
         android:textColor="#666666"
         android:textSize="12sp"
+        android:visibility="gone"
         />
 </merge>
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 61d43d7..26616cd 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -33,12 +33,11 @@
     <com.android.systemui.statusbar.phone.PanelHolder
         android:id="@+id/panel_holder"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_marginTop="@dimen/panel_holder_padding_top">
+        android:layout_height="match_parent" >
         <include layout="@layout/status_bar_expanded"
-            android:layout_width="@dimen/notification_panel_width"
-            android:layout_height="wrap_content"
-            android:layout_gravity="start|top" />
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:visibility="gone" />
     </com.android.systemui.statusbar.phone.PanelHolder>
 
 </com.android.systemui.statusbar.phone.StatusBarWindowView>
diff --git a/packages/SystemUI/res/layout/user_switcher_host.xml b/packages/SystemUI/res/layout/user_switcher_host.xml
index bc56cf6..70c5042 100644
--- a/packages/SystemUI/res/layout/user_switcher_host.xml
+++ b/packages/SystemUI/res/layout/user_switcher_host.xml
@@ -22,7 +22,8 @@
         xmlns:tools="http://schemas.android.com/tools"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:background="#dd000000">
+        android:background="#dd000000"
+        android:elevation="12dp">
     <FrameLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index d8a3114..eb66a59 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Onlangse programme"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Deursoek"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Foon"</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>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 9d1e036..a3eca6a 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"የቅርብ ጊዜ  መተግበሪያዎች"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"ፈልግ"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"ካሜራ"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"ስልክ"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"የግቤት ስልት አዝራር ቀይር"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"የተኳኋኝአጉላ አዝራር።"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"አነስተኛውን ማያ ወደ ትልቅ አጉላ።"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 22a032a..0060004 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -204,22 +204,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"وضع انعكاس اللون"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"وضع التباين المحسن"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"وضع تصحيح الألوان"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"الأخيرة"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"معلومات التطبيق"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"بحث"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"قد تكون الشبكة\nخاضعة للرقابة"</string>
     <string name="description_target_search" msgid="3091587249776033139">"بحث"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"تمرير لأعلى لـ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"تمرير لليسار لـ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"تم إخفاء الإشعار"</item>
-    <item quantity="other" msgid="7388721375827338153">"‏تم إخفاء %d من الإشعارات"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"المس للعرض"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"الرجاء عدم الإزعاج"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"‏%d أخرى"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"انقر مرة أخرى للفتح"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"مرر سريعًا لأعلى لإلغاء القفل"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 00ac707..e03a2f9 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Скорошни приложения"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Търсене"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Телефон"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Бутон за превключване на метода на въвеждане."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Бутон за промяна на мащаба с цел съвместимост."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Промяна на мащаба на екрана от по-малък до по-голям."</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index bfad5bc..e50a155 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Aplicacions recents"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Cerca"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Càmera"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telèfon"</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>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 94ba5c7..a2d9d9c 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Nové aplikace"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Hledat"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparát"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</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>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index df442ab..1e6011c 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -183,8 +183,8 @@
     <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Lysstyrke"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Automatisk rotation"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotation er låst"</string>
-    <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Altid stående"</string>
-    <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Altid liggende"</string>
+    <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Låst i portræt"</string>
+    <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Låst i landskab"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"Inputmetode"</string>
     <string name="quick_settings_location_label" msgid="5011327048748762257">"Placering"</string>
     <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Placering fra"</string>
@@ -198,28 +198,14 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ikke forbundet"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Intet netværk"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi slået fra"</string>
-    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Cast skærm"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Cast-skærm"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Lysstyrke"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Farveinverteringstilstand"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Tilstand for forbedret kontrast"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Farvekorrigeringstilstand"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"SENESTE"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"Oplysninger om applikationen"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"søg"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netværket kan\nvære overvåget"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Søgning"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Glid op for at <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Glid til venstre for at <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"Underretningen er skjult"</item>
-    <item quantity="other" msgid="7388721375827338153">"%d underretninger er skjult"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"Tryk for at vise"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"Vil ikke forstyrres"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"%d mere"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Tryk igen for at åbne"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Stryg for at låse op"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 3c4e0d3..fd41752 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -165,7 +165,7 @@
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Daten erneut aktivieren"</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>
+    <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS wird gesucht"</string>
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Standort durch GPS festgelegt"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Standortanfragen aktiv"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Alle Benachrichtigungen löschen"</string>
@@ -206,22 +206,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Farbinversionsmodus"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Kontrastverbesserungsmodus"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Farbkorrekturmodus"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"Letzte"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"App-Info"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"Suche"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netzwerk wird\neventuell überwacht."</string>
     <string name="description_target_search" msgid="3091587249776033139">"Suche"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach oben schieben"</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach links schieben"</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"Benachrichtigung ausgeblendet"</item>
-    <item quantity="other" msgid="7388721375827338153">"%d Benachrichtigungen ausgeblendet"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"Zum Ansehen tippen"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"Nicht stören"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"%d mehr"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Zum Öffnen erneut tippen"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Zum Entsperren nach oben wischen"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 6dcffcf..96e2aaa 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -206,22 +206,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Λειτουργία αναστροφής χρώματος"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Λειτουργία βελτίωσης αντίθεσης"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Λειτουργία διόρθωσης χρώματος"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"ΠΡΟΣΦΑΤΑ"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"Πληροφορίες εφαρμογής"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"αναζήτηση"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Το δίκτυο μπορεί\nνα παρακολουθείται"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Αναζήτηση"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Κύλιση προς τα επάνω για <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Κύλιση προς τα αριστερά για <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"Έγινε απόκρυψη της ειδοποίησης"</item>
-    <item quantity="other" msgid="7388721375827338153">"Έγινε απόκρυψη %d ειδοποιήσεων"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"Αγγίξτε για εμφάνιση"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"Μην ενοχλείτε"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"%d ακόμη"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Πατήστε ξανά για να ανοίξετε"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Σύρετε για να ξεκλειδώσετε"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 91a334a..342061e 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -204,22 +204,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Colour inversion mode"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Enhanced contrast mode"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Colour correction mode"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"RECENTS"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Network may\nbe monitored"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Search"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Slide up for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Slide left for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"Notification hidden"</item>
-    <item quantity="other" msgid="7388721375827338153">"%d notifications hidden"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"Touch to show"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"Do not disturb"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"%d more"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Tap again to open"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Swipe up to unlock"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 91a334a..342061e 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -204,22 +204,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Colour inversion mode"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Enhanced contrast mode"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Colour correction mode"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"RECENTS"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Network may\nbe monitored"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Search"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Slide up for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Slide left for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"Notification hidden"</item>
-    <item quantity="other" msgid="7388721375827338153">"%d notifications hidden"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"Touch to show"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"Do not disturb"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"%d more"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Tap again to open"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Swipe up to unlock"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 2150cbe..00041a2 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Aplicaciones recientes"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Buscar"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Cámara"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Teléfono"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botón Cambiar método de entrada"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidad"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de pantalla más pequeña a más grande"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 3424166..2a977ee 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -198,28 +198,14 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"No conectado"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"No hay red."</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desactivado"</string>
-    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Enviar contenido a pantalla"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Pantalla de Cast"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillo"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Modo de inversión de color"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Modo de contraste mejorado"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Modo de corrección de color"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"RECIENTES"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"La red se\npuede supervisar"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Buscar"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Desliza el dedo hacia arriba para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Desliza el dedo hacia la izquierda para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"Notification oculta"</item>
-    <item quantity="other" msgid="7388721375827338153">"%d notificaciones ocultas"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"Toca para mostrar"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"No molestar"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"%d más"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Toca de nuevo para abrir"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Desliza el dedo hacia arriba para desbloquear"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 8dbf9af..4c42a32 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Hiljutised rakendused"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Otsing"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kaamera"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</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>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index b2ac990..a9c6af7 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"برنامه‌های اخیر"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"جستجو"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"دوربین"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"تلفن"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"کلید تغییر روش ورود متن."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"دکمه بزرگنمایی سازگار."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"بزرگنمایی از صفحه‌های کوچک تا بزرگ."</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index af0df4d..8ddf070 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Viimeaikaiset sovellukset"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Haku"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Puhelin"</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>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index f01c99a..69b5acc 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Applications récentes"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Rechercher"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Appareil photo"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Téléphone"</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>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 5efbd2f..85f817b 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Applications récentes"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Rechercher"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Appareil photo"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Téléphoner"</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>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index e6d38ef..3167fe7 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -204,22 +204,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"रंग व्युत्क्रम मोड"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"उन्नत कंट्रास्ट मोड"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"रंग सुधार मोड"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"हाल ही का"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"एप्‍लिकेशन जानकारी"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"खोज"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"नेटवर्क को\nमॉनीटर किया जा सकता है"</string>
     <string name="description_target_search" msgid="3091587249776033139">"खोजें"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए ऊपर स्‍लाइड करें."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए बाएं स्‍लाइड करें."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"सूचना छिपी हुई है"</item>
-    <item quantity="other" msgid="7388721375827338153">"%d सूचनाएं छिपी हुई हैं"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"दिखाने के लिए स्पर्श करें"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"परेशान न करें"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"%d और"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"खोलने के लिए पुन: टैप करें"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"अनलॉक करने के लिए ऊपर स्वाइप करें"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index b777b8f..529f891 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -204,22 +204,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Način inverzije boje"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Način pojačanog kontrasta"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Način korekcije boje"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"NEDAVNO"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mreža se\nmožda prati"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Pretraživanje"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Kliznite prema gore za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Kliznite lijevo za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"Obavijest je skrivena"</item>
-    <item quantity="other" msgid="7388721375827338153">"Broj skrivenih obavijesti: %d"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"Dodirnite za prikaz"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"Ne ometaj"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"Još %d"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Dodirnite opet za otvaranje"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Prijeđite prstom prema gore za otključavanje"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 10732fe..7e064dd 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -204,22 +204,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Színinvertálás mód"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Kontrasztjavítás mód"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Színjavítás mód"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"LEGUTÓBBIAK"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"Az alkalmazás adatai"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"keresés"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Lehet, hogy a\nhálózat felügyelt"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Keresés"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"A(z) <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> művelethez csúsztassa felfelé."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"A(z) <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> művelethez csúsztassa balra."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"Értesítés elrejtve"</item>
-    <item quantity="other" msgid="7388721375827338153">"%d értesítés elrejtve"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"A megtekintéshez érintse meg"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"Ne zavarjanak"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"%d további"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Koppintson rá ismét a megnyitáshoz"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Húzza felfelé az ujját a feloldáshoz"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index f1c4869..8c26a8a 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Վերջին ծրագրերը"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Որոնել"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Ֆոտոխցիկ"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Հեռախոս"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Միացնել մուտքագրման եղանակի կոճակը:"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Համատեղելիության խոշորացման կոճակը:"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Դիտափոխել փոքրից ավելի մեծ էկրան:"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index f0b0713..167b101 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -204,22 +204,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Mode inversi warna"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Mode kontras yang disempurnakan"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Mode koreksi warna"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"TERBARU"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"Info Aplikasi"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"telusuri"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Jaringan bisa\ndiawasi"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Telusuri"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Geser ke atas untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Geser ke kiri untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"Pemberitahuan disembunyikan"</item>
-    <item quantity="other" msgid="7388721375827338153">"%d pemberitahuan disembunyikan"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"Sentuh untuk menampilkan"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"Jangan ganggu"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"%d lainnya"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Ketuk lagi untuk membuka"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Gesek ke atas untuk membuka kunci"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 6a57682..6321870 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -188,8 +188,8 @@
     <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Bloccato in verticale"</string>
     <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Bloccato in orizzontale"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"Metodo di immissione"</string>
-    <string name="quick_settings_location_label" msgid="5011327048748762257">"Geolocalizz."</string>
-    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Geolocalizz. non attiva"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"Geolocalizzazione"</string>
+    <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Posizione non attiva"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Dispositivo multimediale"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
     <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Solo chiamate di emergenza"</string>
@@ -206,22 +206,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Modalità inversione colori"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Modalità di contrasto avanzata"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Modalità di correzione del colore"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"MESSAGGI RECENTI"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informazioni sull\'applicazione"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"La rete potrebbe\nessere monitorata"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Ricerca"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Su per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"A sinistra per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"Notifica nascosta"</item>
-    <item quantity="other" msgid="7388721375827338153">"%d notifiche nascoste"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"Tocca per visualizzare"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"Non disturbare"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"Altre %d"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Tocca ancora per aprire"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Scorri verso l\'alto per sbloccare"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 3e87b76..e1625076 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"אפליקציות אחרונות"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"חפש"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"מצלמה"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"טלפון"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"לחצן החלפת שיטת קלט."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"לחצן מרחק מתצוגה של תאימות."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"שנה מרחק מתצוגה של מסך קטן לגדול יותר."</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 1edb630..a9e7935 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"最近使ったアプリ"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"検索"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"カメラ"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"電話"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"入力方法の切り替えボタン。"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"互換ズームボタン。"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"小さい画面から大きい画面に拡大。"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 9d4344a..c56864b 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"ბოლოს გამოყენებული აპები"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"ძიება"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"კამერა"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"ტელეფონი"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"შეყვანის მეთოდის გადართვის ღილაკი."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"თავსებადი მასშტაბირების ღილაკი."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"შეცვალეთ პატარა ეკრანი უფრო დიდით."</string>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index bb2d3b9..a5008b3 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -64,7 +64,7 @@
     <string name="screenshot_saving_ticker" msgid="7403652894056693515">"កំពុង​រក្សាទុក​រូបថត​អេក្រង់…"</string>
     <string name="screenshot_saving_title" msgid="8242282144535555697">"កំពុង​រក្សាទុក​រូបថត​អេក្រង់..."</string>
     <string name="screenshot_saving_text" msgid="2419718443411738818">"រូបថត​អេក្រង់​កំពុង​ត្រូវ​បាន​រក្សាទុក។"</string>
-    <string name="screenshot_saved_title" msgid="6461865960961414961">"បាន​ចាប់​យក​រូបថត​អេក្រង់។"</string>
+    <string name="screenshot_saved_title" msgid="6461865960961414961">"បាន​ចាប់​យក​រូបថត​អេក្រង់។​"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"ប៉ះ ​ដើម្បី​មើល​រូបថត​អេក្រង់​របស់​អ្នក​។"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"មិន​អាច​ចាប់​យក​រូប​ថត​អេក្រង់​។"</string>
     <string name="screenshot_failed_text" msgid="8134011269572415402">"មិន​អាច​រក្សាទុក​រូបថត​អេក្រង់​។ ឧបករណ៍​ផ្ទុក​អាច​កំពុង​ប្រើ​​។"</string>
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"កម្មវិធី​ថ្មីៗ"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"ស្វែងរក"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"ម៉ាស៊ីន​ថត"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"ទូរស័ព្ទ"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ប្ដូរ​ប៊ូតុង​វិធីសាស្ត្រ​បញ្ចូល។"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ប៊ូតុង​ពង្រីក​ត្រូវ​គ្នា។"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ពង្រីក/បង្រួម​​អេក្រង់​ពី​​ទៅធំ"</string>
@@ -139,7 +140,7 @@
     <string name="accessibility_remove_notification" msgid="3603099514902182350">"សម្អាត​ការ​ជូន​ដំណឹង។"</string>
     <string name="accessibility_gps_enabled" msgid="3511469499240123019">"បាន​បើក GPS ។"</string>
     <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"ទទួល​​ GPS ។"</string>
-    <string name="accessibility_tty_enabled" msgid="4613200365379426561">"បាន​បើក​ម៉ាស៊ីន​អង្គុលីលេខ"</string>
+    <string name="accessibility_tty_enabled" msgid="4613200365379426561">"បាន​បើក​ម៉ាស៊ីន​អង្គុលីលេខ​"</string>
     <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"កម្មវិធី​រោទ៍​ញ័រ។"</string>
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"កម្មវិធី​រោទ៍​ស្ងាត់។"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> បដិសេធ។"</string>
@@ -186,7 +187,7 @@
     <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"ចាក់​សោ​​បញ្ឈរ"</string>
     <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"ចាក់​សោ​​​ផ្ដេក"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"វិធីសាស្ត្រ​បញ្ចូល"</string>
-    <string name="quick_settings_location_label" msgid="5011327048748762257">"ទី​តាំង"</string>
+    <string name="quick_settings_location_label" msgid="5011327048748762257">"ទី​តាំង​"</string>
     <string name="quick_settings_location_off_label" msgid="7464544086507331459">"ទីតាំង​បាន​បិទ"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"ឧបករណ៍​មេឌៀ"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
@@ -207,7 +208,7 @@
     <string name="recents_empty_message" msgid="2269156590813544104">"ថ្មីៗ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ព័ត៌មាន​កម្មវិធី"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ស្វែងរក"</string>
-    <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"បណ្ដាញ​អាច​\nត្រូវ​បាន​ត្រួតពិនិត្យ"</string>
+    <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"បណ្ដាញ​អាច​\nត្រូវ​បាន​ត្រួតពិនិត្យ​"</string>
     <string name="description_target_search" msgid="3091587249776033139">"ស្វែងរក"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"រុញ​ឡើង​លើ​ដើម្បី <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string>
     <string name="description_direction_left" msgid="7207478719805562165">"រុញ​ទៅ​ឆ្វេង​ដើម្បី <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 83ffa9f..bd7a257 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"최근에 사용한 앱"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"검색"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"카메라"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"전화"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"입력 방법 버튼을 전환합니다."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"호환성 확대/축소 버튼입니다."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"작은 화면을 큰 화면으로 확대합니다."</string>
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index 7223773..5755029 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -25,7 +25,7 @@
     <integer name="status_bar_recents_bg_gradient_degrees">90</integer>
 
     <!-- The number of columns in the QuickSettings -->
-    <integer name="quick_settings_num_columns">6</integer>
+    <integer name="quick_settings_num_columns">4</integer>
 
     <!-- The maximum number of rows in the QuickSettings -->
     <integer name="quick_settings_max_rows">2</integer>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 9a3d483..59cf520 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -204,22 +204,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"ໂໝດສະລັບສີ"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"ໂໝດຄວາມຕ່າງແສງ"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"ໂໝດການແກ້ໄຂສີ"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"ບໍ່​ດົນ​ມາ​ນີ້"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"​ຂໍ້​ມູນ​ແອັບ​ພ​ລິ​ເຄ​ຊັນ"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"ຊອກຫາ"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ເຄືອຄ່າຍອາດ\nຖືກຕິດຕາມ"</string>
     <string name="description_target_search" msgid="3091587249776033139">"ຊອກຫາ"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"ເລື່ອນຂຶ້ນເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"ເລື່ອນໄປທາງຊ້າຍເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"ເຊື່ອງ​ການ​ແຈ້ງ​ເຕ​ືອນ​ແລ້ວ"</item>
-    <item quantity="other" msgid="7388721375827338153">"ເຊື່ອງ %d ການ​ແຈ້ງ​ເຕືອນ​ແລ້ວ"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"​ແຕະ​ເພື່ອ​ສະ​ແດງ"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"ຫ້າມລົບກວນ"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"%d ເພີ່ມ​ເຕີມ"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"ແຕະ​ອີກ​ຄັ້ງ​ເພື່ອ​ເປີດ"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"ເລື່ອນ​ຂຶ້ນ​ເພື່ອ​ປົດ​ລັອກ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 0e9f5b7..3fe74b3 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -69,7 +69,7 @@
     <string name="screenshot_failed_title" msgid="705781116746922771">"Nepavyko užfiksuoti ekrano kopijos."</string>
     <string name="screenshot_failed_text" msgid="8134011269572415402">"Nepavyko išsaugoti ekrano kopijos. Gali būti naudojama atmintis."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB failo perdavimo parinktys"</string>
-    <string name="use_mtp_button_title" msgid="4333504413563023626">"Įmontuoti kaip medijos leistuvą (MTP)"</string>
+    <string name="use_mtp_button_title" msgid="4333504413563023626">"Įmontuoti kaip medijos grotuvą (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Įmontuoti kaip fotoaparatą (PTP)"</string>
     <string name="installer_cd_button_title" msgid="2312667578562201583">"Įdiegti „Mac“ skirtą „Android“ perkėl. priem. pr."</string>
     <string name="accessibility_back" msgid="567011538994429120">"Atgal"</string>
@@ -180,7 +180,7 @@
     <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>
-    <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Skaistis"</string>
+    <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Šviesumas"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Automatiškai sukti"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Sukimas užrakintas"</string>
     <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Užrakinta stačia padėtis"</string>
@@ -199,27 +199,13 @@
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Tinklo nėra"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"„Wi-Fi“ išjungta"</string>
     <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Perduoti ekraną"</string>
-    <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Skaistis"</string>
+    <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Šviesumas"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATINIS"</string>
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Spalvų inversijos režimas"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Patobulinto kontrasto režimas"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Spalvų taisymo režimas"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"PASTARIEJI"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"Programos informacija"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"paieška"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tinklas gali\nbūti stebimas"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Paieška"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Slyskite aukštyn link <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Slyskite į kairę link <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"Pranešimas paslėptas"</item>
-    <item quantity="other" msgid="7388721375827338153">"Paslėpta pranešimų: %d"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"Palieskite, kad būtų rodoma"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"Netrukdyti"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"Dar %d"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Palieskite dar kartą, kad atidarytumėte"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Perbraukite aukštyn, kad atrakintumėte"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index ca07095..4230b2e 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -204,22 +204,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Krāsu inversijas režīms"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Uzlabota kontrasta režīms"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Krāsu korekcijas režīms"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"JAUNĀKIE"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informācija par lietojumprogrammu"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"Meklēt"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tīkls var\ntikt uzraudzīts"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Meklēt"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Velciet uz augšu, lai veiktu šādu darbību: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Velciet pa kreisi, lai veiktu šādu darbību: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"Paziņojums paslēpts"</item>
-    <item quantity="other" msgid="7388721375827338153">"%d paziņojumi paslēpti"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"Pieskarieties, lai rādītu"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"Netraucēt"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"vēl %d"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Pieskarieties vēlreiz, lai atvērtu"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Velciet uz augšu, lai atbloķētu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 4545301..4669d99 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Сүүлийн апп"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Хайх"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Камер"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Утас"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Оруулах аргыг сэлгэх товч."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Тохиромжтой өсгөх товч."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Жижгээс том дэлгэцрүү өсгөх."</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index aa7e6eb..60e5527 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Aplikasi terbaharu"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Cari"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</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>
@@ -220,8 +221,6 @@
   <plurals name="keyguard_more_overflow_text">
     <item quantity="other" msgid="9180696159506883684">"%d lagi"</item>
   </plurals>
-    <!-- no translation found for notification_tap_again (7590196980943943842) -->
-    <skip />
-    <!-- no translation found for keyguard_unlock (8043466894212841998) -->
-    <skip />
+    <string name="notification_tap_again" msgid="7590196980943943842">"Ketik lagi untuk membuka"</string>
+    <string name="keyguard_unlock" msgid="8043466894212841998">"Leret ke atas untuk membuka kunci"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 001e733..12deaef 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -204,22 +204,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Modus for fargeinvertering"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Forbedret kontrastmodus"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Modus for fargekorrigering"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"NYLIGE"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformasjon"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"Søk"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Nettverket kan\nvære overvåket"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Søk"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Dra opp for å <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Dra til venstre for å <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"Varselet er skjult"</item>
-    <item quantity="other" msgid="7388721375827338153">"%d varsler er skjult"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"Trykk for å vise"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"Ikke forstyrr"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"%d til"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Trykk på nytt for å åpne"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Sveip oppover for å låse opp"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 8a6e33b..59c64b5 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -204,22 +204,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Modus voor kleurinversie"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Modus voor verbeterd contrast"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Modus voor kleurcorrectie"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"RECENTE"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"App-informatie"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"zoeken"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netwerk kan\nworden gecontroleerd"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Zoeken"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Veeg omhoog voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Veeg naar links voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"Melding verborgen"</item>
-    <item quantity="other" msgid="7388721375827338153">"%d meldingen verborgen"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"Raak aan om weer te geven"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"Niet storen"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"Nog %d"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Tik nogmaals om te openen"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Veeg omhoog om te ontgrendelen"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 4862d1b..00bea9c 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Ostatnie aplikacje"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Szukaj"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Aparat"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</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>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 012283a..fc25ea8 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -204,22 +204,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Modo de inversão de cor"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Modo de contraste melhorado"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Modo de correção de cor"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"RECENTES"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações da aplicação"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"A rede pode ser\nmonitorizada"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Pesquisar"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Deslize para cima para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Deslize para a esquerda para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"Notificação oculta"</item>
-    <item quantity="other" msgid="7388721375827338153">"%d notificações ocultas"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"Toque para mostrar"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"Não incomodar"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"Mais %d"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Toque novamente para abrir"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Deslizar rapidamente com o dedo para cima para desbloquear"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 0978d18..2337a7d 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Aplicativos recentes"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Pesquisar"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Câmera"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefone"</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>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index 25f643f..adf54bc 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -378,12 +378,6 @@
     <skip />
     <!-- no translation found for quick_settings_color_space_label (853443689745584770) -->
     <skip />
-    <!-- no translation found for recents_empty_message (2269156590813544104) -->
-    <skip />
-    <!-- no translation found for recents_app_info_button_label (2890317189376000030) -->
-    <skip />
-    <!-- no translation found for recents_search_bar_label (8074997400187836677) -->
-    <skip />
     <!-- no translation found for ssl_ca_cert_warning (9005954106902053641) -->
     <skip />
     <!-- no translation found for description_target_search (3091587249776033139) -->
@@ -392,15 +386,4 @@
     <skip />
     <!-- no translation found for description_direction_left (7207478719805562165) -->
     <skip />
-    <!-- no translation found for zen_mode_notification_title:one (7809876956258040354) -->
-    <!-- no translation found for zen_mode_notification_title:other (7388721375827338153) -->
-    <!-- no translation found for zen_mode_notification_text (8336623711388065713) -->
-    <skip />
-    <!-- no translation found for zen_mode_title (8793432092004749188) -->
-    <skip />
-    <!-- no translation found for keyguard_more_overflow_text:other (9180696159506883684) -->
-    <!-- no translation found for notification_tap_again (7590196980943943842) -->
-    <skip />
-    <!-- no translation found for keyguard_unlock (8043466894212841998) -->
-    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 6281110..4f2c471 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Aplicaţii recente"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Căutați"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Cameră foto"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</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>
@@ -220,8 +221,6 @@
   <plurals name="keyguard_more_overflow_text">
     <item quantity="other" msgid="9180696159506883684">"Încă %d"</item>
   </plurals>
-    <!-- no translation found for notification_tap_again (7590196980943943842) -->
-    <skip />
-    <!-- no translation found for keyguard_unlock (8043466894212841998) -->
-    <skip />
+    <string name="notification_tap_again" msgid="7590196980943943842">"Atingeți din nou pentru a deschide"</string>
+    <string name="keyguard_unlock" msgid="8043466894212841998">"Glisați în sus pentru a debloca"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 976a793..837e98e 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Недавние приложения"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Поиск"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Телефон."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка переключения способа ввода."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка масштабирования (режим совместимости)"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Уменьшение изображения для увеличения свободного места на экране."</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 1224c3a..ae70ed6 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Nové aplikácie"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Hľadať"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparát"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefón"</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>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 10011bc..a5b3244 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -183,7 +183,7 @@
     <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Svetlost"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Samodejno vrtenje"</string>
     <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Zaklenjeno vrtenje"</string>
-    <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Zaklenjeno na pokončno postavitev"</string>
+    <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Zaklenjeno na navpično postavitev"</string>
     <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Zaklenjeno na ležečo postavitev"</string>
     <string name="quick_settings_ime_label" msgid="7073463064369468429">"Način vnosa"</string>
     <string name="quick_settings_location_label" msgid="5011327048748762257">"Lokacija"</string>
@@ -204,22 +204,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Način inverzije barv"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Način izboljšanega kontrasta"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Način popravljanja barv"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"NEDAVNI"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"Podatki o aplikaciji"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"iskanje"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Omrežje je\nlahko spremljano"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Iskanje"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Povlecite navzgor za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Povlecite v levo za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"Obvestilo je skrito"</item>
-    <item quantity="other" msgid="7388721375827338153">"Skritih je toliko obvestil: %d"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"Dotaknite se za prikaz"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"Ne moti"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"še %d"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Znova se dotaknite, da odprete"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Povlecite, da odklenete"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 0c6a939..0bdccee 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -204,22 +204,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Режим инверзије боје"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Режим унапређеног контраста"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Режим корекције боје"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"НАЈНОВИЈЕ"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"Информације о апликацији"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"претражи"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мрежа се можда\nнадгледа"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Претрага"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Превуците нагоре за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Превуците улево за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"Обавештење је сакривено"</item>
-    <item quantity="other" msgid="7388721375827338153">"Сакривена обавештења: %d"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"Додирните за приказ"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"Не узнемиравај"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"Још %d"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Додирните поново да бисте отворили"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Превуците нагоре да бисте откључали"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index d8bd1b1..efe7fcb 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -204,22 +204,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Färginverteringsläge"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Kontrastförbättringsläge"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Färgkorrigeringsläge"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"NYA"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformation"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"sök"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Nätverket kan\nvara övervakat"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Sök"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Dra uppåt för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Dra åt vänster för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"Aviseringen har dolts"</item>
-    <item quantity="other" msgid="7388721375827338153">"%d aviseringar har dolts"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"Tryck här om du vill visa aviseringar"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"Stör ej"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"%d till"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Tryck igen för att öppna"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Dra uppåt om du vill låsa upp"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index d308b518..2713cf9 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -76,6 +76,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Programu za hivi karibuni"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Tafuta"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Simu"</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>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
deleted file mode 100644
index c6c0719..0000000
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (c) 2012, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
--->
-<resources>
-    <!-- Layout parameters for the notification panel -->
-	<dimen name="notification_panel_margin_bottom">0dp</dimen>
-    <dimen name="notification_panel_margin_left">32dp</dimen>
-</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index fe2224e..6dea81f 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -21,7 +21,7 @@
      for different hardware and product builds. -->
 <resources>
     <!-- The number of columns in the QuickSettings -->
-    <integer name="quick_settings_num_columns">3</integer>
+    <integer name="quick_settings_num_columns">4</integer>
 
     <!-- The maximum number of rows in the QuickSettings -->
     <integer name="quick_settings_max_rows">4</integer>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 5b5587d..7372181 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -19,10 +19,6 @@
     <!-- The width of the notification panel window: 446 + 16 + 16 (padding in the bg drawable) -->
     <dimen name="notification_panel_width">478dp</dimen>
 
-    <!-- Layout parameters for the notification panel -->
-    <dimen name="notification_panel_margin_bottom">192dp</dimen>
-    <dimen name="notification_panel_margin_left">16dp</dimen>
-
     <!-- Gravity for the notification panel -->
     <!-- 0x31 = top|center_horizontal -->
     <integer name="notification_panel_layout_gravity">0x31</integer>
@@ -36,13 +32,13 @@
     <!-- Height of search panel including navigation bar height -->
     <dimen name="navbar_search_panel_height">280dip</dimen>
 
+    <!-- The width of the view containing the menu/ime navigation bar icons -->
+    <dimen name="navigation_extra_key_width">48dip</dimen>
+
     <!-- Size of application thumbnail -->
     <dimen name="status_bar_recents_thumbnail_width">200dp</dimen>
     <dimen name="status_bar_recents_thumbnail_height">177dp</dimen>
 
-    <!-- On tablets, panels drop from the statusbar instead of overlapping it. -->
-    <dimen name="panel_holder_padding_top">@*android:dimen/status_bar_height</dimen>
-
     <!-- Minimum fraction of the screen that should be taken up by the notification panel. -->
     <item type="dimen" name="notification_panel_min_height_frac">40%</item>
 
diff --git a/packages/SystemUI/res/values-sw600dp/styles.xml b/packages/SystemUI/res/values-sw600dp/styles.xml
index b7becac..d4a99866 100644
--- a/packages/SystemUI/res/values-sw600dp/styles.xml
+++ b/packages/SystemUI/res/values-sw600dp/styles.xml
@@ -18,4 +18,15 @@
     <style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer">
         <item name="android:layout_width">480dp</item>
     </style>
+
+    <style name="NotificationsQuickSettings">
+        <item name="android:layout_width">@dimen/notification_panel_width</item>
+        <item name="android:layout_height">match_parent</item>
+        <item name="android:layout_gravity">top|center_horizontal</item>
+    </style>
+
+    <style name="StatusBarHeader">
+        <item name="android:layout_width">@dimen/notification_panel_width</item>
+        <item name="android:layout_gravity">center_horizontal</item>
+    </style>
 </resources>
diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml
index bf01a8d..7cf711a 100644
--- a/packages/SystemUI/res/values-sw720dp/config.xml
+++ b/packages/SystemUI/res/values-sw720dp/config.xml
@@ -32,5 +32,8 @@
 
     <!-- Min alpha % that recent items will fade to while being dismissed -->
     <integer name="config_recent_item_min_alpha">0</integer>
+
+    <!-- Transposes the search bar layout in landscape -->
+    <bool name="recents_transpose_search_layout_with_orientation">false</bool>
 </resources>
 
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index b1fc00a..a1c5b66 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -24,8 +24,6 @@
 
     <!-- The width of the ticker, including the icon -->
     <dimen name="notification_ticker_width">360dp</dimen>
-    <!-- Status bar panel bottom offset (height of status bar - overlap) -->
-    <dimen name="status_bar_panel_bottom_offset">36dp</dimen>
     <!-- gap on either side of status bar notification icons -->
     <dimen name="status_bar_icon_padding">1dp</dimen>
     <!-- The width of the notification panel window -->
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 7929a30..4dc3d22 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"แอปพลิเคชันล่าสุด"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"ค้นหา"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"กล้องถ่ายรูป"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"โทรศัพท์"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ปุ่มสลับวิธีการป้อนข้อมูล"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ปุ่มซูมที่ใช้งานร่วมกันได้"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ซูมหน้าจอให้มีขนาดใหญ่ขึ้น"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 92473a4..e50f723 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Kamakailang apps"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Hanapin"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Camera"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telepono"</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>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 9837ff8..9100055 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Son uygulamalar"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Ara"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</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>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 534f520..3a474a4 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -204,22 +204,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Режим інверсії кольорів"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Режим посиленого контрасту"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Режим коригування кольору"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"ОСТАННІ"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"Інформація про додаток"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"пошук"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мережа може\nвідстежуватися"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Пошук"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Проведіть пальцем угору, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Проведіть пальцем ліворуч, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"Сповіщення сховано"</item>
-    <item quantity="other" msgid="7388721375827338153">"Сховано сповіщень: %d"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"Торкніться, щоб показати"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"Не турбувати"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"Ще %d"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Торкніться знову, щоб відкрити"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Проведіть пальцем угору, щоб розблокувати"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 56fc89c..a4aadb3 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Ứng dụng gần đây"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Tìm kiếm"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Máy ảnh"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Điện thoại"</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>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 442fdb7..a5ae2b7 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"最近运行的应用"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"搜索"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"相机"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"电话"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"输入法切换按钮。"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"兼容性缩放按钮。"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"将小屏幕的图片放大在较大屏幕上显示。"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 54a3b1e..d229347 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -206,22 +206,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"色彩反轉模式"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"增強對比模式"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"色彩校準模式"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"近期"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資料"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"網絡可能會\n受到監控"</string>
     <string name="description_target_search" msgid="3091587249776033139">"搜尋"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"向上滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
     <string name="description_direction_left" msgid="7207478719805562165">"向左滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"已隱藏通知"</item>
-    <item quantity="other" msgid="7388721375827338153">"已隱藏 %d 則通知"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"輕觸即可顯示"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"請勿騷擾"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"還有 %d 個"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"再次輕按即可開啟"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"向上快速滑動即可解鎖"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index fc74f53..1e3f455 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"最近使用的應用程式"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"搜尋"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"相機"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"電話"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"相容性縮放按鈕。"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"將較小螢幕的畫面放大在較大螢幕上顯示。"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index dfe8838..d676b5c 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -204,22 +204,8 @@
     <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Imodi yokuguqulwa kombala"</string>
     <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Imodi ethuthukisiwe yokugqama"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Imodi yokulungisa umbala"</string>
-    <string name="recents_empty_message" msgid="2269156590813544104">"OKWAKAMUVA"</string>
-    <string name="recents_app_info_button_label" msgid="2890317189376000030">"Ulwazi lohlelo lokusebenza"</string>
-    <string name="recents_search_bar_label" msgid="8074997400187836677">"sesha"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Kungenzeka inethiwekhi\niqashiwe"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Sesha"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Shelelisela ngenhla ku-<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Shelelisela ngakwesokunxele ku-<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-  <plurals name="zen_mode_notification_title">
-    <item quantity="one" msgid="7809876956258040354">"Isaziso sifihliwe"</item>
-    <item quantity="other" msgid="7388721375827338153">"%d izaziso zifihliwe"</item>
-  </plurals>
-    <string name="zen_mode_notification_text" msgid="8336623711388065713">"Thinta ukuze ubonise"</string>
-    <string name="zen_mode_title" msgid="8793432092004749188">"Ungaphazamisi"</string>
-  <plurals name="keyguard_more_overflow_text">
-    <item quantity="other" msgid="9180696159506883684">"%d okuningi"</item>
-  </plurals>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Thepha futhi ukuze uvule"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Swayiphela phezulu ukuze uvule"</string>
 </resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 734abdc..8fd1206 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -45,6 +45,19 @@
     <declare-styleable name="BatteryMeterView">
         <attr name="frameColor" format="color" />
     </declare-styleable>
+    <declare-styleable name="SwipeAffordanceView">
+        <attr name="swipeDirection" format="enum">
+            <enum name="start" value="0" />
+            <enum name="end" value="1" />
+        </attr>
+    </declare-styleable>
+    <declare-styleable name="Clock">
+        <attr name="amPmStyle" format="enum">
+            <enum name="normal" value="0" />
+            <enum name="small" value="1" />
+            <enum name="gone" value="2" />
+        </attr>
+    </declare-styleable>
     <attr name="orientation">
         <enum name="horizontal" value="0" />
         <enum name="vertical" value="1" />
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 9281265..7de1bd0 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -30,13 +30,20 @@
     <drawable name="recents_callout_line">#99ffffff</drawable>
     <drawable name="notification_item_background_legacy_color">#ffaaaaaa</drawable>
     <drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable>
-    <drawable name="notification_header_bg">#FF000000</drawable>
     <color name="notification_panel_scrim_color">#A0000000</color>
     <color name="notification_panel_scrim_color_keyguard">#80000000</color>
     <color name="batterymeter_frame_color">#66FFFFFF</color><!-- 40% white -->
     <color name="batterymeter_charge_color">#FFFFFFFF</color>
     <color name="batterymeter_bolt_color">#FFFFFFFF</color>
     <color name="qs_batterymeter_frame_color">#FF404040</color>
+    <color name="system_primary_color">#ff263238</color>
+    <color name="system_secondary_color">#ff384248</color>
+    <color name="system_accent_color">#ff7fcac3</color>
+    <color name="system_error_color">#fff0592b</color>
+    <color name="quick_settings_tile_icon_enabled">#ffffffff</color>
+    <color name="quick_settings_tile_icon_disabled">#ffcccccc</color>
+    <color name="quick_settings_tile_divider">#ff888888</color>
+    <color name="quick_settings_tile_text">#FFFFFFFF</color>
     <color name="status_bar_clock_color">#FFFFFFFF</color>
     <drawable name="notification_item_background_color">#ff111111</drawable>
     <drawable name="notification_item_background_color_pressed">#ff454545</drawable>
@@ -53,10 +60,18 @@
     <!-- The default recents task bar background color. -->
     <color name="recents_task_bar_default_background_color">#e6444444</color>
     <!-- The default recents task bar text color. -->
-    <color name="recents_task_bar_default_text_color">#ffffffff</color>
+    <color name="recents_task_bar_default_text_color">#ffeeeeee</color>
     <!-- The recents task bar light text color to be drawn on top of dark backgrounds. -->
-    <color name="recents_task_bar_light_text_color">#ffffffff</color>
+    <color name="recents_task_bar_light_text_color">#ffeeeeee</color>
     <!-- The recents task bar dark text color to be drawn on top of light backgrounds. -->
     <color name="recents_task_bar_dark_text_color">#ff222222</color>
+    <!-- The recents task bar light dismiss icon color to be drawn on top of dark backgrounds. -->
+    <color name="recents_task_bar_light_dismiss_color">#ffeeeeee</color>
+    <!-- The recents task bar dark dismiss icon color to be drawn on top of light backgrounds. -->
+    <color name="recents_task_bar_dark_dismiss_color">#ff333333</color>
 
+    <!-- Our quantum color palette (deep teal) -->
+    <color name="primary_color">#ff7fcac3</color>
+    <color name="background_color_1">#ff384248</color>
+    <color name="background_color_1_press">#ff54656e</color>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 722ca15..21eb41c 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -99,9 +99,6 @@
 
     <integer name="blinds_pop_duration_ms">10</integer>
 
-    <!-- The device supports quick settings. -->
-    <bool name="config_hasQuickSettings">true</bool>
-
     <!-- Should "4G" be shown instead of "LTE" when the network is NETWORK_TYPE_LTE? -->
     <bool name="config_show4GForLTE">true</bool>
 
@@ -115,12 +112,18 @@
     <integer name="recents_filter_animate_current_views_min_duration">175</integer>
     <!-- The min animation duration for animating views that are newly visible. -->
     <integer name="recents_filter_animate_new_views_min_duration">125</integer>
-    <!-- The min animation duration for animating views that are newly visible. -->
+    <!-- The min animation duration for animating the task bar in. -->
     <integer name="recents_animate_task_bar_enter_duration">200</integer>
+    <!-- The min animation duration for animating the task bar out. -->
+    <integer name="recents_animate_task_bar_exit_duration">150</integer>
     <!-- The animation duration for animating in the info pane. -->
     <integer name="recents_animate_task_view_info_pane_duration">150</integer>
+    <!-- The animation duration for animating the removal of a task view. -->
+    <integer name="recents_animate_task_view_remove_duration">250</integer>
     <!-- The minimum alpha for the dim applied to cards that go deeper into the stack. -->
     <integer name="recents_max_task_stack_view_dim">96</integer>
+    <!-- Transposes the search bar layout in landscape -->
+    <bool name="recents_transpose_search_layout_with_orientation">true</bool>
 
     <!-- Whether to enable KeyguardService or not -->
     <bool name="config_enableKeyguardService">true</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 9837d9b..79612e0 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -128,8 +128,8 @@
     <!-- The width of the view containing non-menu status bar icons -->
     <dimen name="navigation_key_width">80dip</dimen>
 
-    <!-- The width of the view containing the menu status bar icon -->
-    <dimen name="navigation_menu_key_width">40dip</dimen>
+    <!-- The width of the view containing the menu/ime navigation bar icons -->
+    <dimen name="navigation_extra_key_width">40dip</dimen>
 
     <!-- Default distance beyond which snaps to the matching target -->
     <dimen name="navbar_search_snap_margin">40dip</dimen>
@@ -152,21 +152,14 @@
     <!-- Amount of close_handle that will NOT overlap the notification list -->
     <dimen name="close_handle_underlap">32dp</dimen>
 
-    <!-- Height of the notification panel header bar -->
-    <dimen name="notification_panel_header_height">48dp</dimen>
+    <!-- Height of the status bar header bar -->
+    <dimen name="status_bar_header_height">56dp</dimen>
 
-    <!-- Extra space above the panel -->
-    <dimen name="notification_panel_padding_top">0dp</dimen>
+    <!-- Height of the status bar header bar when expanded -->
+    <dimen name="status_bar_header_height_expanded">144dp</dimen>
 
-    <!-- Extra space above the clock in the panel -->
-    <dimen name="notification_panel_header_padding_top">0dp</dimen>
-
-    <!-- Extra space above the panel holder -->
-    <dimen name="panel_holder_padding_top">0dp</dimen>
-
-    <!-- Layout parameters for the notification panel -->
-    <dimen name="notification_panel_margin_bottom">0dp</dimen>
-    <dimen name="notification_panel_margin_left">0dp</dimen>
+    <!-- Height of the status bar header bar when on Keyguard -->
+    <dimen name="status_bar_header_height_keyguard">40dp</dimen>
 
     <!-- Gravity for the notification panel -->
     <!-- 0x37 = fill_horizontal|top -->
@@ -206,9 +199,6 @@
     <!-- Quick Settings CA Cert Warning tile geometry: gap between icon and text -->
     <dimen name="qs_cawarn_tile_margin_below_icon">3dp</dimen>
 
-    <!-- The width of the notification panel window: match_parent below sw600dp -->
-    <dimen name="notification_panel_width">-1dp</dimen>
-
     <!-- used by DessertCase -->
     <dimen name="dessert_case_cell_size">192dp</dimen>
 
@@ -227,14 +217,20 @@
     <!-- The radius of the rounded corners on a task view. -->
     <dimen name="recents_task_view_rounded_corners_radius">2dp</dimen>
 
+    <!-- The min translation in the Z index for the last task. -->
+    <dimen name="recents_task_view_z_min">3dp</dimen>
+
+    <!-- The translation in the Z index for each task above the last task. -->
+    <dimen name="recents_task_view_z_increment">5dp</dimen>
+
+    <!-- The amount to translate when animating the removal of a task. -->
+    <dimen name="recents_task_view_remove_anim_translation_x">100dp</dimen>
+
     <!-- The amount of space a user has to scroll to dismiss any info panes. -->
     <dimen name="recents_task_stack_scroll_dismiss_info_pane_distance">50dp</dimen>
 
     <!-- The height of the search bar space. -->
-    <dimen name="recents_search_bar_space_height">40dp</dimen>
-
-    <!-- The search bar edge margins. -->
-    <dimen name="recents_search_bar_space_edge_margins">12dp</dimen>
+    <dimen name="recents_search_bar_space_height">64dp</dimen>
 
     <!-- Used to calculate the translation animation duration, the expected amount of movement 
          in dps over one second of time. -->
@@ -247,7 +243,10 @@
     <dimen name="top_stack_peek_amount">12dp</dimen>
 
     <!-- Space reserved for the cards behind the top card in the bottom stack -->
-    <dimen name="bottom_stack_peek_amount">18dp</dimen>
+    <dimen name="bottom_stack_peek_amount">12dp</dimen>
+
+    <!-- The height of the area before the bottom stack in which the notifications slow down -->
+    <dimen name="bottom_stack_slow_down_length">12dp</dimen>
 
     <!-- The side padding of the notifications-->
     <dimen name="notification_side_padding">8dp</dimen>
@@ -255,17 +254,30 @@
     <!-- Z distance between notifications if they are in the stack -->
     <dimen name="z_distance_between_notifications">2dp</dimen>
 
+    <!-- The padding between the individual notification cards when dimmed. -->
+    <dimen name="notification_padding_dimmed">0dp</dimen>
+
     <!-- The padding between the individual notification cards. -->
-    <dimen name="notification_padding">3dp</dimen>
+    <dimen name="notification_padding">4dp</dimen>
+
+    <!-- The total height of the stack in its collapsed size (i.e. when quick settings is open) -->
+    <dimen name="collapsed_stack_height">94dp</dimen>
 
     <!-- Width of the zen mode interstitial dialog. -->
     <dimen name="zen_mode_dialog_width">320dp</dimen>
 
-    <!-- Camera affordance drag distance -->
-    <dimen name="camera_drag_distance">100dp</dimen>
+    <!-- Lockscreen affordance drag distance for camera and phone. -->
+    <dimen name="affordance_drag_distance">100dp</dimen>
 
     <dimen name="quick_settings_tmp_scrim_stroke_width">8dp</dimen>
     <dimen name="quick_settings_tmp_scrim_text_size">30dp</dimen>
+    <dimen name="quick_settings_panel_padding">16dp</dimen>
+    <dimen name="quick_settings_tile_icon_outline">2dp</dimen>
+    <dimen name="quick_settings_tile_text_size">12sp</dimen>
+    <dimen name="quick_settings_tile_divider_height">1dp</dimen>
 
     <dimen name="notifications_top_padding">8dp</dimen>
+    
+    <!-- Minimum distance the user has to drag down to go to the full shade. -->
+    <dimen name="keyguard_drag_down_min_distance">100dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
new file mode 100644
index 0000000..6418930
--- /dev/null
+++ b/packages/SystemUI/res/values/ids.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+    <item type="id" name="translation_y_animator_tag"/>
+    <item type="id" name="translation_z_animator_tag"/>
+    <item type="id" name="scale_animator_tag"/>
+    <item type="id" name="alpha_animator_tag"/>
+    <item type="id" name="top_inset_animator_tag"/>
+    <item type="id" name="height_animator_tag"/>
+    <item type="id" name="translation_y_animator_end_value_tag"/>
+    <item type="id" name="translation_z_animator_end_value_tag"/>
+    <item type="id" name="scale_animator_end_value_tag"/>
+    <item type="id" name="alpha_animator_end_value_tag"/>
+    <item type="id" name="top_inset_animator_end_value_tag"/>
+    <item type="id" name="height_animator_end_value_tag"/>
+    <item type="id" name="translation_y_animator_start_value_tag"/>
+    <item type="id" name="translation_z_animator_start_value_tag"/>
+    <item type="id" name="scale_animator_start_value_tag"/>
+    <item type="id" name="alpha_animator_start_value_tag"/>
+    <item type="id" name="top_inset_animator_start_value_tag"/>
+    <item type="id" name="height_animator_start_value_tag"/>
+</resources>
+
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index b4a13d4..a50a0ac 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -196,6 +196,8 @@
     <string name="accessibility_search_light">Search</string>
     <!-- Content description of the camera button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_camera_button">Camera</string>
+    <!-- Content description of the phone button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_phone_button">Phone</string>
 
     <!-- Content description of the switch input method button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_ime_switch_button">Switch input method button.</string>
@@ -501,11 +503,15 @@
     <!-- QuickSettings: Brightness dialog auto brightness button [CHAR LIMIT=NONE] -->
     <string name="quick_settings_brightness_dialog_auto_brightness_label">AUTO</string>
     <!-- QuickSettings: Label for the toggle that controls whether display inversion is enabled. [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_inversion_label">Color inversion mode</string>
-    <!-- QuickSettings: Label for the toggle that controls whether display contrast enhancement is enabled. [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_contrast_label">Enhanced contrast mode</string>
+    <string name="quick_settings_inversion_label">Invert colors</string>
     <!-- QuickSettings: Label for the toggle that controls whether display color correction is enabled. [CHAR LIMIT=NONE] -->
     <string name="quick_settings_color_space_label">Color correction mode</string>
+    <!-- QuickSettings: Control panel: Label for button that navigates to settings. [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_more_settings">More settings</string>
+    <!-- QuickSettings: Tethering. [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_tethering_label">Tethering</string>
+    <!-- QuickSettings: Hotspot. [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_hotspot_label">Hotspot</string>
 
     <!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
     <string name="recents_empty_message">RECENTS</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 8ab646d..1273e74 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -69,8 +69,7 @@
     <style name="TextAppearance.StatusBar.Expanded" parent="@*android:style/TextAppearance.StatusBar" />
 
     <style name="TextAppearance.StatusBar.Expanded.Clock">
-        <item name="android:textSize">32dp</item>
-        <item name="android:fontFamily">sans-serif-light</item>
+        <item name="android:textSize">18dp</item>
         <item name="android:textStyle">normal</item>
         <item name="android:textColor">#ffffff</item>
     </style>
@@ -78,8 +77,7 @@
     <style name="TextAppearance.StatusBar.Expanded.Date">
         <item name="android:textSize">12dp</item>
         <item name="android:textStyle">normal</item>
-        <item name="android:textColor">#cccccc</item>
-        <item name="android:textAllCaps">true</item>
+        <item name="android:textColor">#afb3b6</item>
     </style>
 
     <style name="TextAppearance.StatusBar.Expanded.Network" parent="@style/TextAppearance.StatusBar.Expanded.Date">
@@ -138,6 +136,7 @@
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
         <item name="android:padding">16dp</item>
+        <item name="android:layout_alignParentBottom">true</item>
     </style>
 
     <style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer" />
@@ -169,6 +168,28 @@
         <item name="android:textSize">14dp</item>
     </style>
 
-    <style name="systemui_theme" parent="@android:style/Theme.DeviceDefault" />
+    <style name="systemui_theme" parent="@android:style/Theme.DeviceDefault">
+        <item name="android:colorPrimary">@color/primary_color</item>
+    </style>
 
+    <style name="NotificationsQuickSettings">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">match_parent</item>
+    </style>
+
+    <style name="StatusBarHeader">
+        <item name="android:layout_width">match_parent</item>
+    </style>
+
+    <style name="QSWhiteTheme" parent="@android:style/Theme.DeviceDefault">
+        <item name="android:colorControlNormal">#ffffffff</item>
+        <item name="android:colorControlActivated">#ffffffff</item>
+    </style>
+
+    <style name="QSAccentTheme" parent="@android:style/Theme.DeviceDefault">
+        <item name="android:colorControlNormal">@color/system_accent_color</item>
+        <item name="android:colorControlActivated">@color/system_accent_color</item>
+    </style>
+
+    <style name="QSBorderless" parent="@android:style/Widget.Quantum.Button.Borderless" />
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 61c268e..4d6d815c 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -29,17 +29,16 @@
 import android.view.ScaleGestureDetector;
 import android.view.ScaleGestureDetector.OnScaleGestureListener;
 import android.view.View;
-import android.view.View.OnClickListener;
 import android.view.ViewConfiguration;
 
-import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.policy.ScrollAdapter;
 
-public class ExpandHelper implements Gefingerpoken, OnClickListener {
+public class ExpandHelper implements Gefingerpoken {
     public interface Callback {
-        View getChildAtRawPosition(float x, float y);
-        View getChildAtPosition(float x, float y);
+        ExpandableView getChildAtRawPosition(float x, float y);
+        ExpandableView getChildAtPosition(float x, float y);
         boolean canChildBeExpanded(View v);
         void setUserExpandedChild(View v, boolean userExpanded);
         void setUserLockedChild(View v, boolean userLocked);
@@ -48,9 +47,7 @@
     private static final String TAG = "ExpandHelper";
     protected static final boolean DEBUG = false;
     protected static final boolean DEBUG_SCALE = false;
-    protected static final boolean DEBUG_GLOW = false;
     private static final long EXPAND_DURATION = 250;
-    private static final long GLOW_DURATION = 150;
 
     // Set to false to disable focus-based gestures (spread-finger vertical pull).
     private static final boolean USE_DRAG = true;
@@ -115,7 +112,7 @@
             float focusX = detector.getFocusX();
             float focusY = detector.getFocusY();
 
-            final View underFocus = findView(focusX, focusY);
+            final ExpandableView underFocus = findView(focusX, focusY);
             startExpanding(underFocus, STRETCH);
             return mExpanding;
         }
@@ -172,24 +169,6 @@
         mPopDuration = mContext.getResources().getInteger(R.integer.blinds_pop_duration_ms);
         mPullGestureMinXSpan = mContext.getResources().getDimension(R.dimen.pull_span_min);
 
-        AnimatorListenerAdapter glowVisibilityController = new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationStart(Animator animation) {
-                View target = (View) ((ObjectAnimator) animation).getTarget();
-                if (target.getAlpha() <= 0.0f) {
-                    target.setVisibility(View.VISIBLE);
-                }
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                View target = (View) ((ObjectAnimator) animation).getTarget();
-                if (target.getAlpha() <= 0.0f) {
-                    target.setVisibility(View.INVISIBLE);
-                }
-            }
-        };
-
         final ViewConfiguration configuration = ViewConfiguration.get(mContext);
         mTouchSlop = configuration.getScaledTouchSlop();
 
@@ -221,8 +200,8 @@
         return out;
     }
 
-    private View findView(float x, float y) {
-        View v = null;
+    private ExpandableView findView(float x, float y) {
+        ExpandableView v;
         if (mEventSource != null) {
             int[] location = new int[2];
             mEventSource.getLocationOnScreen(location);
@@ -271,15 +250,6 @@
         mScrollAdapter = adapter;
     }
 
-    private float calculateGlow(float target, float actual) {
-        // glow if overscale
-        if (DEBUG_GLOW) Log.d(TAG, "target: " + target + " actual: " + actual);
-        float stretch = Math.abs((target - actual) / mMaximumStretch);
-        float strength = 1f / (1f + (float) Math.pow(Math.E, -1 * ((8f * stretch) - 5f)));
-        if (DEBUG_GLOW) Log.d(TAG, "stretch: " + stretch + " strength: " + strength);
-        return (GLOW_BASE + strength * (1f - GLOW_BASE));
-    }
-
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         final int action = ev.getAction();
@@ -313,7 +283,7 @@
                 // detect a vertical pulling gesture with fingers somewhat separated
                 if (DEBUG_SCALE) Log.v(TAG, "got pull gesture (xspan=" + xspan + "px)");
 
-                final View underFocus = findView(x, y);
+                final ExpandableView underFocus = findView(x, y);
                 startExpanding(underFocus, PULL);
                 return true;
             }
@@ -328,7 +298,7 @@
                     if (yDiff > mTouchSlop) {
                         if (DEBUG) Log.v(TAG, "got venetian gesture (dy=" + yDiff + "px)");
                         mLastMotionY = y;
-                        final View underFocus = findView(x, y);
+                        final ExpandableView underFocus = findView(x, y);
                         if (startExpanding(underFocus, BLINDS)) {
                             mInitialTouchY = mLastMotionY;
                             mHasPopped = false;
@@ -394,7 +364,7 @@
 
                     final int x = (int) mSGD.getFocusX();
                     final int y = (int) mSGD.getFocusY();
-                    View underFocus = findView(x, y);
+                    ExpandableView underFocus = findView(x, y);
                     if (isFinished && underFocus != null && underFocus != mCurrView) {
                         finishExpanding(false); // @@@ needed?
                         startExpanding(underFocus, BLINDS);
@@ -432,7 +402,7 @@
     /**
      * @return True if the view is expandable, false otherwise.
      */
-    private boolean startExpanding(View v, int expandType) {
+    private boolean startExpanding(ExpandableView v, int expandType) {
         if (!(v instanceof ExpandableNotificationRow)) {
             return false;
         }
@@ -512,13 +482,6 @@
         mCurrView = v;
     }
 
-    @Override
-    public void onClick(View v) {
-        startExpanding(v, STRETCH);
-        finishExpanding(true);
-        clearView();
-    }
-
     /**
      * Use this to abort any pending expansions in progress.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 74483cc..4857adc 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -211,6 +211,7 @@
             if (mReceiver != null) {
                 unregisterReceiver(mReceiver);
             }
+            mBackground = null;
         }
 
         void updateSurfaceSize(SurfaceHolder surfaceHolder) {
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index d38d828..6387a92 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -322,6 +322,7 @@
         anim.addListener(new AnimatorListenerAdapter() {
             public void onAnimationEnd(Animator animator) {
                 updateAlphaFromOffset(animView, canAnimViewBeDismissed);
+                mCallback.onChildSnappedBack(animView);
             }
         });
         anim.start();
@@ -407,5 +408,7 @@
         void onChildDismissed(View v);
 
         void onDragCancelled(View v);
+
+        void onChildSnappedBack(View animView);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 103991a..217074f 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -65,6 +65,8 @@
         // the theme set there.
         setTheme(R.style.systemui_theme);
 
+        IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
+        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
         registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
@@ -80,7 +82,7 @@
                     }
                 }
             }
-        }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+        }, filter);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index ffdb620..e73e904 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -542,9 +542,8 @@
 
     /**
      * Called to let us know the screen was turned off.
-     * @param why either {@link android.view.WindowManagerPolicy#OFF_BECAUSE_OF_USER},
-     *   {@link android.view.WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT} or
-     *   {@link android.view.WindowManagerPolicy#OFF_BECAUSE_OF_PROX_SENSOR}.
+     * @param why either {@link android.view.WindowManagerPolicy#OFF_BECAUSE_OF_USER} or
+     *   {@link android.view.WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT}.
      */
     public void onScreenTurnedOff(int why) {
         synchronized (this) {
@@ -576,8 +575,6 @@
             } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT
                    || (why == WindowManagerPolicy.OFF_BECAUSE_OF_USER && !lockImmediately)) {
                 doKeyguardLaterLocked();
-            } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR) {
-                // Do not enable the keyguard if the prox sensor forced the screen off.
             } else {
                 doKeyguardLocked(null);
             }
@@ -810,7 +807,6 @@
      */
     public void setOccluded(boolean isOccluded) {
         if (DEBUG) Log.d(TAG, "setOccluded " + isOccluded);
-        mUpdateMonitor.sendKeyguardVisibilityChanged(!isOccluded);
         mHandler.removeMessages(SET_OCCLUDED);
         Message msg = mHandler.obtainMessage(SET_OCCLUDED, (isOccluded ? 1 : 0), 0);
         mHandler.sendMessage(msg);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/CircularClipper.java b/packages/SystemUI/src/com/android/systemui/qs/CircularClipper.java
new file mode 100644
index 0000000..16ee3b0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/CircularClipper.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.view.View;
+
+/** Helper for view-level circular clip animations. **/
+public class CircularClipper {
+
+    private final View mTarget;
+
+    private ValueAnimator mAnimator;
+
+    public CircularClipper(View target) {
+        mTarget = target;
+    }
+
+    public void animateCircularClip(int x, int y, boolean in, AnimatorListener listener) {
+        if (mAnimator != null) {
+            mAnimator.cancel();
+        }
+        final int w = mTarget.getWidth() - x;
+        final int h = mTarget.getHeight() - y;
+        int r = (int) Math.ceil(Math.sqrt(x * x + y * y));
+        r = (int) Math.max(r, Math.ceil(Math.sqrt(w * w + y * y)));
+        r = (int) Math.max(r, Math.ceil(Math.sqrt(w * w + h * h)));
+        r = (int) Math.max(r, Math.ceil(Math.sqrt(x * x + h * h)));
+
+        mAnimator = mTarget.createRevealAnimator(x, y, 0, r);
+        mAnimator.removeAllListeners();
+        if (listener != null) {
+            mAnimator.addListener(listener);
+        }
+        if (in) {
+            mAnimator.addListener(mVisibleOnStart);
+            mAnimator.start();
+        } else {
+            mAnimator.addListener(mGoneOnEnd);
+            mAnimator.reverse();
+        }
+    }
+
+    private final AnimatorListenerAdapter mVisibleOnStart = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationStart(Animator animation) {
+            mTarget.setVisibility(View.VISIBLE);
+        }
+    };
+
+    private final AnimatorListenerAdapter mGoneOnEnd = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mTarget.setVisibility(View.GONE);
+        };
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FilterCanvas.java b/packages/SystemUI/src/com/android/systemui/qs/FilterCanvas.java
new file mode 100644
index 0000000..05c8ee3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/FilterCanvas.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Rect;
+
+/** Canvas that forwards calls to another canvas.  Can be subclassed to transform drawing calls.
+ * Temporary solution to runtime modification of a single drawable shape into two
+ * enabled & disabled versions.  See QSImageView. **/
+public class FilterCanvas extends Canvas {
+    private final Canvas mCanvas;
+
+    public FilterCanvas(Canvas c) {
+        mCanvas = c;
+    }
+
+    @Override
+    public void drawPath(Path path, Paint paint) {
+        mCanvas.drawPath(path, paint);
+    }
+
+    @Override
+    public int getSaveCount() {
+        return mCanvas.getSaveCount();
+    }
+
+    @Override
+    public int save() {
+        return mCanvas.save();
+    }
+
+    @Override
+    public void translate(float dx, float dy) {
+        mCanvas.translate(dx, dy);
+    }
+
+    @Override
+    public boolean clipRect(int left, int top, int right, int bottom) {
+        return mCanvas.clipRect(left, top, right, bottom);
+    }
+
+    @Override
+    public boolean clipRect(Rect rect) {
+        return mCanvas.clipRect(rect);
+    }
+
+    @Override
+    public void concat(Matrix matrix) {
+        mCanvas.concat(matrix);
+    }
+
+    @Override
+    public void restoreToCount(int saveCount) {
+        mCanvas.restoreToCount(saveCount);
+    }
+
+    @Override
+    public void drawRect(Rect r, Paint paint) {
+        mCanvas.drawRect(r, paint);
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java b/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java
new file mode 100644
index 0000000..1e15b9f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.provider.Settings.Global;
+
+import com.android.systemui.statusbar.policy.Disposable;
+
+/** Helper for managing a global setting. **/
+public abstract class GlobalSetting extends ContentObserver implements Disposable {
+    private final Context mContext;
+    private final String mSettingName;
+
+    protected abstract void handleValueChanged(int value);
+
+    public GlobalSetting(Context context, Handler handler, String settingName) {
+        super(handler);
+        mContext = context;
+        mSettingName = settingName;
+        mContext.getContentResolver().registerContentObserver(
+                Global.getUriFor(mSettingName), false, this);
+    }
+
+    public int getValue() {
+        return Global.getInt(mContext.getContentResolver(), mSettingName, 0);
+    }
+
+    public void setValue(int value) {
+        Global.putInt(mContext.getContentResolver(), mSettingName, value);
+    }
+
+    @Override
+    public void dispose() {
+        mContext.getContentResolver().unregisterContentObserver(this);
+    }
+
+    @Override
+    public void onChange(boolean selfChange) {
+        handleValueChanged(getValue());
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSImageView.java b/packages/SystemUI/src/com/android/systemui/qs/QSImageView.java
new file mode 100644
index 0000000..ed67560
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSImageView.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Path;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.VectorDrawable;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+
+/** ImageView that performs runtime modification of vector drawables (using FilterCanvas). **/
+public class QSImageView extends ImageView {
+
+    private final int mOutlineWidth;
+    private final int mColorEnabled;
+    private final int mColorDisabled;
+    private FilterCanvas mFilterCanvas;
+    private Canvas mCanvas;
+    private boolean mEnabledVersion = true;
+    private boolean mFilter;
+
+    public QSImageView(Context context) {
+        this(context, null);
+    }
+
+    public QSImageView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        final Resources res = context.getResources();
+        mOutlineWidth = res.getDimensionPixelSize(R.dimen.quick_settings_tile_icon_outline);
+        mColorEnabled = res.getColor(R.color.quick_settings_tile_icon_enabled);
+        mColorDisabled = res.getColor(R.color.quick_settings_tile_icon_disabled);
+    }
+
+    public void setEnabledVersion(boolean enabledVersion) {
+        mEnabledVersion = enabledVersion;
+        invalidate();
+    }
+
+    @Override
+    public void setImageDrawable(Drawable drawable) {
+        mFilter = drawable instanceof VectorDrawable;
+        super.setImageDrawable(drawable);
+    }
+
+    @Override
+    public void setImageResource(int resId) {
+        setImageDrawable(mContext.getDrawable(resId));
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        if (mFilter) {
+            if (canvas != mCanvas) {
+                mCanvas = canvas;
+                mFilterCanvas = new QSFilterCanvas(canvas);
+            }
+            super.draw(mFilterCanvas);
+        } else {
+            super.draw(canvas);
+        }
+    }
+
+    private class QSFilterCanvas extends FilterCanvas {
+        public QSFilterCanvas(Canvas c) {
+            super(c);
+        }
+
+        @Override
+        public void drawPath(Path path, Paint paint) {
+            if (mEnabledVersion) {
+                paint.setColor(mColorEnabled);
+            } else {
+                paint.setStyle(Style.STROKE);
+                paint.setStrokeJoin(Paint.Join.ROUND);
+                paint.setColor(mColorDisabled);
+                paint.setStrokeWidth(mOutlineWidth);
+            }
+            super.drawPath(path, paint);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
new file mode 100644
index 0000000..afb5483
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.systemui.R;
+
+import java.util.ArrayList;
+
+/** View that represents the quick settings tile panel. **/
+public class QSPanel extends ViewGroup {
+    private static final float TILE_ASPECT = 1.4f;
+    private static final float LARGE_TILE_FACTOR = 1.1f;
+
+    private final Context mContext;
+    private final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
+    private final FrameLayout mDetail;
+    private final CircularClipper mClipper;
+    private final H mHandler = new H();
+
+    private int mColumns;
+    private int mCellWidth;
+    private int mCellHeight;
+    private int mLargeCellWidth;
+    private int mLargeCellHeight;
+
+    private TileRecord mDetailRecord;
+
+    public QSPanel(Context context) {
+        this(context, null);
+    }
+
+    public QSPanel(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mContext = context;
+
+        mDetail = new FrameLayout(mContext);
+        mDetail.setVisibility(GONE);
+        mDetail.setClickable(true);
+        addView(mDetail);
+        mClipper = new CircularClipper(mDetail);
+        updateResources();
+    }
+
+    public void updateResources() {
+        final int columns = Math.max(1,
+                mContext.getResources().getInteger(R.integer.quick_settings_num_columns));
+        if (mColumns != columns) {
+            mColumns = columns;
+            postInvalidate();
+        }
+    }
+
+    public void setExpanded(boolean expanded) {
+        if (!expanded) {
+            showDetail(false /*show*/, mDetailRecord);
+        }
+        for (TileRecord r : mRecords) {
+            r.tile.setShown(expanded);
+        }
+    }
+
+    private void showDetail(boolean show, TileRecord r) {
+        mHandler.obtainMessage(H.SHOW_DETAIL, show ? 1 : 0, 0, r).sendToTarget();
+    }
+
+    private void setTileVisibility(View v, boolean visible) {
+        mHandler.obtainMessage(H.SET_TILE_VISIBILITY, visible ? 1 : 0, 0, v).sendToTarget();
+    }
+
+    private void handleSetTileVisibility(View v, boolean visible) {
+        v.setVisibility(visible ? VISIBLE : GONE);
+    }
+
+    public void addTile(final QSTile<?> tile) {
+        final TileRecord r = new TileRecord();
+        r.tile = tile;
+        r.tileView = tile.createTileView(mContext);
+        r.tileView.setVisibility(View.GONE);
+        r.tile.setCallback(new QSTile.Callback() {
+            @Override
+            public void onStateChanged(QSTile.State state) {
+                setTileVisibility(r.tileView, state.visible);
+                r.tileView.onStateChanged(state);
+            }
+            @Override
+            public void onShowDetail(boolean show) {
+                QSPanel.this.showDetail(show, r);
+            }
+        });
+        final View.OnClickListener click = new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                r.tile.click();
+            }
+        };
+        final View.OnClickListener clickSecondary = new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                r.tile.secondaryClick();
+            }
+        };
+        r.tileView.init(click, clickSecondary);
+        mRecords.add(r);
+
+        addView(r.tileView);
+    }
+
+    private void handleShowDetail(TileRecord r, boolean show) {
+        AnimatorListener listener = null;
+        if (show) {
+            if (mDetailRecord != null) return;
+            final View detail = r.tile.createDetailView(mContext, mDetail);
+            if (detail == null) return;
+            mDetailRecord = r;
+            mDetail.removeAllViews();
+            mDetail.bringToFront();
+            mDetail.addView(detail);
+        } else {
+            if (mDetailRecord == null) return;
+            listener = mTeardownDetailWhenDone;
+        }
+        int x = r.tileView.getLeft() + r.tileView.getWidth() / 2;
+        int y = r.tileView.getTop() + r.tileView.getHeight() / 2;
+        mClipper.animateCircularClip(x, y, show, listener);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int width = MeasureSpec.getSize(widthMeasureSpec);
+        mCellWidth = width / mColumns;
+        mCellHeight = (int)(mCellWidth / TILE_ASPECT);
+        mLargeCellWidth = (int)(mCellWidth * LARGE_TILE_FACTOR);
+        mLargeCellHeight = (int)(mCellHeight * LARGE_TILE_FACTOR);
+        int r = 0;
+        int c = 0;
+        int rows = 0;
+        for (TileRecord record : mRecords) {
+            if (record.tileView.getVisibility() == GONE) continue;
+            record.row = r;
+            record.col = c;
+            rows = r + 1;
+            c++;
+            if (c == mColumns /*end of normal column*/ || r == 0 && c == 2 /*end of 1st column*/) {
+                c = 0;
+                r++;
+            }
+        }
+
+        for (TileRecord record : mRecords) {
+            if (record.tileView.getVisibility() == GONE) continue;
+            record.tileView.setDual(record.row == 0);
+            final int cw = record.row == 0 ? mLargeCellWidth : mCellWidth;
+            final int ch = record.row == 0 ? mLargeCellHeight : mCellHeight;
+            record.tileView.measure(exactly(cw), exactly(ch));
+        }
+        final int actualHeight = rows == 0 ? 0 : getRowTop(rows);
+        mDetail.measure(exactly(width), exactly(actualHeight));
+        setMeasuredDimension(width, actualHeight);
+    }
+
+    private static int exactly(int size) {
+        return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        final int w = mCellWidth * mColumns;
+        for (TileRecord record : mRecords) {
+            if (record.tileView.getVisibility() == GONE) continue;
+            final int cols = getColumnCount(record.row);
+            final int cw = record.row == 0 ? mLargeCellWidth : mCellWidth;
+            final int extra = (w - cw * cols) / (cols + 1);
+            final int left = record.col * cw + (record.col + 1) * extra;
+            final int top = getRowTop(record.row);
+            record.tileView.layout(left, top,
+                    left + record.tileView.getMeasuredWidth(),
+                    top + record.tileView.getMeasuredHeight());
+        }
+        mDetail.layout(0, 0, mDetail.getMeasuredWidth(), mDetail.getMeasuredHeight());
+    }
+
+    private int getRowTop(int row) {
+        if (row <= 0) return 0;
+        return mLargeCellHeight + (row - 1) * mCellHeight;
+    }
+
+    private int getColumnCount(int row) {
+        int cols = 0;
+        for (TileRecord record : mRecords) {
+            if (record.tileView.getVisibility() == GONE) continue;
+            if (record.row == row) cols++;
+        }
+        return cols;
+    }
+
+    private class H extends Handler {
+        private static final int SHOW_DETAIL = 1;
+        private static final int SET_TILE_VISIBILITY = 2;
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == SHOW_DETAIL) {
+                handleShowDetail((TileRecord)msg.obj, msg.arg1 != 0);
+            } else if (msg.what == SET_TILE_VISIBILITY) {
+                handleSetTileVisibility((View)msg.obj, msg.arg1 != 0);
+            }
+        }
+    }
+
+    private static final class TileRecord {
+        QSTile<?> tile;
+        QSTileView tileView;
+        int row;
+        int col;
+    }
+
+    private final AnimatorListenerAdapter mTeardownDetailWhenDone = new AnimatorListenerAdapter() {
+        public void onAnimationEnd(Animator animation) {
+            mDetail.removeAllViews();
+            mDetailRecord = null;
+        };
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
new file mode 100644
index 0000000..05f308d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.VectorDrawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.qs.QSTile.State;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.Disposable;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.TetheringController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Base quick-settings tile, extend this to create a new tile.
+ *
+ * State management done on a looper provided by the host.  Tiles should update state in
+ * handleUpdateState.  Callbacks affecting state should use refreshState to trigger another
+ * state update pass on tile looper.
+ */
+public abstract class QSTile<TState extends State> implements Disposable {
+    private final String TAG = "QSTile." + getClass().getSimpleName();
+
+    protected final Host mHost;
+    protected final Context mContext;
+    protected final H mHandler;
+    protected final Handler mUiHandler = new Handler(Looper.getMainLooper());
+
+    private Callback mCallback;
+    protected final TState mState = newTileState();
+    private final TState mTmpState = newTileState();
+
+    abstract protected TState newTileState();
+    abstract protected void handleClick();
+    abstract protected void handleUpdateState(TState state, Object arg);
+
+    protected QSTile(Host host) {
+        mHost = host;
+        mContext = host.getContext();
+        mHandler = new H(host.getLooper());
+    }
+
+    public Host getHost() {
+        return mHost;
+    }
+
+    public QSTileView createTileView(Context context) {
+        return new QSTileView(context);
+    }
+
+    public View createDetailView(Context context, ViewGroup root) {
+        return null; // optional
+    }
+
+    // safe to call from any thread
+
+    public void setCallback(Callback callback) {
+        mHandler.obtainMessage(H.SET_CALLBACK, callback).sendToTarget();
+    }
+
+    public void click() {
+        mHandler.sendEmptyMessage(H.CLICK);
+    }
+
+    public void secondaryClick() {
+        mHandler.sendEmptyMessage(H.SECONDARY_CLICK);
+    }
+
+    public void showDetail(boolean show) {
+        mHandler.obtainMessage(H.SHOW_DETAIL, show ? 1 : 0, 0).sendToTarget();
+    }
+
+    protected final void refreshState() {
+        refreshState(null);
+    }
+
+    protected final void refreshState(Object arg) {
+        mHandler.obtainMessage(H.REFRESH_STATE, arg).sendToTarget();
+    }
+
+    public void userSwitch(int newUserId) {
+        mHandler.obtainMessage(H.USER_SWITCH, newUserId).sendToTarget();
+    }
+
+    public void setShown(boolean shown) {
+        mHandler.obtainMessage(H.SHOWN, shown ? 1 : 0, 0).sendToTarget();
+    }
+
+    // call only on tile worker looper
+
+    private void handleSetCallback(Callback callback) {
+        mCallback = callback;
+        handleRefreshState(null);
+    }
+
+    protected void handleSecondaryClick() {
+        // optional
+    }
+
+    protected void handleShown(boolean shown) {
+        // optional, discouraged
+    }
+
+    protected void handleRefreshState(Object arg) {
+        handleUpdateState(mTmpState, arg);
+        final boolean changed = mTmpState.copyTo(mState);
+        if (changed) {
+            handleStateChanged();
+        }
+    }
+
+    private void handleStateChanged() {
+        if (mCallback != null) {
+            mCallback.onStateChanged(mState);
+        }
+    }
+
+    private void handleShowDetail(boolean show) {
+        if (mCallback != null) {
+            mCallback.onShowDetail(show);
+        }
+    }
+
+    protected void handleUserSwitch(int newUserId) {
+        handleRefreshState(null);
+    }
+
+    protected final class H extends Handler {
+        private static final int SET_CALLBACK = 1;
+        private static final int CLICK = 2;
+        private static final int SECONDARY_CLICK = 3;
+        private static final int REFRESH_STATE = 4;
+        private static final int SHOW_DETAIL = 5;
+        private static final int USER_SWITCH = 6;
+        private static final int SHOWN = 7;
+
+        private H(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            String name = null;
+            try {
+                if (msg.what == SET_CALLBACK) {
+                    name = "handleSetCallback";
+                    handleSetCallback((QSTile.Callback)msg.obj);
+                } else if (msg.what == CLICK) {
+                    name = "handleClick";
+                    handleClick();
+                } else if (msg.what == SECONDARY_CLICK) {
+                    name = "handleSecondaryClick";
+                    handleSecondaryClick();
+                } else if (msg.what == REFRESH_STATE) {
+                    name = "handleRefreshState";
+                    handleRefreshState(msg.obj);
+                } else if (msg.what == SHOW_DETAIL) {
+                    name = "handleShowDetail";
+                    handleShowDetail(msg.arg1 != 0);
+                } else if (msg.what == USER_SWITCH) {
+                    name = "handleUserSwitch";
+                    handleUserSwitch(msg.arg1);
+                } else if (msg.what == SHOWN) {
+                    name = "handleShown";
+                    handleShown(msg.arg1 != 0);
+                }
+            } catch (Throwable t) {
+                final String error = "Error in " + name;
+                Log.w(TAG, error, t);
+                mHost.warn(error, t);
+            }
+        }
+    }
+
+    public interface Callback {
+        void onStateChanged(State state);
+        void onShowDetail(boolean show);
+    }
+
+    public interface Host {
+        void startSettingsActivity(Intent intent);
+        void warn(String message, Throwable t);
+        void collapsePanels();
+        Looper getLooper();
+        Context getContext();
+        VectorDrawable getVectorDrawable(int resId);
+        BluetoothController getBluetoothController();
+        LocationController getLocationController();
+        RotationLockController getRotationLockController();
+        List<QSTile<?>> getTiles();
+        NetworkController getNetworkController();
+        ZenModeController getZenModeController();
+        TetheringController getTetheringController();
+        CastController getCastController();
+    }
+
+    public static class State {
+        public boolean visible;
+        public int iconId;
+        public Drawable icon;
+        public String label;
+        public String contentDescription;
+
+        public boolean copyTo(State other) {
+            if (other == null) throw new IllegalArgumentException();
+            if (!other.getClass().equals(getClass())) throw new IllegalArgumentException();
+            final boolean changed = other.visible != visible
+                    || other.iconId != iconId
+                    || !Objects.equals(other.icon, icon)
+                    || !Objects.equals(other.label, label)
+                    || !Objects.equals(other.contentDescription, contentDescription);
+            other.visible = visible;
+            other.iconId = iconId;
+            other.icon = icon;
+            other.label = label;
+            other.contentDescription = contentDescription;
+            return changed;
+        }
+
+        @Override
+        public String toString() {
+            return toStringBuilder().toString();
+        }
+
+        protected StringBuilder toStringBuilder() {
+            final StringBuilder sb = new StringBuilder(  getClass().getSimpleName()).append('[');
+            sb.append("visible=").append(visible);
+            sb.append(",iconId=").append(iconId);
+            sb.append(",icon=").append(icon);
+            sb.append(",label=").append(label);
+            sb.append(",contentDescription=").append(contentDescription);
+            return sb.append(']');
+        }
+    }
+
+    public static class BooleanState extends State {
+        public boolean value;
+
+        @Override
+        public boolean copyTo(State other) {
+            final BooleanState o = (BooleanState) other;
+            final boolean changed = super.copyTo(other) || o.value != value;
+            o.value = value;
+            return changed;
+        }
+
+        @Override
+        protected StringBuilder toStringBuilder() {
+            final StringBuilder rt = super.toStringBuilder();
+            rt.insert(rt.length() - 1, ",value=" + value);
+            return rt;
+        }
+    }
+
+    public static final class SignalState extends State {
+        public boolean enabled;
+        public boolean connected;
+        public boolean activityIn;
+        public boolean activityOut;
+        public int overlayIconId;
+
+        @Override
+        public boolean copyTo(State other) {
+            final SignalState o = (SignalState) other;
+            final boolean changed = o.enabled != enabled
+                    || o.connected != connected || o.activityIn != activityIn
+                    || o.activityOut != activityOut
+                    || o.overlayIconId != overlayIconId;
+            o.enabled = enabled;
+            o.connected = connected;
+            o.activityIn = activityIn;
+            o.activityOut = activityOut;
+            o.overlayIconId = overlayIconId;
+            return super.copyTo(other) || changed;
+        }
+
+        @Override
+        protected StringBuilder toStringBuilder() {
+            final StringBuilder rt = super.toStringBuilder();
+            rt.insert(rt.length() - 1, ",enabled=" + enabled);
+            rt.insert(rt.length() - 1, ",connected=" + connected);
+            rt.insert(rt.length() - 1, ",activityIn=" + activityIn);
+            rt.insert(rt.length() - 1, ",activityOut=" + activityOut);
+            rt.insert(rt.length() - 1, ",overlayIconId=" + overlayIconId);
+            return rt;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
new file mode 100644
index 0000000..17a95fb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.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 com.android.systemui.qs;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView.ScaleType;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile.State;
+
+/** View that represents a standard quick settings tile. **/
+public class QSTileView extends ViewGroup {
+    private static final Typeface CONDENSED = Typeface.create("sans-serif-condensed",
+            Typeface.NORMAL);
+    private static final int VERTICAL_PADDING_FACTOR = 8;  // internal padding 1/8 the cell height
+
+    protected final Context mContext;
+    private final View mIcon;
+    private final View mDivider;
+    private final TextView mLabel;
+    private final H mHandler = new H();
+
+    private boolean mDual;
+    private OnClickListener mClickPrimary;
+    private OnClickListener mClickSecondary;
+
+    public QSTileView(Context context) {
+        super(context);
+
+        mContext = context;
+        final Resources res = context.getResources();
+        mLabel = new TextView(mContext);
+        mLabel.setId(android.R.id.title);
+        mLabel.setTextColor(res.getColor(R.color.quick_settings_tile_text));
+        mLabel.setGravity(Gravity.CENTER);
+        mLabel.setTypeface(CONDENSED);
+        mLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+                res.getDimensionPixelSize(R.dimen.quick_settings_tile_text_size));
+        addView(mLabel);
+        setClipChildren(false);
+
+        mIcon = createIcon();
+        addView(mIcon);
+
+        mDivider = new View(mContext);
+        mDivider.setBackgroundColor(res.getColor(R.color.quick_settings_tile_divider));
+        final int dh = res.getDimensionPixelSize(R.dimen.quick_settings_tile_divider_height);
+        mDivider.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, dh));
+        addView(mDivider);
+
+        setClickable(true);
+        setBackground(getSelectableBackground());
+    }
+
+    public void setDual(boolean dual) {
+        mDual = dual;
+        if (mDual) {
+            setOnClickListener(mClickPrimary);
+            mLabel.setClickable(true);
+            mLabel.setOnClickListener(mClickSecondary);
+        } else {
+            mLabel.setClickable(false);
+            setOnClickListener(mClickPrimary);
+        }
+        mDivider.setVisibility(dual ? VISIBLE : GONE);
+        postInvalidate();
+    }
+
+    public void init(OnClickListener clickPrimary, OnClickListener clickSecondary) {
+        mClickPrimary = clickPrimary;
+        mClickSecondary = clickSecondary;
+    }
+
+    protected View createIcon() {
+        QSImageView icon = new QSImageView(mContext);
+        icon.setId(android.R.id.icon);
+        icon.setScaleType(ScaleType.CENTER_INSIDE);
+        return icon;
+    }
+
+    private Drawable getSelectableBackground() {
+        final int[] attrs = new int[] { android.R.attr.selectableItemBackground};
+        final TypedArray ta = mContext.obtainStyledAttributes(attrs);
+        final Drawable d = ta.getDrawable(0);
+        ta.recycle();
+        return d;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int w = MeasureSpec.getSize(widthMeasureSpec);
+        final int h = MeasureSpec.getSize(heightMeasureSpec);
+        final int p = h / VERTICAL_PADDING_FACTOR;
+        final int iconSpec = exactly((int)mLabel.getTextSize() * 2);
+        mIcon.measure(iconSpec, iconSpec);
+        mLabel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(h, MeasureSpec.AT_MOST));
+        mLabel.measure(widthMeasureSpec, exactly(mLabel.getMeasuredHeight() + p * 2));
+        if (mDual) {
+            mDivider.measure(widthMeasureSpec, exactly(mDivider.getLayoutParams().height));
+        }
+        setMeasuredDimension(w, h);
+    }
+
+    private static int exactly(int size) {
+        return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        final int w = getMeasuredWidth();
+        final int h = getMeasuredHeight();
+        final int p = h / VERTICAL_PADDING_FACTOR;
+        final int contentHeight = p + mIcon.getMeasuredHeight() + mLabel.getMeasuredHeight()
+                + (mDual ? (p + mDivider.getMeasuredHeight()) : 0);
+
+        int top = (h - contentHeight) / 2 + p;
+        final int iconLeft = (w - mIcon.getMeasuredWidth()) / 2;
+        layout(mIcon, iconLeft, top);
+        top = mIcon.getBottom();
+        if (mDual) {
+            top += p;
+            layout(mDivider, 0, top);
+            top = mDivider.getBottom();
+        }
+        layout(mLabel, 0, top);
+    }
+
+    private static void layout(View child, int left, int top) {
+        child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
+    }
+
+    protected void handleStateChanged(QSTile.State state) {
+        if (mIcon instanceof QSImageView) {
+            QSImageView qsiv = (QSImageView) mIcon;
+            if (state.icon != null) {
+                qsiv.setImageDrawable(state.icon);
+            } else if (state.iconId > 0) {
+                qsiv.setImageResource(state.iconId);
+            }
+            if (state.icon != null && state instanceof QSTile.BooleanState) {
+                qsiv.setEnabledVersion(((QSTile.BooleanState)state).value);
+            }
+        }
+        mLabel.setText(state.label);
+        setContentDescription(state.contentDescription);
+    }
+
+    public void onStateChanged(QSTile.State state) {
+        mHandler.obtainMessage(H.STATE_CHANGED, state).sendToTarget();
+    }
+
+    private class H extends Handler {
+        private static final int STATE_CHANGED = 1;
+        public H() {
+            super(Looper.getMainLooper());
+        }
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == STATE_CHANGED) {
+                handleStateChanged((State) msg.obj);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
new file mode 100644
index 0000000..4debaa9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.provider.Settings.Secure;
+
+import com.android.systemui.statusbar.policy.Disposable;
+
+/** Helper for managing a secure setting. **/
+public abstract class SecureSetting extends ContentObserver implements Disposable {
+    private final Context mContext;
+    private final String mSettingName;
+
+    protected abstract void handleValueChanged(int value);
+
+    public SecureSetting(Context context, Handler handler, String settingName) {
+        super(handler);
+        mContext = context;
+        mSettingName = settingName;
+        rebindForCurrentUser();
+    }
+
+    public void rebindForCurrentUser() {
+        mContext.getContentResolver().registerContentObserver(
+                Secure.getUriFor(mSettingName), false, this);
+    }
+
+    public int getValue() {
+        return Secure.getInt(mContext.getContentResolver(), mSettingName, 0);
+    }
+
+    public void setValue(int value) {
+        Secure.putInt(mContext.getContentResolver(), mSettingName, value);
+    }
+
+    @Override
+    public void dispose() {
+        mContext.getContentResolver().unregisterContentObserver(this);
+    }
+
+    @Override
+    public void onChange(boolean selfChange) {
+        handleValueChanged(getValue());
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
new file mode 100644
index 0000000..7b6c544
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile.SignalState;
+
+/** View that represents a custom quick settings tile for displaying signal info (wifi/cell). **/
+public final class SignalTileView extends QSTileView {
+    private static final long DEFAULT_DURATION = new ValueAnimator().getDuration();
+    private static final long SHORT_DURATION = DEFAULT_DURATION / 3;
+
+    private FrameLayout mIconFrame;
+    private ImageView mSignal;
+    private ImageView mOverlay;
+    private ImageView mIn;
+    private ImageView mOut;
+
+    public SignalTileView(Context context) {
+        super(context);
+
+        mIn = new ImageView(context);
+        mIn.setImageResource(R.drawable.ic_qs_signal_in);
+        addView(mIn);
+
+        mOut = new ImageView(context);
+        mOut.setImageResource(R.drawable.ic_qs_signal_out);
+        addView(mOut);
+    }
+
+    @Override
+    protected View createIcon() {
+        mIconFrame = new FrameLayout(mContext);
+        mSignal = new ImageView(mContext);
+        mIconFrame.addView(mSignal);
+        mOverlay = new ImageView(mContext);
+        mIconFrame.addView(mOverlay);
+        return mIconFrame;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        int hs = MeasureSpec.makeMeasureSpec(mIconFrame.getMeasuredHeight(), MeasureSpec.EXACTLY);
+        int ws = MeasureSpec.makeMeasureSpec(mIconFrame.getMeasuredHeight(), MeasureSpec.AT_MOST);
+        mIn.measure(ws, hs);
+        mOut.measure(ws, hs);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        layoutIndicator(mIn);
+        layoutIndicator(mOut);
+    }
+
+    private void layoutIndicator(View indicator) {
+        indicator.layout(
+                mIconFrame.getRight(),
+                mIconFrame.getBottom() - indicator.getMeasuredHeight(),
+                mIconFrame.getRight() + indicator.getMeasuredWidth(),
+                mIconFrame.getBottom());
+    }
+
+    @Override
+    protected void handleStateChanged(QSTile.State state) {
+        super.handleStateChanged(state);
+        final SignalState s = (SignalState) state;
+        mSignal.setImageDrawable(null);  // force refresh
+        mSignal.setImageResource(s.iconId);
+        if (s.overlayIconId > 0) {
+            mOverlay.setVisibility(VISIBLE);
+            mOverlay.setImageDrawable(null);  // force refresh
+            mOverlay.setImageResource(s.overlayIconId);
+        } else {
+            mOverlay.setVisibility(GONE);
+        }
+        setVisibility(mIn, s.activityIn);
+        setVisibility(mOut, s.activityOut);
+    }
+
+    private void setVisibility(View view, boolean visible) {
+        final float newAlpha = visible ? 1 : 0;
+        if (view.getAlpha() != newAlpha) {
+            view.animate()
+                .setDuration(visible ? SHORT_DURATION : DEFAULT_DURATION)
+                .alpha(newAlpha)
+                .withLayer()
+                .start();
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
new file mode 100644
index 0000000..5fe8422
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.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.systemui.qs.tiles;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.provider.Settings.Global;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.GlobalSetting;
+import com.android.systemui.qs.QSTile;
+
+/** Quick settings tile: Airplane mode **/
+public class AirplaneModeTile extends QSTile<QSTile.BooleanState> {
+    private final GlobalSetting mSetting;
+
+    public AirplaneModeTile(Host host) {
+        super(host);
+
+        mSetting = new GlobalSetting(mContext, mHandler, Global.AIRPLANE_MODE_ON) {
+            @Override
+            protected void handleValueChanged(int value) {
+                handleRefreshState(value);
+            }
+        };
+
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        mContext.registerReceiver(mReceiver, filter);
+        refreshState();
+    }
+
+    @Override
+    protected BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    public void handleClick() {
+        setEnabled(!mState.value);
+    }
+
+    private void setEnabled(boolean enabled) {
+        mSetting.setValue(enabled ? 1 : 0);
+        final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        intent.putExtra("state", enabled);
+        mContext.sendBroadcast(intent);
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        final int value = arg instanceof Integer ? (Integer)arg : mSetting.getValue();
+        final boolean airplaneMode = value != 0;
+        state.value = airplaneMode;
+        state.visible = true;
+        state.label = mContext.getString(R.string.quick_settings_airplane_mode_label);
+        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_airplane);
+        if (airplaneMode) {
+            state.iconId =  R.drawable.ic_qs_airplane_on;
+            state.contentDescription =  mContext.getString(
+                    R.string.accessibility_quick_settings_airplane,
+                    mContext.getString(R.string.accessibility_desc_on));
+        } else {
+            state.iconId = R.drawable.ic_qs_airplane_off;
+            state.contentDescription =  mContext.getString(
+                    R.string.accessibility_quick_settings_airplane,
+                    mContext.getString(R.string.accessibility_desc_off));
+        }
+    }
+
+    public void dispose() {
+        mSetting.dispose();
+        mContext.unregisterReceiver(mReceiver);
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(intent.getAction())) {
+                refreshState();
+            }
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
new file mode 100644
index 0000000..60a6047
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
+import android.content.Intent;
+import android.provider.Settings;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.BluetoothController;
+
+/** Quick settings tile: Bluetooth **/
+public class BluetoothTile extends QSTile<QSTile.BooleanState>  {
+    private static final Intent BLUETOOTH_SETTINGS = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
+
+    private final BluetoothController mController;
+
+    public BluetoothTile(Host host) {
+        super(host);
+        mController = host.getBluetoothController();
+        mController.addStateChangedCallback(mCallback);
+    }
+
+    @Override
+    protected BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    public void dispose() {
+        mController.removeStateChangedCallback(mCallback);
+    }
+
+    @Override
+    protected void handleClick() {
+        final boolean isEnabled = (Boolean)mState.value;
+        mController.setBluetoothEnabled(!isEnabled);
+    }
+
+    @Override
+    protected void handleSecondaryClick() {
+        mHost.startSettingsActivity(BLUETOOTH_SETTINGS);
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        final boolean supported = mController.isBluetoothSupported();
+        final boolean enabled = mController.isBluetoothEnabled();
+        final boolean connected = mController.isBluetoothConnected();
+        state.visible = supported;
+        state.value = enabled;
+        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_bluetooth);
+        final String stateContentDescription;
+        if (enabled) {
+            if (connected) {
+                state.iconId = R.drawable.ic_qs_bluetooth_on;
+                stateContentDescription = mContext.getString(R.string.accessibility_desc_connected);
+            } else {
+                state.iconId = R.drawable.ic_qs_bluetooth_not_connected;
+                stateContentDescription = mContext.getString(R.string.accessibility_desc_on);
+            }
+            state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
+        } else {
+            state.iconId = R.drawable.ic_qs_bluetooth_off;
+            state.label = mContext.getString(R.string.quick_settings_bluetooth_off_label);
+            stateContentDescription = mContext.getString(R.string.accessibility_desc_off);
+        }
+        state.contentDescription = mContext.getString(
+                R.string.accessibility_quick_settings_bluetooth, stateContentDescription);
+    }
+
+    private final BluetoothStateChangeCallback mCallback = new BluetoothStateChangeCallback() {
+        @Override
+        public void onBluetoothStateChange(boolean on) {
+            refreshState();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
new file mode 100644
index 0000000..0e9b9a7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.app.ActivityManagerNative;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.os.RemoteException;
+import android.provider.Settings.Global;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.GlobalSetting;
+import com.android.systemui.qs.QSTile;
+
+/** Quick settings tile: Bug report **/
+public class BugreportTile extends QSTile<QSTile.State> {
+
+    private final GlobalSetting mSetting;
+
+    public BugreportTile(Host host) {
+        super(host);
+        mSetting = new GlobalSetting(mContext, mHandler, Global.BUGREPORT_IN_POWER_MENU) {
+            @Override
+            protected void handleValueChanged(int value) {
+                handleRefreshState(null);
+            }
+        };
+    }
+
+    @Override
+    protected State newTileState() {
+        return new State();
+    }
+
+    @Override
+    public void dispose() {
+        mSetting.dispose();
+    }
+
+    @Override
+    protected void handleClick() {
+        mHost.collapsePanels();
+        mUiHandler.post(mShowDialog);
+    }
+
+    @Override
+    protected void handleUpdateState(State state, Object pushArg) {
+        state.visible = mSetting.getValue() != 0;
+        state.iconId = com.android.internal.R.drawable.stat_sys_adb;
+        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_bugreport);
+        state.label = mContext.getString(com.android.internal.R.string.bugreport_title);
+    }
+
+    private final Runnable mShowDialog = new Runnable() {
+        @Override
+        public void run() {
+            final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+            builder.setPositiveButton(com.android.internal.R.string.report, new OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    if (which == DialogInterface.BUTTON_POSITIVE) {
+                        // 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);
+                    }
+                }
+            });
+            builder.setMessage(com.android.internal.R.string.bugreport_message);
+            builder.setTitle(com.android.internal.R.string.bugreport_title);
+            builder.setCancelable(true);
+            final Dialog dialog = builder.create();
+            dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+            try {
+                WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
+            } catch (RemoteException e) {
+            }
+            dialog.show();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
new file mode 100644
index 0000000..a3eaa2c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.app.Dialog;
+import android.content.Intent;
+import android.media.MediaRouter;
+import android.provider.Settings;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.internal.app.MediaRouteDialogPresenter;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.CastController;
+
+/** Quick settings tile: Cast **/
+public class CastTile extends QSTile<QSTile.BooleanState> {
+    private static final Intent WIFI_DISPLAY_SETTINGS =
+            new Intent(Settings.ACTION_WIFI_DISPLAY_SETTINGS);
+
+    private final CastController mController;
+
+    private boolean mShown;
+
+    public CastTile(Host host) {
+        super(host);
+        mController = host.getCastController();
+        if (mController != null) {
+            mController.addCallback(mCallback);
+        }
+    }
+
+    @Override
+    protected BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    public void dispose() {
+        if (mController == null) return;
+        mController.removeCallback(mCallback);
+    }
+
+    @Override
+    protected void handleUserSwitch(int newUserId) {
+        super.handleUserSwitch(newUserId);
+        if (mController == null) return;
+        mController.setCurrentUserId(newUserId);
+    }
+
+    @Override
+    protected void handleShown(boolean shown) {
+        if (mShown == shown) return;
+        if (mController == null) return;
+        mShown = shown;
+        mController.setDiscovering(mShown);
+    }
+
+    @Override
+    protected void handleClick() {
+        mHost.collapsePanels();
+        mUiHandler.post(mShowDialog);
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        state.visible = true;
+        state.label = mContext
+                .getString(R.string.quick_settings_remote_display_no_connection_label);
+        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_cast);
+        if (arg instanceof CallbackInfo) {
+            final CallbackInfo cb = (CallbackInfo) arg;
+            if (cb.connectedRouteName != null) {
+                state.value = !cb.connecting;
+            }
+        }
+    }
+
+    private static class CallbackInfo {
+        boolean enabled;
+        boolean connecting;
+        String connectedRouteName;
+    }
+
+    private final CastController.Callback mCallback = new CastController.Callback() {
+        @Override
+        public void onStateChanged(boolean enabled, boolean connecting,
+                String connectedRouteName) {
+            final CallbackInfo info = new CallbackInfo();  // TODO pool
+            info.enabled = enabled;
+            info.connecting = connecting;
+            info.connectedRouteName = connectedRouteName;
+            refreshState(info);
+        }
+    };
+
+    private final Runnable mShowDialog = new Runnable() {
+        private Dialog mDialog;
+        @Override
+        public void run() {
+            mDialog = MediaRouteDialogPresenter.createDialog(mContext,
+                    MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
+                    new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    mDialog.dismiss();
+                    mHost.startSettingsActivity(WIFI_DISPLAY_SETTINGS);
+                }
+            });
+            mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
+            mDialog.show();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
new file mode 100644
index 0000000..86a4e79
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.QSTileView;
+import com.android.systemui.qs.SignalTileView;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
+
+/** Quick settings tile: Cellular **/
+public class CellularTile extends QSTile<QSTile.SignalState> {
+    private static final Intent CELLULAR_SETTINGS = new Intent().setComponent(new ComponentName(
+            "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity"));
+
+    private final NetworkController mController;
+
+    public CellularTile(Host host) {
+        super(host);
+        mController = host.getNetworkController();
+        mController.addNetworkSignalChangedCallback(mCallback);
+    }
+
+    @Override
+    protected SignalState newTileState() {
+        return new SignalState();
+    }
+
+    @Override
+    public void dispose() {
+        mController.removeNetworkSignalChangedCallback(mCallback);
+    }
+
+    @Override
+    public QSTileView createTileView(Context context) {
+        return new SignalTileView(context);
+    }
+
+    @Override
+    protected void handleClick() {
+        mHost.startSettingsActivity(CELLULAR_SETTINGS);
+    }
+
+    @Override
+    protected void handleUpdateState(SignalState state, Object arg) {
+        state.visible = mController.hasMobileDataFeature();
+        if (!state.visible) return;
+        final CallbackInfo cb = (CallbackInfo) arg;
+        if (cb == null) return;
+
+        final Resources r = mContext.getResources();
+        state.iconId = cb.enabled && (cb.mobileSignalIconId > 0)
+                ? cb.mobileSignalIconId
+                : R.drawable.ic_qs_signal_no_signal;
+        state.overlayIconId = cb.enabled && (cb.dataTypeIconId > 0) && !cb.wifiEnabled
+                ? cb.dataTypeIconId
+                : 0;
+        state.activityIn = cb.enabled && cb.activityIn;
+        state.activityOut = cb.enabled && cb.activityOut;
+
+        state.label = cb.enabled
+                ? removeTrailingPeriod(cb.enabledDesc)
+                : r.getString(R.string.quick_settings_rssi_emergency_only);
+
+        final String signalContentDesc = cb.enabled && (cb.mobileSignalIconId > 0)
+                ? cb.signalContentDescription
+                : r.getString(R.string.accessibility_no_signal);
+        final String dataContentDesc = cb.enabled && (cb.dataTypeIconId > 0) && !cb.wifiEnabled
+                ? cb.dataContentDescription
+                : r.getString(R.string.accessibility_no_data);
+        state.contentDescription = r.getString(
+                R.string.accessibility_quick_settings_mobile,
+                signalContentDesc, dataContentDesc,
+                state.label);
+    }
+
+    // Remove the period from the network name
+    public static String removeTrailingPeriod(String string) {
+        if (string == null) return null;
+        final int length = string.length();
+        if (string.endsWith(".")) {
+            return string.substring(0, length - 1);
+        }
+        return string;
+    }
+
+    private static final class CallbackInfo {
+        boolean enabled;
+        boolean wifiEnabled;
+        int mobileSignalIconId;
+        String signalContentDescription;
+        int dataTypeIconId;
+        String dataContentDescription;
+        boolean activityIn;
+        boolean activityOut;
+        String enabledDesc;
+    }
+
+    private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() {
+        private boolean mWifiEnabled;
+
+        @Override
+        public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
+                boolean activityIn, boolean activityOut,
+                String wifiSignalContentDescriptionId, String description) {
+            mWifiEnabled = enabled;
+        }
+
+        @Override
+        public void onMobileDataSignalChanged(boolean enabled,
+                int mobileSignalIconId,
+                String mobileSignalContentDescriptionId, int dataTypeIconId,
+                boolean activityIn, boolean activityOut,
+                String dataTypeContentDescriptionId, String description) {
+            final CallbackInfo info = new CallbackInfo();  // TODO pool?
+            info.enabled = enabled;
+            info.wifiEnabled = mWifiEnabled;
+            info.mobileSignalIconId = mobileSignalIconId;
+            info.signalContentDescription = mobileSignalContentDescriptionId;
+            info.dataTypeIconId = dataTypeIconId;
+            info.dataContentDescription = dataTypeContentDescriptionId;
+            info.activityIn = activityIn;
+            info.activityOut = activityOut;
+            info.enabledDesc = description;
+            refreshState(info);
+        }
+
+        @Override
+        public void onAirplaneModeChanged(boolean enabled) {
+            // noop
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
new file mode 100644
index 0000000..66740af
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.provider.Settings.Secure;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.SecureSetting;
+
+/** Quick settings tile: Invert colors **/
+public class ColorInversionTile extends QSTile<QSTile.BooleanState> {
+
+    private final SecureSetting mSetting;
+
+    private boolean mVisible;
+
+    public ColorInversionTile(Host host) {
+        super(host);
+
+        mSetting = new SecureSetting(mContext, mHandler,
+                Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED) {
+            @Override
+            protected void handleValueChanged(int value) {
+                handleRefreshState(value);
+            }
+        };
+
+        refreshState();
+    }
+
+    @Override
+    protected BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    public void dispose() {
+        mSetting.dispose();
+    }
+
+    @Override
+    protected void handleUserSwitch(int newUserId) {
+        mSetting.rebindForCurrentUser();
+    }
+
+    @Override
+    protected void handleClick() {
+        mSetting.setValue(mState.value ? 0 : 1);
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue();
+        final boolean enabled = value != 0;
+        if (enabled) {
+            mVisible = true;
+        }
+        state.visible = mVisible;
+        state.value = enabled;
+        state.label = mContext.getString(R.string.quick_settings_inversion_label);
+        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_invert_colors);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
new file mode 100644
index 0000000..1a67afc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.Intent;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.TetheringController;
+
+/** Quick settings tile: Hotspot **/
+public class HotspotTile extends QSTile<QSTile.State> {
+    private static final Intent TETHER_SETTINGS = new Intent()
+            .setClassName("com.android.settings", "com.android.settings.TetherSettings");
+
+    // TODO: implement. see com.android.settings.TetherSettings
+
+    private final TetheringController mController;
+
+    public HotspotTile(Host host) {
+        super(host);
+        mController = host.getTetheringController();
+    }
+
+    @Override
+    protected State newTileState() {
+        return new State();
+    }
+
+    @Override
+    public void dispose() {
+
+    }
+
+    @Override
+    protected void handleClick() {
+        mHost.startSettingsActivity(TETHER_SETTINGS);
+    }
+
+    @Override
+    protected void handleUpdateState(State state, Object arg) {
+        state.visible = mController != null;
+        state.label = mContext.getString(R.string.quick_settings_hotspot_label);
+        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_hotspot);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
new file mode 100644
index 0000000..d32f98f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.LocationController.LocationSettingsChangeCallback;
+
+/** Quick settings tile: Location **/
+public class LocationTile extends QSTile<QSTile.BooleanState> {
+
+    private final LocationController mController;
+
+    public LocationTile(Host host) {
+        super(host);
+        mController = host.getLocationController();
+        mController.addSettingsChangedCallback(mCallback);
+    }
+
+    @Override
+    protected BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    public void dispose() {
+        mController.removeSettingsChangedCallback(mCallback);
+    }
+
+    @Override
+    protected void handleClick() {
+        final boolean wasEnabled = (Boolean) mState.value;
+        final boolean changed = mController.setLocationEnabled(!wasEnabled);
+        if (!wasEnabled && changed) {
+            // If we've successfully switched from location off to on, close the
+            // notifications tray to show the network location provider consent dialog.
+            mHost.collapsePanels();
+        }
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        final boolean locationEnabled =  mController.isLocationEnabled();
+        state.visible = true;
+        state.value = locationEnabled;
+        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_location);
+        if (locationEnabled) {
+            state.iconId = R.drawable.ic_qs_location_on;
+            state.label = mContext.getString(R.string.quick_settings_location_label);
+            state.contentDescription = mContext.getString(
+                    R.string.accessibility_quick_settings_location,
+                    mContext.getString(R.string.accessibility_desc_on));
+        } else {
+            state.iconId = R.drawable.ic_qs_location_off;
+            state.label = mContext.getString(R.string.quick_settings_location_off_label);
+            state.contentDescription = mContext.getString(
+                    R.string.accessibility_quick_settings_location,
+                    mContext.getString(R.string.accessibility_desc_off));
+        }
+    }
+
+    private final LocationSettingsChangeCallback mCallback = new LocationSettingsChangeCallback() {
+        @Override
+        public void onLocationSettingsChanged(boolean enabled) {
+            refreshState();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java
new file mode 100644
index 0000000..36a579c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.media.AudioManager;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+
+/** Quick settings tile: Ringer mode **/
+public class RingerModeTile extends QSTile<RingerModeTile.IntState> {
+
+    private final AudioManager mAudioManager;
+
+    public RingerModeTile(Host host) {
+        super(host);
+        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        final IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
+        mContext.registerReceiver(mReceiver, filter);
+    }
+
+    @Override
+    protected IntState newTileState() {
+        return new IntState();
+    }
+
+    @Override
+    public void dispose() {
+        mContext.unregisterReceiver(mReceiver);
+    }
+
+    @Override
+    protected void handleClick() {
+        final int oldValue = (Integer) mState.value;
+        final int newValue =
+                oldValue == AudioManager.RINGER_MODE_NORMAL ? AudioManager.RINGER_MODE_VIBRATE
+              : oldValue == AudioManager.RINGER_MODE_VIBRATE ? AudioManager.RINGER_MODE_SILENT
+              : AudioManager.RINGER_MODE_NORMAL;
+
+        mAudioManager.setRingerMode(newValue);
+    }
+
+    @Override
+    protected void handleUpdateState(IntState state, Object arg) {
+        final int ringerMode = mAudioManager.getRingerMode();
+        state.visible = true;
+        state.value = ringerMode;
+        if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
+            state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_ringer_vibrate);
+            state.label = "Vibrate";
+        } else if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
+            state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_ringer_silent);
+            state.label = "Silent";
+        } else {
+            state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_ringer_audible);
+            state.label = "Audible";
+        }
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(intent.getAction())) {
+                refreshState();
+            }
+        }
+    };
+
+    public static class IntState extends QSTile.State {
+        public int value;
+
+        @Override
+        public boolean copyTo(State other) {
+            final IntState o = (IntState) other;
+            final boolean changed = o.value != value;
+            o.value = value;
+            return super.copyTo(other) || changed;
+        }
+
+        @Override
+        protected StringBuilder toStringBuilder() {
+            final StringBuilder rt = super.toStringBuilder();
+            rt.insert(rt.length() - 1, ",value=" + value);
+            return rt;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
new file mode 100644
index 0000000..d075299
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.res.Configuration;
+import android.graphics.drawable.AnimationDrawable;
+import android.graphics.drawable.Drawable;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
+
+/** Quick settings tile: Rotation **/
+public class RotationLockTile extends QSTile<QSTile.BooleanState> {
+
+    private final RotationLockController mController;
+
+    public RotationLockTile(Host host) {
+        super(host);
+        mController = host.getRotationLockController();
+        if (mController == null) return;
+        mController.addRotationLockControllerCallback(mCallback);
+    }
+
+    @Override
+    protected BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    public void dispose() {
+        if (mController == null) return;
+        mController.removeRotationLockControllerCallback(mCallback);
+    }
+
+    @Override
+    protected void handleClick() {
+        if (mController == null) return;
+        mController.setRotationLocked(!mState.value);
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        if (mController == null) return;
+        final boolean rotationLocked = mController.isRotationLocked();
+        state.visible = mController.isRotationLockAffordanceVisible();
+        if (state.value != rotationLocked) {
+            state.value = rotationLocked;
+            final AnimationDrawable d = (AnimationDrawable) mContext.getDrawable(rotationLocked
+                    ? R.drawable.ic_rotate_locked_anim
+                    : R.drawable.ic_rotate_unlocked_anim);
+            state.icon = d;
+            mUiHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    d.start();
+                }
+            });
+        }
+        if (rotationLocked) {
+            final int lockOrientation = mController.getRotationLockOrientation();
+            final int label = lockOrientation == Configuration.ORIENTATION_PORTRAIT
+                    ? R.string.quick_settings_rotation_locked_portrait_label
+                    : lockOrientation == Configuration.ORIENTATION_LANDSCAPE
+                    ? R.string.quick_settings_rotation_locked_landscape_label
+                    : R.string.quick_settings_rotation_locked_label;
+            state.label = mContext.getString(label);
+            if (state.icon == null) {
+                state.icon = mContext.getDrawable(R.drawable.ic_rotate_24_15);
+            }
+        } else {
+            state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label);
+            if (state.icon == null) {
+                state.icon = mContext.getDrawable(R.drawable.ic_rotate_24_01);
+            }
+        }
+    }
+
+    private final RotationLockControllerCallback mCallback = new RotationLockControllerCallback() {
+        @Override
+        public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
+            refreshState();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
new file mode 100644
index 0000000..e08a6fa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.provider.Settings;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.QSTileView;
+import com.android.systemui.qs.SignalTileView;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
+
+/** Quick settings tile: Wifi **/
+public class WifiTile extends QSTile<QSTile.SignalState> {
+    private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS);
+
+    private final NetworkController mController;
+
+    public WifiTile(Host host) {
+        super(host);
+        mController = host.getNetworkController();
+        mController.addNetworkSignalChangedCallback(mCallback);
+    }
+
+    @Override
+    protected SignalState newTileState() {
+        return new SignalState();
+    }
+
+    @Override
+    public void dispose() {
+        mController.removeNetworkSignalChangedCallback(mCallback);
+    }
+
+    @Override
+    public QSTileView createTileView(Context context) {
+        return new SignalTileView(context);
+    }
+
+    @Override
+    protected void handleClick() {
+        mController.setWifiEnabled(!mState.enabled);
+    }
+
+    @Override
+    protected void handleSecondaryClick() {
+        mHost.startSettingsActivity(WIFI_SETTINGS);
+    }
+
+    @Override
+    protected void handleUpdateState(SignalState state, Object arg) {
+        if (arg == null) return;
+        state.visible = true;
+        CallbackInfo cb = (CallbackInfo) arg;
+
+        boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.enabledDesc != null);
+        boolean wifiNotConnected = (cb.wifiSignalIconId > 0) && (cb.enabledDesc == null);
+        state.enabled = wifiConnected;
+        state.connected = wifiConnected;
+        state.activityIn = cb.enabled && cb.activityIn;
+        state.activityOut = cb.enabled && cb.activityOut;
+        final String signalContentDescription;
+        final Resources r = mContext.getResources();
+        if (wifiConnected) {
+            state.iconId = cb.wifiSignalIconId;
+            state.label = removeDoubleQuotes(cb.enabledDesc);
+            signalContentDescription = cb.wifiSignalContentDescription;
+        } else if (wifiNotConnected) {
+            state.iconId = R.drawable.ic_qs_wifi_0;
+            state.label = r.getString(R.string.quick_settings_wifi_label);
+            signalContentDescription = r.getString(R.string.accessibility_no_wifi);
+        } else {
+            state.iconId = R.drawable.ic_qs_wifi_no_network;
+            state.label = r.getString(R.string.quick_settings_wifi_off_label);
+            signalContentDescription = r.getString(R.string.accessibility_wifi_off);
+        }
+        state.contentDescription = mContext.getString(
+                R.string.accessibility_quick_settings_wifi,
+                signalContentDescription,
+                state.connected ? state.label : "");
+    }
+
+    private static String removeDoubleQuotes(String string) {
+        if (string == null) return null;
+        final int length = string.length();
+        if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
+            return string.substring(1, length - 1);
+        }
+        return string;
+    }
+
+    private static final class CallbackInfo {
+        boolean enabled;
+        int wifiSignalIconId;
+        String enabledDesc;
+        boolean activityIn;
+        boolean activityOut;
+        String wifiSignalContentDescription;
+    }
+
+    private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() {
+        @Override
+        public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
+                boolean activityIn, boolean activityOut,
+                String wifiSignalContentDescriptionId, String description) {
+            final CallbackInfo info = new CallbackInfo();
+            info.enabled = enabled;
+            info.wifiSignalIconId = wifiSignalIconId;
+            info.enabledDesc = description;
+            info.activityIn = activityIn;
+            info.activityOut = activityOut;
+            info.wifiSignalContentDescription = wifiSignalContentDescriptionId;
+            refreshState(info);
+        }
+
+        @Override
+        public void onMobileDataSignalChanged(boolean enabled,
+                int mobileSignalIconId,
+                String mobileSignalContentDescriptionId, int dataTypeIconId,
+                boolean activityIn, boolean activityOut,
+                String dataTypeContentDescriptionId, String description) {
+            // noop
+        }
+
+        @Override
+        public void onAirplaneModeChanged(boolean enabled) {
+            // noop
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java
new file mode 100644
index 0000000..dceb856
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings;
+import android.service.notification.Condition;
+import android.util.AttributeSet;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.ListView;
+import android.widget.RadioButton;
+import android.widget.RelativeLayout;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSImageView;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import java.util.HashSet;
+
+/** Quick settings control panel: Zen mode **/
+public class ZenModeDetail extends RelativeLayout {
+    private static final String TAG = "ZenModeDetail";
+    private static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+    private static final int[] MINUTES = new int[] { 15, 30, 45, 60, 120, 180, 240 };
+
+    private final H mHandler = new H();
+
+    private int mMinutesIndex = 3;
+    private Context mContext;
+    private ZenModeTile mTile;
+    private QSTile.Host mHost;
+    private ZenModeController mController;
+
+    private Switch mSwitch;
+    private ConditionAdapter mAdapter;
+
+    public ZenModeDetail(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public void init(ZenModeTile tile) {
+        mTile = tile;
+        mHost = mTile.getHost();
+        mContext = getContext();
+        mController = mHost.getZenModeController();
+
+        final QSImageView close = (QSImageView) findViewById(android.R.id.button1);
+        close.setImageDrawable(mHost.getVectorDrawable(R.drawable.ic_qs_close));
+        close.setEnabledVersion(true);
+        close.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mTile.showDetail(false);
+            }
+        });
+        mSwitch = (Switch) findViewById(android.R.id.checkbox);
+        mSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+            @Override
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                mController.setZen(isChecked);
+            }
+        });
+        mSwitch.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                final boolean isChecked = mSwitch.isChecked();
+                mController.setZen(isChecked);
+                if (!isChecked) {
+                    mTile.showDetail(false);
+                }
+            }
+        });
+
+        final View moreSettings = findViewById(android.R.id.button2);
+        moreSettings.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mHost.startSettingsActivity(ZEN_SETTINGS);
+                mTile.showDetail(false);
+            }
+        });
+        final ListView conditions = (ListView) findViewById(android.R.id.content);
+        mAdapter = new ConditionAdapter(mContext);
+        conditions.setAdapter(mAdapter);
+        mAdapter.add(updateTimeCondition());
+
+        updateZen(mController.isZen());
+    }
+
+    private Condition updateTimeCondition() {
+        final int minutes = MINUTES[mMinutesIndex];
+        final long millis = System.currentTimeMillis() + minutes * 60 * 1000;
+        final Uri id = new Uri.Builder().scheme(Condition.SCHEME).authority("android")
+                .appendPath("countdown").appendPath(Long.toString(millis)).build();
+        final int num = minutes < 60 ? minutes : minutes / 60;
+        final String units = minutes < 60 ? "minutes" : minutes == 60 ? "hour" : "hours";
+        return new Condition(id, "For " + num + " " + units, "", "", 0, Condition.STATE_TRUE,
+                Condition.FLAG_RELEVANT_NOW);
+    }
+
+    private void editTimeCondition(int delta) {
+        final int i = mMinutesIndex + delta;
+        if (i < 0 || i >= MINUTES.length) return;
+        mMinutesIndex = i;
+        mAdapter.remove(mAdapter.getItem(0));
+        final Condition c = updateTimeCondition();
+        mAdapter.insert(c, 0);
+        select(c);
+    }
+
+    private void select(Condition condition) {
+        mController.select(condition);
+    }
+
+    private void updateZen(boolean zen) {
+        mHandler.obtainMessage(H.UPDATE_ZEN, zen ? 1 : 0, 0).sendToTarget();
+    }
+
+    private void updateConditions(Condition[] conditions) {
+        if (conditions == null) return;
+        mHandler.obtainMessage(H.UPDATE_CONDITIONS, conditions).sendToTarget();
+    }
+
+    private void handleUpdateZen(boolean zen) {
+        mSwitch.setChecked(zen);
+    }
+
+    private void handleUpdateConditions(Condition[] conditions) {
+        for (int i = mAdapter.getCount() - 1; i > 0; i--) {
+            mAdapter.remove(mAdapter.getItem(i));
+        }
+        for (Condition condition : conditions) {
+            mAdapter.add(condition);
+        }
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mController.addCallback(mCallback);
+        mController.requestConditions(true);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mController.removeCallback(mCallback);
+        mController.requestConditions(false);
+    }
+
+    private final class H extends Handler {
+        private static final int UPDATE_ZEN = 1;
+        private static final int UPDATE_CONDITIONS = 2;
+
+        public H() {
+            super(Looper.getMainLooper());
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == UPDATE_ZEN) {
+                handleUpdateZen(msg.arg1 == 1);
+            } else if (msg.what == UPDATE_CONDITIONS) {
+                handleUpdateConditions((Condition[])msg.obj);
+            }
+        }
+    }
+
+    private final ZenModeController.Callback mCallback = new ZenModeController.Callback() {
+        @Override
+        public void onZenChanged(boolean zen) {
+            updateZen(zen);
+        }
+        public void onConditionsChanged(Condition[] conditions) {
+            updateConditions(conditions);
+        }
+    };
+
+    private final class ConditionAdapter extends ArrayAdapter<Condition> {
+        private final LayoutInflater mInflater;
+        private final HashSet<RadioButton> mRadioButtons = new HashSet<RadioButton>();
+
+        public ConditionAdapter(Context context) {
+            super(context, 0);
+            mInflater = LayoutInflater.from(new ContextThemeWrapper(context, R.style.QSWhiteTheme));
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            final Condition condition = getItem(position);
+            final boolean enabled = condition.state == Condition.STATE_TRUE;
+
+            final View row = convertView != null ? convertView : mInflater
+                    .inflate(R.layout.qs_zen_mode_detail_condition, parent, false);
+            final RadioButton rb = (RadioButton) row.findViewById(android.R.id.checkbox);
+            mRadioButtons.add(rb);
+            rb.setEnabled(enabled);
+            rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+                @Override
+                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                    if (isChecked) {
+                        for (RadioButton otherButton : mRadioButtons) {
+                            if (otherButton == rb) continue;
+                            otherButton.setChecked(false);
+                        }
+                        select(condition);
+                    }
+                }
+            });
+            final TextView title = (TextView) row.findViewById(android.R.id.title);
+            title.setText(condition.summary);
+            title.setEnabled(enabled);
+            title.setAlpha(enabled ? 1 : .5f);
+            final QSImageView button1 = (QSImageView) row.findViewById(android.R.id.button1);
+            button1.setImageDrawable(mHost.getVectorDrawable(R.drawable.ic_qs_minus));
+            button1.setEnabledVersion(true);
+            button1.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    rb.setChecked(true);
+                    editTimeCondition(-1);
+                }
+            });
+
+            final QSImageView button2 = (QSImageView) row.findViewById(android.R.id.button2);
+            button2.setImageDrawable(mHost.getVectorDrawable(R.drawable.ic_qs_plus));
+            button2.setEnabledVersion(true);
+            button2.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    rb.setChecked(true);
+                    editTimeCondition(1);
+                }
+            });
+            title.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    rb.setChecked(true);
+                }
+            });
+            if (position != 0) {
+                button1.setVisibility(View.GONE);
+                button2.setVisibility(View.GONE);
+            }
+            if (position == 0 && mRadioButtons.size() == 1) {
+                rb.setChecked(true);
+            }
+            return row;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java
new file mode 100644
index 0000000..83918e8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.Context;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+/** Quick settings tile: Zen mode **/
+public class ZenModeTile extends QSTile<QSTile.BooleanState> {
+    private final ZenModeController mController;
+
+    public ZenModeTile(Host host) {
+        super(host);
+        mController = host.getZenModeController();
+        mController.addCallback(mCallback);
+    }
+
+    @Override
+    public View createDetailView(Context context, ViewGroup root) {
+        final Context themedContext = new ContextThemeWrapper(mContext, R.style.QSAccentTheme);
+        final ZenModeDetail v = (ZenModeDetail) LayoutInflater.from(themedContext)
+                .inflate(R.layout.qs_zen_mode_detail, root, false);
+        v.init(this);
+        return v;
+    }
+
+    @Override
+    protected BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    public void dispose() {
+        mController.removeCallback(mCallback);
+    }
+
+    @Override
+    protected void handleClick() {
+        final boolean newZen = !mState.value;
+        mController.setZen(newZen);
+        if (newZen) {
+            showDetail(true);
+        }
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        final boolean zen = arg instanceof Boolean ? (Boolean)arg : mController.isZen();
+        state.value = zen;
+        state.visible = true;
+        state.iconId = R.drawable.stat_sys_zen_limited;
+        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_zen);
+        state.label = mContext.getString(R.string.zen_mode_title);
+    }
+
+    private final ZenModeController.Callback mCallback = new ZenModeController.Callback() {
+        @Override
+        public void onZenChanged(boolean zen) {
+            refreshState(zen);
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 35c824b..0759b8e 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -217,6 +217,10 @@
     public void onDragCancelled(View v) {
     }
 
+    @Override
+    public void onChildSnappedBack(View animView) {
+    }
+
     public View getChildAtPosition(MotionEvent ev) {
         final float x = ev.getX() + getScrollX();
         final float y = ev.getY() + getScrollY();
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index 297fe0d..c2dde6a 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -225,6 +225,10 @@
     public void onDragCancelled(View v) {
     }
 
+    @Override
+    public void onChildSnappedBack(View animView) {
+    }
+
     public View getChildAtPosition(MotionEvent ev) {
         final float x = ev.getX() + getScrollX();
         final float y = ev.getY() + getScrollY();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index f2e322d..19a1b11 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -64,6 +64,17 @@
                 mSingleCountFirstTaskRect.offset(0, (int) statusBarHeight);
                 mMultipleCountFirstTaskRect = replyData.getParcelable(KEY_MULTIPLE_TASK_STACK_RECT);
                 mMultipleCountFirstTaskRect.offset(0, (int) statusBarHeight);
+                Console.log(Constants.Log.App.RecentsComponent,
+                        "[RecentsComponent|RecentsMessageHandler|handleMessage]",
+                        "singleTaskRect: " + mSingleCountFirstTaskRect +
+                        " multipleTaskRect: " + mMultipleCountFirstTaskRect);
+
+                // If we had the update the animation rects as a result of onServiceConnected, then
+                // we check for whether we need to toggle the recents here.
+                if (mToggleRecentsUponServiceBound) {
+                    startAlternateRecentsActivity();
+                    mToggleRecentsUponServiceBound = false;
+                }
             }
         }
     }
@@ -72,22 +83,27 @@
     class RecentsServiceConnection implements ServiceConnection {
         @Override
         public void onServiceConnected(ComponentName className, IBinder service) {
-            Console.log(Constants.DebugFlags.App.RecentsComponent,
+            Console.log(Constants.Log.App.RecentsComponent,
                     "[RecentsComponent|ServiceConnection|onServiceConnected]",
                     "toggleRecents: " + mToggleRecentsUponServiceBound);
             mService = new Messenger(service);
             mServiceIsBound = true;
 
-            // Toggle recents if this service connection was triggered by hitting the recents button
-            if (mToggleRecentsUponServiceBound) {
-                startAlternateRecentsActivity();
+            if (hasValidTaskRects()) {
+                // Toggle recents if this new service connection was triggered by hitting recents
+                if (mToggleRecentsUponServiceBound) {
+                    startAlternateRecentsActivity();
+                    mToggleRecentsUponServiceBound = false;
+                }
+            } else {
+                // Otherwise, update the animation rects before starting the recents if requested
+                updateAnimationRects();
             }
-            mToggleRecentsUponServiceBound = false;
         }
 
         @Override
         public void onServiceDisconnected(ComponentName className) {
-            Console.log(Constants.DebugFlags.App.RecentsComponent,
+            Console.log(Constants.Log.App.RecentsComponent,
                     "[RecentsComponent|ServiceConnection|onServiceDisconnected]");
             mService = null;
             mServiceIsBound = false;
@@ -138,7 +154,7 @@
     }
 
     public void onStart() {
-        Console.log(Constants.DebugFlags.App.RecentsComponent, "[RecentsComponent|start]");
+        Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|start]");
 
         // Try to create a long-running connection to the recents service
         bindToRecentsService(false);
@@ -146,11 +162,11 @@
 
     /** Toggles the alternate recents activity */
     public void onToggleRecents(Display display, int layoutDirection, View statusBarView) {
-        Console.logStartTracingTime(Constants.DebugFlags.App.TimeRecentsStartup,
-                Constants.DebugFlags.App.TimeRecentsStartupKey);
-        Console.logStartTracingTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
-                Constants.DebugFlags.App.TimeRecentsLaunchKey);
-        Console.log(Constants.DebugFlags.App.RecentsComponent, "[RecentsComponent|toggleRecents]",
+        Console.logStartTracingTime(Constants.Log.App.TimeRecentsStartup,
+                Constants.Log.App.TimeRecentsStartupKey);
+        Console.logStartTracingTime(Constants.Log.App.TimeRecentsLaunchTask,
+                Constants.Log.App.TimeRecentsLaunchKey);
+        Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|toggleRecents]",
                 "serviceIsBound: " + mServiceIsBound);
         mStatusBarView = statusBarView;
         if (!mServiceIsBound) {
@@ -176,7 +192,7 @@
     }
 
     public void onCloseRecents() {
-        Console.log(Constants.DebugFlags.App.RecentsComponent, "[RecentsComponent|closeRecents]");
+        Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|closeRecents]");
         if (mServiceIsBound) {
             // Try and update the recents configuration
             try {
@@ -191,6 +207,26 @@
     }
 
     public void onConfigurationChanged(Configuration newConfig) {
+        updateAnimationRects();
+    }
+
+    /** Binds to the recents implementation */
+    private void bindToRecentsService(boolean toggleRecentsUponConnection) {
+        mToggleRecentsUponServiceBound = toggleRecentsUponConnection;
+        Intent intent = new Intent();
+        intent.setClassName(sRecentsPackage, sRecentsService);
+        mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+    }
+
+    /** Returns whether we have valid task rects to animate to. */
+    boolean hasValidTaskRects() {
+        return mSingleCountFirstTaskRect != null && mSingleCountFirstTaskRect.width() > 0 &&
+                mSingleCountFirstTaskRect.height() > 0 && mMultipleCountFirstTaskRect != null &&
+                mMultipleCountFirstTaskRect.width() > 0 && mMultipleCountFirstTaskRect.height() > 0;
+    }
+
+    /** Updates each of the task animation rects. */
+    void updateAnimationRects() {
         if (mServiceIsBound) {
             Resources res = mContext.getResources();
             int statusBarHeight = res.getDimensionPixelSize(
@@ -216,26 +252,13 @@
         }
     }
 
-    /** Binds to the recents implementation */
-    private void bindToRecentsService(boolean toggleRecentsUponConnection) {
-        mToggleRecentsUponServiceBound = toggleRecentsUponConnection;
-        Intent intent = new Intent();
-        intent.setClassName(sRecentsPackage, sRecentsService);
-        mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
-    }
-
     /** Loads the first task thumbnail */
     Bitmap loadFirstTaskThumbnail() {
         SystemServicesProxy ssp = mSystemServicesProxy;
-        List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(1,
-                UserHandle.CURRENT.getIdentifier());
-        for (ActivityManager.RecentTaskInfo t : tasks) {
-            // Skip tasks in the home stack
-            if (ssp.isInHomeStack(t.persistentId)) {
-                return null;
-            }
+        List<ActivityManager.RunningTaskInfo> tasks = ssp.getRunningTasks(1);
 
-            return ssp.getTaskThumbnail(t.persistentId);
+        for (ActivityManager.RunningTaskInfo t : tasks) {
+            return ssp.getTaskThumbnail(t.id);
         }
         return null;
     }
@@ -258,17 +281,6 @@
         return (tasks.size() > 1);
     }
 
-    /** Returns whether the base intent of the top task stack was launched with the flag
-     * Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS. */
-    boolean isTopTaskExcludeFromRecents(List<ActivityManager.RecentTaskInfo> tasks) {
-        if (tasks.size() > 0) {
-            ActivityManager.RecentTaskInfo t = tasks.get(0);
-            Console.log(t.baseIntent.toString());
-            return (t.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0;
-        }
-        return false;
-    }
-
     /** Converts from the device rotation to the degree */
     float getDegreesForRotation(int value) {
         switch (value) {
@@ -300,6 +312,49 @@
         return SurfaceControl.screenshot((int) dims[0], (int) dims[1]);
     }
 
+    /** Creates the activity options for a thumbnail transition. */
+    ActivityOptions getThumbnailTransitionActivityOptions(Rect taskRect) {
+        // Loading from thumbnail
+        Bitmap thumbnail;
+        Bitmap firstThumbnail = loadFirstTaskThumbnail();
+        if (firstThumbnail != null) {
+            // Create the thumbnail
+            thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
+                    Bitmap.Config.ARGB_8888);
+            int size = Math.min(firstThumbnail.getWidth(), firstThumbnail.getHeight());
+            Canvas c = new Canvas(thumbnail);
+            c.drawBitmap(firstThumbnail, new Rect(0, 0, size, size),
+                    new Rect(0, 0, taskRect.width(), taskRect.height()), null);
+            c.setBitmap(null);
+            // Recycle the old thumbnail
+            firstThumbnail.recycle();
+        } else {
+            // Load the thumbnail from the screenshot if can't get one from the system
+            WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+            Display display = wm.getDefaultDisplay();
+            Bitmap screenshot = takeScreenshot(display);
+            if (screenshot != null) {
+                Resources res = mContext.getResources();
+                int size = Math.min(screenshot.getWidth(), screenshot.getHeight());
+                int statusBarHeight = res.getDimensionPixelSize(
+                        com.android.internal.R.dimen.status_bar_height);
+                thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
+                        Bitmap.Config.ARGB_8888);
+                Canvas c = new Canvas(thumbnail);
+                c.drawBitmap(screenshot, new Rect(0, statusBarHeight, size, statusBarHeight +
+                        size), new Rect(0, 0, taskRect.width(), taskRect.height()), null);
+                c.setBitmap(null);
+                // Recycle the temporary screenshot
+                screenshot.recycle();
+            } else {
+                return null;
+            }
+        }
+
+        return ActivityOptions.makeThumbnailScaleDownAnimation(mStatusBarView, thumbnail,
+                taskRect.left, taskRect.top, null);
+    }
+
     /** Starts the recents activity */
     void startAlternateRecentsActivity() {
         // If the user has toggled it too quickly, then just eat up the event here (it's better than
@@ -329,10 +384,10 @@
                     mService.send(msg);
 
                     // Time this path
-                    Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
-                            Constants.DebugFlags.App.TimeRecentsStartupKey, "sendToggleRecents");
-                    Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
-                            Constants.DebugFlags.App.TimeRecentsLaunchKey, "sendToggleRecents");
+                    Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                            Constants.Log.App.TimeRecentsStartupKey, "sendToggleRecents");
+                    Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+                            Constants.Log.App.TimeRecentsLaunchKey, "sendToggleRecents");
                 } catch (RemoteException re) {
                     re.printStackTrace();
                 }
@@ -345,61 +400,40 @@
         }
 
         // Otherwise, Recents is not the front-most activity and we should animate into it.  If
-        // the activity at the root of the top task stack is excluded from recents, or if that
-        // task stack is in the home stack, then we just do a simple transition.  Otherwise, we
-        // animate to the rects defined by the Recents service, which can differ depending on the
-        // number of items in the list.
+        // the activity at the root of the top task stack in the home stack, then we just do a
+        // simple transition.  Otherwise, we animate to the rects defined by the Recents service,
+        // which can differ depending on the number of items in the list.
         List<ActivityManager.RecentTaskInfo> recentTasks =
-                ssp.getRecentTasks(4, UserHandle.CURRENT.getIdentifier());
-        boolean hasMultipleTasks = hasMultipleRecentsTask(recentTasks);
-        boolean isTaskExcludedFromRecents = isTopTaskExcludeFromRecents(recentTasks);
-        Rect taskRect = hasMultipleTasks ? mMultipleCountFirstTaskRect : mSingleCountFirstTaskRect;
-        if (!isTopTaskHome && !isTaskExcludedFromRecents &&
-                (taskRect != null) && (taskRect.width() > 0) && (taskRect.height() > 0)) {
-            // Loading from thumbnail
-            Bitmap thumbnail;
-            Bitmap firstThumbnail = loadFirstTaskThumbnail();
-            if (firstThumbnail != null) {// Create the thumbnail
-                thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
-                        Bitmap.Config.ARGB_8888);
-                int size = Math.min(firstThumbnail.getWidth(), firstThumbnail.getHeight());
-                Canvas c = new Canvas(thumbnail);
-                c.drawBitmap(firstThumbnail, new Rect(0, 0, size, size),
-                        new Rect(0, 0, taskRect.width(), taskRect.height()), null);
-                c.setBitmap(null);
-                // Recycle the old thumbnail
-                firstThumbnail.recycle();
-            } else {
-                // Load the thumbnail from the screenshot if can't get one from the system
-                WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
-                Display display = wm.getDefaultDisplay();
-                Bitmap screenshot = takeScreenshot(display);
-                Resources res = mContext.getResources();
-                int size = Math.min(screenshot.getWidth(), screenshot.getHeight());
-                int statusBarHeight = res.getDimensionPixelSize(
-                        com.android.internal.R.dimen.status_bar_height);
-                thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
-                        Bitmap.Config.ARGB_8888);
-                Canvas c = new Canvas(thumbnail);
-                c.drawBitmap(screenshot, new Rect(0, statusBarHeight, size, statusBarHeight + size),
-                        new Rect(0, 0, taskRect.width(), taskRect.height()), null);
-                c.setBitmap(null);
-                // Recycle the temporary screenshot
-                screenshot.recycle();
-            }
+                ssp.getRecentTasks(2, UserHandle.CURRENT.getIdentifier());
+        Rect taskRect = hasMultipleRecentsTask(recentTasks) ? mMultipleCountFirstTaskRect :
+                mSingleCountFirstTaskRect;
+        boolean useThumbnailTransition = !isTopTaskHome &&
+                hasValidTaskRects();
 
-            ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation(mStatusBarView,
-                    thumbnail, taskRect.left, taskRect.top, null);
-            startAlternateRecentsActivity(opts, true);
-        } else {
+        if (useThumbnailTransition) {
+            // Try starting with a thumbnail transition
+            ActivityOptions opts = getThumbnailTransitionActivityOptions(taskRect);
+            if (opts != null) {
+                startAlternateRecentsActivity(opts, true);
+            } else {
+                // Fall through below to the non-thumbnail transition
+                useThumbnailTransition = false;
+            }
+        }
+
+        // If there is no thumbnail transition, then just use a generic transition
+        // XXX: This should be different between home and from a recents-excluded app, perhaps the
+        //      recents-excluded app should still show up in recents, when the app is in the
+        //      foreground
+        if (!useThumbnailTransition) {
             ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
                     R.anim.recents_from_launcher_enter,
                     R.anim.recents_from_launcher_exit);
             startAlternateRecentsActivity(opts, false);
         }
 
-        Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
-                Constants.DebugFlags.App.TimeRecentsStartupKey, "startRecentsActivity");
+        Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                Constants.Log.App.TimeRecentsStartupKey, "startRecentsActivity");
         mLastToggleTime = System.currentTimeMillis();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java b/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java
deleted file mode 100644
index 95ab8e8..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.android.systemui.recents;
-
-import android.animation.TimeInterpolator;
-
-/**
- * A pre-baked bezier-curved interpolator for quantum-paper transitions.
- */
-public class BakedBezierInterpolator implements TimeInterpolator {
-    public static final BakedBezierInterpolator INSTANCE = new BakedBezierInterpolator();
-
-    /**
-     * Use the INSTANCE variable instead of instantiating.
-     */
-    private BakedBezierInterpolator() {
-        super();
-    }
-
-    /**
-     * Lookup table values.
-     * Generated using a Bezier curve from (0,0) to (1,1) with control points:
-     * P0 (0,0)
-     * P1 (0.4, 0)
-     * P2 (0.2, 1.0)
-     * P3 (1.0, 1.0)
-     *
-     * Values sampled with x at regular intervals between 0 and 1.
-     */
-    private static final float[] VALUES = new float[] {
-        0.0f, 0.0002f, 0.0009f, 0.0019f, 0.0036f, 0.0059f, 0.0086f, 0.0119f, 0.0157f, 0.0209f,
-        0.0257f, 0.0321f, 0.0392f, 0.0469f, 0.0566f, 0.0656f, 0.0768f, 0.0887f, 0.1033f, 0.1186f,
-        0.1349f, 0.1519f, 0.1696f, 0.1928f, 0.2121f, 0.237f, 0.2627f, 0.2892f, 0.3109f, 0.3386f,
-        0.3667f, 0.3952f, 0.4241f, 0.4474f, 0.4766f, 0.5f, 0.5234f, 0.5468f, 0.5701f, 0.5933f,
-        0.6134f, 0.6333f, 0.6531f, 0.6698f, 0.6891f, 0.7054f, 0.7214f, 0.7346f, 0.7502f, 0.763f,
-        0.7756f, 0.7879f, 0.8f, 0.8107f, 0.8212f, 0.8326f, 0.8415f, 0.8503f, 0.8588f, 0.8672f,
-        0.8754f, 0.8833f, 0.8911f, 0.8977f, 0.9041f, 0.9113f, 0.9165f, 0.9232f, 0.9281f, 0.9328f,
-        0.9382f, 0.9434f, 0.9476f, 0.9518f, 0.9557f, 0.9596f, 0.9632f, 0.9662f, 0.9695f, 0.9722f,
-        0.9753f, 0.9777f, 0.9805f, 0.9826f, 0.9847f, 0.9866f, 0.9884f, 0.9901f, 0.9917f, 0.9931f,
-        0.9944f, 0.9955f, 0.9964f, 0.9973f, 0.9981f, 0.9986f, 0.9992f, 0.9995f, 0.9998f, 1.0f, 1.0f
-    };
-
-    private static final float STEP_SIZE = 1.0f / (VALUES.length - 1);
-
-    @Override
-    public float getInterpolation(float input) {
-        if (input >= 1.0f) {
-            return 1.0f;
-        }
-
-        if (input <= 0f) {
-            return 0f;
-        }
-
-        int position = Math.min(
-                (int)(input * (VALUES.length - 1)),
-                VALUES.length - 2);
-
-        float quantized = position * STEP_SIZE;
-        float difference = input - quantized;
-        float weight = difference / STEP_SIZE;
-
-        return VALUES[position] + weight * (VALUES[position + 1] - VALUES[position]);
-    }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Console.java b/packages/SystemUI/src/com/android/systemui/recents/Console.java
index 4b75c99..c8d97cc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Console.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Console.java
@@ -37,7 +37,7 @@
     public static final String AnsiRed = "\u001B[31m";      // SystemUIHandshake
     public static final String AnsiGreen = "\u001B[32m";    // MeasureAndLayout
     public static final String AnsiYellow = "\u001B[33m";   // SynchronizeViewsWithModel
-    public static final String AnsiBlue = "\u001B[34m";     // TouchEvents
+    public static final String AnsiBlue = "\u001B[34m";     // TouchEvents, Search
     public static final String AnsiPurple = "\u001B[35m";   // Draw
     public static final String AnsiCyan = "\u001B[36m";     // ClickEvents
     public static final String AnsiWhite = "\u001B[37m";
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 72d9a52..90998da 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -18,7 +18,6 @@
 
 /**
  * Constants
- * XXX: We are going to move almost all of these into a resource.
  */
 public class Constants {
     public static class DebugFlags {
@@ -26,11 +25,18 @@
         public static final boolean Verbose = false;
 
         public static class App {
-            public static final boolean EnableTaskFiltering = true;
+            // Enables the filtering of tasks according to their grouping
+            public static final boolean EnableTaskFiltering = false;
+            // Enables clipping of tasks against each other
             public static final boolean EnableTaskStackClipping = false;
-            public static final boolean EnableInfoPane = true;
-            public static final boolean EnableSearchButton = false;
-
+            // Enables the use of theme colors as the task bar background
+            public static final boolean EnableTaskBarThemeColors = true;
+            // Enables the info pane on long-press
+            public static final boolean EnableInfoPane = false;
+            // Enables the search bar layout
+            public static final boolean EnableSearchLayout = true;
+            // Enables the dynamic shadows behind each task
+            public static final boolean EnableShadows = false;
             // This disables the bitmap and icon caches
             public static final boolean DisableBackgroundCache = false;
             // For debugging, this enables us to create mock recents tasks
@@ -39,8 +45,11 @@
             public static final int SystemServicesProxyMockPackageCount = 3;
             // For debugging, this defines the number of mock recents tasks to create
             public static final int SystemServicesProxyMockTaskCount = 75;
+        }
+    }
 
-            // Timing certain paths
+    public static class Log {
+        public static class App {
             public static final String TimeRecentsStartupKey = "startup";
             public static final String TimeRecentsLaunchKey = "launchTask";
             public static final boolean TimeRecentsStartup = false;
@@ -51,6 +60,7 @@
             public static final boolean SystemUIHandshake = false;
             public static final boolean TimeSystemCalls = false;
             public static final boolean Memory = false;
+            public static final boolean Search = false;
         }
 
         public static class UI {
@@ -70,7 +80,12 @@
         }
     }
 
+    /** XXX: We are going to move almost all of these into a resource once they are nailed down. */
     public static class Values {
+        public static class App {
+            public static int AppWidgetHostId = 1024;
+            public static String Key_SearchAppWidgetId = "searchAppWidgetId";
+        }
         public static class Window {
             // The dark background dim is set behind the empty recents view
             public static final float DarkBackgroundDim = 0.5f;
@@ -85,11 +100,8 @@
             public static final int TaskStackOverscrollRange = 150;
             public static final int FilterStartDelay = 25;
 
-            // The amount to inverse scale the movement if we are overscrolling
-            public static final float TouchOverscrollScaleFactor = 3f;
-
             // The padding will be applied to the smallest dimension, and then applied to all sides
-            public static final float StackPaddingPct = 0.15f;
+            public static final float StackPaddingPct = 0.1f;
             // The overlap height relative to the task height
             public static final float StackOverlapPct = 0.65f;
             // The height of the peek space relative to the stack height
@@ -99,10 +111,5 @@
             // The number of cards we see in the peek space
             public static final int StackPeekNumCards = 3;
         }
-
-        public static class TaskView {
-            public static final boolean AnimateFrontTaskBarOnEnterRecents = true;
-            public static final boolean AnimateFrontTaskBarOnLeavingRecents = true;
-        }
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 71c45f2..b74f6ac 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -17,11 +17,17 @@
 package com.android.systemui.recents;
 
 import android.app.Activity;
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Bundle;
+import android.util.Pair;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.WindowManager;
@@ -32,14 +38,39 @@
 import com.android.systemui.recents.views.RecentsView;
 
 import java.util.ArrayList;
+import java.util.Set;
 
+/** Our special app widget host */
+class RecentsAppWidgetHost extends AppWidgetHost {
+    /* Callbacks to notify when an app package changes */
+    interface RecentsAppWidgetHostCallbacks {
+        public void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidgetInfo);
+    }
+
+    RecentsAppWidgetHostCallbacks mCb;
+
+    public RecentsAppWidgetHost(Context context, int hostId, RecentsAppWidgetHostCallbacks cb) {
+        super(context, hostId);
+        mCb = cb;
+    }
+
+    @Override
+    protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget) {
+        mCb.onProviderChanged(appWidgetId, appWidget);
+    }
+}
 
 /* Activity */
-public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks {
+public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks,
+        RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks {
     FrameLayout mContainerView;
     RecentsView mRecentsView;
     View mEmptyView;
 
+    AppWidgetHost mAppWidgetHost;
+    AppWidgetProviderInfo mSearchAppWidgetInfo;
+    AppWidgetHostView mSearchAppWidgetHostView;
+
     boolean mVisible;
     boolean mTaskLaunched;
 
@@ -48,7 +79,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+            Console.log(Constants.Log.App.SystemUIHandshake,
                     "[RecentsActivity|serviceBroadcast]", action, Console.AnsiRed);
             if (action.equals(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
                 // Try and unfilter and filtered stacks
@@ -102,6 +133,75 @@
         }
     }
 
+    /** Attempts to allocate and bind the search bar app widget */
+    void bindSearchBarAppWidget() {
+        if (Constants.DebugFlags.App.EnableSearchLayout) {
+            RecentsConfiguration config = RecentsConfiguration.getInstance();
+            SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
+
+            // Reset the host view and widget info
+            mSearchAppWidgetHostView = null;
+            mSearchAppWidgetInfo = null;
+
+            // Try and load the app widget id from the settings
+            int appWidgetId = config.searchBarAppWidgetId;
+            if (appWidgetId >= 0) {
+                mSearchAppWidgetInfo = ssp.getAppWidgetInfo(appWidgetId);
+                if (mSearchAppWidgetInfo == null) {
+                    // If there is no actual widget associated with that id, then delete it and
+                    // prepare to bind another app widget in its place
+                    ssp.unbindSearchAppWidget(mAppWidgetHost, appWidgetId);
+                    appWidgetId = -1;
+                }
+                Console.log(Constants.Log.App.SystemUIHandshake,
+                        "[RecentsActivity|onCreate|settings|appWidgetId]",
+                        "Id: " + appWidgetId,
+                        Console.AnsiBlue);
+            }
+
+            // If there is no id, then bind a new search app widget
+            if (appWidgetId < 0) {
+                Pair<Integer, AppWidgetProviderInfo> widgetInfo =
+                        ssp.bindSearchAppWidget(mAppWidgetHost);
+                if (widgetInfo != null) {
+                    Console.log(Constants.Log.App.SystemUIHandshake,
+                            "[RecentsActivity|onCreate|searchWidget]",
+                            "Id: " + widgetInfo.first + " Info: " + widgetInfo.second,
+                            Console.AnsiBlue);
+
+                    // Save the app widget id into the settings
+                    config.updateSearchBarAppWidgetId(this, widgetInfo.first);
+                    mSearchAppWidgetInfo = widgetInfo.second;
+                }
+            }
+        }
+    }
+
+    /** Creates the search bar app widget view */
+    void addSearchBarAppWidgetView() {
+        if (Constants.DebugFlags.App.EnableSearchLayout) {
+            RecentsConfiguration config = RecentsConfiguration.getInstance();
+            int appWidgetId = config.searchBarAppWidgetId;
+            if (appWidgetId >= 0) {
+                Console.log(Constants.Log.App.SystemUIHandshake,
+                        "[RecentsActivity|onCreate|addSearchAppWidgetView]",
+                        "Id: " + appWidgetId,
+                        Console.AnsiBlue);
+                mSearchAppWidgetHostView = mAppWidgetHost.createView(this, appWidgetId,
+                        mSearchAppWidgetInfo);
+                Bundle opts = new Bundle();
+                opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
+                        AppWidgetProviderInfo.WIDGET_CATEGORY_RECENTS);
+                mSearchAppWidgetHostView.updateAppWidgetOptions(opts);
+                // Set the padding to 0 for this search widget
+                mSearchAppWidgetHostView.setPadding(0, 0, 0, 0);
+                mRecentsView.setSearchBar(mSearchAppWidgetHostView);
+            } else {
+                mRecentsView.setSearchBar(null);
+            }
+        }
+    }
+
     /** Dismisses recents if we are already visible and the intent is to toggle the recents view */
     boolean dismissRecentsIfVisible() {
         if (mVisible) {
@@ -117,16 +217,19 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        Console.logDivider(Constants.DebugFlags.App.SystemUIHandshake);
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onCreate]",
+        Console.logDivider(Constants.Log.App.SystemUIHandshake);
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onCreate]",
                 getIntent().getAction() + " visible: " + mVisible, Console.AnsiRed);
-        Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
-                Constants.DebugFlags.App.TimeRecentsStartupKey, "onCreate");
+        Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                Constants.Log.App.TimeRecentsStartupKey, "onCreate");
 
         // Initialize the loader and the configuration
         RecentsTaskLoader.initialize(this);
         RecentsConfiguration.reinitialize(this);
 
+        // Initialize the widget host (the host id is static and does not change)
+        mAppWidgetHost = new RecentsAppWidgetHost(this, Constants.Values.App.AppWidgetHostId, this);
+
         // Create the view hierarchy
         mRecentsView = new RecentsView(this);
         mRecentsView.setCallbacks(this);
@@ -145,6 +248,11 @@
 
         // Update the recent tasks
         updateRecentsTasks(getIntent());
+
+        // Bind the search app widget when we first start up
+        bindSearchBarAppWidget();
+        // Add the search bar layout
+        addSearchBarAppWidgetView();
     }
 
     @Override
@@ -153,11 +261,11 @@
         // Reset the task launched flag if we encounter an onNewIntent() before onStop()
         mTaskLaunched = false;
 
-        Console.logDivider(Constants.DebugFlags.App.SystemUIHandshake);
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onNewIntent]",
+        Console.logDivider(Constants.Log.App.SystemUIHandshake);
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onNewIntent]",
                 intent.getAction() + " visible: " + mVisible, Console.AnsiRed);
-        Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
-                Constants.DebugFlags.App.TimeRecentsStartupKey, "onNewIntent");
+        Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                Constants.Log.App.TimeRecentsStartupKey, "onNewIntent");
 
         // Initialize the loader and the configuration
         RecentsTaskLoader.initialize(this);
@@ -165,26 +273,30 @@
 
         // Update the recent tasks
         updateRecentsTasks(intent);
+
+        // Don't attempt to rebind the search bar widget, but just add the search bar layout
+        addSearchBarAppWidgetView();
     }
 
     @Override
     protected void onStart() {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onStart]", "",
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onStart]", "",
                 Console.AnsiRed);
         super.onStart();
+        mAppWidgetHost.startListening();
         mVisible = true;
     }
 
     @Override
     protected void onResume() {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onResume]", "",
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onResume]", "",
                 Console.AnsiRed);
         super.onResume();
     }
 
     @Override
     public void onAttachedToWindow() {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+        Console.log(Constants.Log.App.SystemUIHandshake,
                 "[RecentsActivity|onAttachedToWindow]", "",
                 Console.AnsiRed);
         super.onAttachedToWindow();
@@ -198,11 +310,14 @@
         filter = new IntentFilter();
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         registerReceiver(mScreenOffReceiver, filter);
+
+        // Register any broadcast receivers for the task loader
+        RecentsTaskLoader.getInstance().registerReceivers(this, mRecentsView);
     }
 
     @Override
     public void onDetachedFromWindow() {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+        Console.log(Constants.Log.App.SystemUIHandshake,
                 "[RecentsActivity|onDetachedFromWindow]", "",
                 Console.AnsiRed);
         super.onDetachedFromWindow();
@@ -210,28 +325,30 @@
         // Unregister any broadcast receivers we have registered
         unregisterReceiver(mServiceBroadcastReceiver);
         unregisterReceiver(mScreenOffReceiver);
+        RecentsTaskLoader.getInstance().unregisterReceivers();
     }
 
     @Override
     protected void onPause() {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onPause]", "",
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onPause]", "",
                 Console.AnsiRed);
         super.onPause();
     }
 
     @Override
     protected void onStop() {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onStop]", "",
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onStop]", "",
                 Console.AnsiRed);
         super.onStop();
 
+        mAppWidgetHost.stopListening();
         mVisible = false;
         mTaskLaunched = false;
     }
 
     @Override
     protected void onDestroy() {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onDestroy]", "",
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onDestroy]", "",
                 Console.AnsiRed);
         super.onDestroy();
     }
@@ -265,4 +382,18 @@
     public void onTaskLaunching() {
         mTaskLaunched = true;
     }
+
+    @Override
+    public void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidgetInfo) {
+        RecentsConfiguration config = RecentsConfiguration.getInstance();
+        SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
+        if (appWidgetId > -1 && appWidgetId == config.searchBarAppWidgetId) {
+            // The search provider may have changed, so just delete the old widget and bind it again
+            ssp.unbindSearchAppWidget(mAppWidgetHost, appWidgetId);
+            config.updateSearchBarAppWidgetId(this, -1);
+            // Load the widget again
+            bindSearchBarAppWidget();
+            addSearchBarAppWidgetView();
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index d54df13..9afc1cb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -17,11 +17,14 @@
 package com.android.systemui.recents;
 
 import android.content.Context;
+import android.content.SharedPreferences;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import com.android.systemui.R;
 
 
@@ -35,17 +38,32 @@
     public Rect systemInsets = new Rect();
     public Rect displayRect = new Rect();
 
+    boolean isLandscape;
+    boolean transposeSearchLayoutWithOrientation;
+    int searchBarAppWidgetId = -1;
+
     public float animationPxMovementPerSecond;
 
+    public Interpolator defaultBezierInterpolator;
+
     public int filteringCurrentViewsMinAnimDuration;
     public int filteringNewViewsMinAnimDuration;
     public int taskBarEnterAnimDuration;
+    public int taskBarExitAnimDuration;
     public int taskStackScrollDismissInfoPaneDistance;
     public int taskStackMaxDim;
     public int taskViewInfoPaneAnimDuration;
+    public int taskViewRemoveAnimDuration;
+    public int taskViewRemoveAnimTranslationXPx;
+    public int taskViewTranslationZMinPx;
+    public int taskViewTranslationZIncrementPx;
     public int taskViewRoundedCornerRadiusPx;
     public int searchBarSpaceHeightPx;
-    public int searchBarSpaceEdgeMarginsPx;
+
+    public int taskBarViewDefaultBackgroundColor;
+    public int taskBarViewDefaultTextColor;
+    public int taskBarViewLightTextColor;
+    public int taskBarViewDarkTextColor;
 
     public boolean launchedWithThumbnailAnimation;
 
@@ -72,9 +90,11 @@
         DisplayMetrics dm = res.getDisplayMetrics();
         mDisplayMetrics = dm;
 
-        boolean isLandscape = res.getConfiguration().orientation ==
+        isLandscape = res.getConfiguration().orientation ==
                 Configuration.ORIENTATION_LANDSCAPE;
-        Console.log(Constants.DebugFlags.UI.MeasureAndLayout,
+        transposeSearchLayoutWithOrientation =
+                res.getBoolean(R.bool.recents_transpose_search_layout_with_orientation);
+        Console.log(Constants.Log.UI.MeasureAndLayout,
                 "[RecentsConfiguration|orientation]", isLandscape ? "Landscape" : "Portrait",
                 Console.AnsiGreen);
 
@@ -87,16 +107,39 @@
                 res.getInteger(R.integer.recents_filter_animate_new_views_min_duration);
         taskBarEnterAnimDuration =
                 res.getInteger(R.integer.recents_animate_task_bar_enter_duration);
+        taskBarExitAnimDuration =
+                res.getInteger(R.integer.recents_animate_task_bar_exit_duration);
         taskStackScrollDismissInfoPaneDistance = res.getDimensionPixelSize(
                 R.dimen.recents_task_stack_scroll_dismiss_info_pane_distance);
         taskStackMaxDim = res.getInteger(R.integer.recents_max_task_stack_view_dim);
         taskViewInfoPaneAnimDuration =
                 res.getInteger(R.integer.recents_animate_task_view_info_pane_duration);
+        taskViewRemoveAnimDuration =
+                res.getInteger(R.integer.recents_animate_task_view_remove_duration);
+        taskViewRemoveAnimTranslationXPx =
+                res.getDimensionPixelSize(R.dimen.recents_task_view_remove_anim_translation_x);
         taskViewRoundedCornerRadiusPx =
                 res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
+        taskViewTranslationZMinPx = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
+        taskViewTranslationZIncrementPx =
+                res.getDimensionPixelSize(R.dimen.recents_task_view_z_increment);
         searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height);
-        searchBarSpaceEdgeMarginsPx =
-                res.getDimensionPixelSize(R.dimen.recents_search_bar_space_edge_margins);
+
+        taskBarViewDefaultBackgroundColor =
+                res.getColor(R.color.recents_task_bar_default_background_color);
+        taskBarViewDefaultTextColor =
+                res.getColor(R.color.recents_task_bar_default_text_color);
+        taskBarViewLightTextColor =
+                res.getColor(R.color.recents_task_bar_light_text_color);
+        taskBarViewDarkTextColor =
+                res.getColor(R.color.recents_task_bar_dark_text_color);
+
+        defaultBezierInterpolator = AnimationUtils.loadInterpolator(context,
+                        com.android.internal.R.interpolator.fast_out_slow_in);
+
+        // Update the search widget id
+        SharedPreferences settings = context.getSharedPreferences(context.getPackageName(), 0);
+        searchBarAppWidgetId = settings.getInt(Constants.Values.App.Key_SearchAppWidgetId, -1);
     }
 
     /** Updates the system insets */
@@ -104,24 +147,57 @@
         systemInsets.set(insets);
     }
 
-    /** Returns the search bar bounds in the specified orientation */
-    public void getSearchBarBounds(int width, int height,
-                                   Rect searchBarSpaceBounds, Rect searchBarBounds) {
+    /** Updates the search bar app widget */
+    public void updateSearchBarAppWidgetId(Context context, int appWidgetId) {
+        searchBarAppWidgetId = appWidgetId;
+        SharedPreferences settings = context.getSharedPreferences(context.getPackageName(), 0);
+        settings.edit().putInt(Constants.Values.App.Key_SearchAppWidgetId,
+                appWidgetId).apply();
+    }
+
+    /** Returns whether the search bar app widget exists */
+    public boolean hasSearchBarAppWidget() {
+        return searchBarAppWidgetId >= 0;
+    }
+
+    /**
+     * Returns the task stack bounds in the current orientation. These bounds do not account for
+     * the system insets.
+     */
+    public void getTaskStackBounds(int width, int height, Rect taskStackBounds) {
+        if (hasSearchBarAppWidget()) {
+            Rect searchBarBounds = new Rect();
+            getSearchBarBounds(width, height, searchBarBounds);
+            if (isLandscape && transposeSearchLayoutWithOrientation) {
+                // In landscape, the search bar appears on the left, so shift the task rect right
+                taskStackBounds.set(searchBarBounds.width(), 0, width, height);
+            } else {
+                // In portrait, the search bar appears on the top, so shift the task rect below
+                taskStackBounds.set(0, searchBarBounds.height(), width, height);
+            }
+        } else {
+            taskStackBounds.set(0, 0, width, height);
+        }
+    }
+
+    /**
+     * Returns the search bar bounds in the current orientation.  These bounds do not account for
+     * the system insets.
+     */
+    public void getSearchBarBounds(int width, int height, Rect searchBarSpaceBounds) {
         // Return empty rects if search is not enabled
-        if (!Constants.DebugFlags.App.EnableSearchButton) {
+        if (!Constants.DebugFlags.App.EnableSearchLayout) {
             searchBarSpaceBounds.set(0, 0, 0, 0);
-            searchBarBounds.set(0, 0, 0, 0);
             return;
         }
 
-        // Calculate the search bar bounds, and account for the system insets
-        int edgeMarginPx = searchBarSpaceEdgeMarginsPx;
-        int availableWidth = width - systemInsets.left - systemInsets.right;
-        searchBarSpaceBounds.set(0, 0, availableWidth, 2 * edgeMarginPx + searchBarSpaceHeightPx);
-
-        // Inset from the search bar space to get the search bar bounds
-        searchBarBounds.set(searchBarSpaceBounds);
-        searchBarBounds.inset(edgeMarginPx, edgeMarginPx);
+        if (isLandscape && transposeSearchLayoutWithOrientation) {
+            // In landscape, the search bar appears on the left
+            searchBarSpaceBounds.set(0, 0, searchBarSpaceHeightPx, height);
+        } else {
+            // In portrait, the search bar appears on the top
+            searchBarSpaceBounds.set(0, 0, width, searchBarSpaceHeightPx);
+        }
     }
 
     /** Converts from DPs to PXs */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsPackageMonitor.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsPackageMonitor.java
new file mode 100644
index 0000000..4e620b6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsPackageMonitor.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Looper;
+import com.android.internal.content.PackageMonitor;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * The package monitor listens for changes from PackageManager to update the contents of the Recents
+ * list.
+ */
+public class RecentsPackageMonitor extends PackageMonitor {
+    public interface PackageCallbacks {
+        public void onComponentRemoved(Set<ComponentName> cns);
+    }
+
+    PackageCallbacks mCb;
+    List<ActivityManager.RecentTaskInfo> mTasks;
+    SystemServicesProxy mSsp;
+
+    public RecentsPackageMonitor(Context context) {
+        mSsp = new SystemServicesProxy(context);
+    }
+
+    /** Registers the broadcast receivers with the specified callbacks. */
+    public void register(Context context, PackageCallbacks cb) {
+        mCb = cb;
+        register(context, Looper.getMainLooper(), false);
+    }
+
+    /** Unregisters the broadcast receivers. */
+    @Override
+    public void unregister() {
+        super.unregister();
+        mTasks.clear();
+    }
+
+    /** Sets the list of tasks to match against package broadcast changes. */
+    void setTasks(List<ActivityManager.RecentTaskInfo> tasks) {
+        mTasks = tasks;
+    }
+
+    @Override
+    public void onPackageRemoved(String packageName, int uid) {
+        if (mCb == null) return;
+
+        // Identify all the tasks that should be removed as a result of the package being removed.
+        // Using a set to ensure that we callback once per unique component.
+        HashSet<ComponentName> componentsToRemove = new HashSet<ComponentName>();
+        for (ActivityManager.RecentTaskInfo t : mTasks) {
+            ComponentName cn = t.baseIntent.getComponent();
+            if (cn.getPackageName().equals(packageName)) {
+                componentsToRemove.add(cn);
+            }
+        }
+        // Notify our callbacks that the components no longer exist
+        mCb.onComponentRemoved(componentsToRemove);
+    }
+
+    @Override
+    public boolean onPackageChanged(String packageName, int uid, String[] components) {
+        onPackageModified(packageName);
+        return true;
+    }
+
+    @Override
+    public void onPackageModified(String packageName) {
+        if (mCb == null) return;
+
+        // Identify all the tasks that should be removed as a result of the package being removed.
+        // Using a set to ensure that we callback once per unique component.
+        HashSet<ComponentName> componentsKnownToExist = new HashSet<ComponentName>();
+        HashSet<ComponentName> componentsToRemove = new HashSet<ComponentName>();
+        for (ActivityManager.RecentTaskInfo t : mTasks) {
+            ComponentName cn = t.baseIntent.getComponent();
+            if (cn.getPackageName().equals(packageName)) {
+                if (componentsKnownToExist.contains(cn)) {
+                    // If we know that the component still exists in the package, then skip
+                    continue;
+                }
+                if (mSsp.getActivityInfo(cn) != null) {
+                    componentsKnownToExist.add(cn);
+                } else {
+                    componentsToRemove.add(cn);
+                }
+            }
+        }
+        // Notify our callbacks that the components no longer exist
+        mCb.onComponentRemoved(componentsToRemove);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
index 36b761e..837cb34 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
@@ -45,7 +45,7 @@
 
     @Override
     public void handleMessage(Message msg) {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+        Console.log(Constants.Log.App.SystemUIHandshake,
                 "[RecentsService|handleMessage]", msg);
 
         Context context = mContext.get();
@@ -60,39 +60,41 @@
                 Rect windowRect = data.getParcelable(AlternateRecentsComponent.KEY_WINDOW_RECT);
                 Rect systemInsets = data.getParcelable(AlternateRecentsComponent.KEY_SYSTEM_INSETS);
 
+                // NOTE: None of the rects computed below need to be offset for the status bar,
+                // since that is done when we compute the animation itself in the Recents component
+
                 // Create a dummy task stack & compute the rect for the thumbnail to animate to
                 TaskStack stack = new TaskStack(context);
                 TaskStackView tsv = new TaskStackView(context, stack);
                 Bundle replyData = new Bundle();
                 TaskViewTransform transform;
 
-                // Get the search bar bounds so that we can account for its height in the children
-                Rect searchBarSpaceBounds = new Rect();
-                Rect searchBarBounds = new Rect();
+                // Get the task stack and search bar bounds
+                Rect taskStackBounds = new Rect();
                 RecentsConfiguration config = RecentsConfiguration.getInstance();
-                config.getSearchBarBounds(windowRect.width(), windowRect.height(),
-                        searchBarSpaceBounds, searchBarBounds);
+                config.getTaskStackBounds(windowRect.width(), windowRect.height(), taskStackBounds);
 
-                // Calculate the target task rect for when there is one task
+                // Calculate the target task rect for when there is one task.
+
                 // NOTE: Since the nav bar height is already accounted for in the windowRect, don't
-                // pass in a bottom inset
+                // pass in a left or bottom inset
                 stack.addTask(new Task());
-                tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top -
-                        systemInsets.bottom - searchBarSpaceBounds.height(), 0);
+                tsv.computeRects(taskStackBounds.width(), taskStackBounds.height() -
+                        systemInsets.top - systemInsets.bottom, 0, 0);
                 tsv.boundScroll();
                 transform = tsv.getStackTransform(0, tsv.getStackScroll());
-                transform.rect.offset(0, searchBarSpaceBounds.height());
+                transform.rect.offset(taskStackBounds.left, taskStackBounds.top);
                 replyData.putParcelable(AlternateRecentsComponent.KEY_SINGLE_TASK_STACK_RECT,
                         new Rect(transform.rect));
 
-                // Also calculate the target task rect when there are multiple tasks
+                // Also calculate the target task rect when there are multiple tasks.
                 stack.addTask(new Task());
-                tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top -
-                        systemInsets.bottom - searchBarSpaceBounds.height(), 0);
+                tsv.computeRects(taskStackBounds.width(), taskStackBounds.height() -
+                        systemInsets.top - systemInsets.bottom, 0, 0);
                 tsv.setStackScrollRaw(Integer.MAX_VALUE);
                 tsv.boundScroll();
                 transform = tsv.getStackTransform(1, tsv.getStackScroll());
-                transform.rect.offset(0, searchBarSpaceBounds.height());
+                transform.rect.offset(taskStackBounds.left, taskStackBounds.top);
                 replyData.putParcelable(AlternateRecentsComponent.KEY_MULTIPLE_TASK_STACK_RECT,
                         new Rect(transform.rect));
 
@@ -113,10 +115,10 @@
             context.sendBroadcast(intent);
 
             // Time this path
-            Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
-                    Constants.DebugFlags.App.TimeRecentsStartupKey, "receivedToggleRecents");
-            Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
-                    Constants.DebugFlags.App.TimeRecentsLaunchKey, "receivedToggleRecents");
+            Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                    Constants.Log.App.TimeRecentsStartupKey, "receivedToggleRecents");
+            Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+                    Constants.Log.App.TimeRecentsLaunchKey, "receivedToggleRecents");
         }
     }
 }
@@ -129,31 +131,31 @@
 
     @Override
     public void onCreate() {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onCreate]");
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onCreate]");
         super.onCreate();
     }
 
     @Override
     public IBinder onBind(Intent intent) {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onBind]");
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onBind]");
         return mSystemUIMessenger.getBinder();
     }
 
     @Override
     public boolean onUnbind(Intent intent) {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onUnbind]");
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onUnbind]");
         return super.onUnbind(intent);
     }
 
     @Override
     public void onRebind(Intent intent) {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onRebind]");
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onRebind]");
         super.onRebind(intent);
     }
 
     @Override
     public void onDestroy() {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onDestroy]");
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onDestroy]");
         super.onDestroy();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index 52bba4a..1ca0476 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -35,7 +35,6 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
@@ -51,7 +50,7 @@
 
     /** Adds a new task to the load queue */
     void addTask(Task t, boolean forceLoad) {
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "  [TaskResourceLoadQueue|addTask]");
+        Console.log(Constants.Log.App.TaskDataLoader, "  [TaskResourceLoadQueue|addTask]");
         if (!mQueue.contains(t)) {
             mQueue.add(t);
         }
@@ -68,7 +67,7 @@
      * force reloaded.
      */
     Pair<Task, Boolean> nextTask() {
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "  [TaskResourceLoadQueue|nextTask]");
+        Console.log(Constants.Log.App.TaskDataLoader, "  [TaskResourceLoadQueue|nextTask]");
         Task task = mQueue.poll();
         Boolean forceLoadTask = null;
         if (task != null) {
@@ -82,14 +81,14 @@
 
     /** Removes a task from the load queue */
     void removeTask(Task t) {
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "  [TaskResourceLoadQueue|removeTask]");
+        Console.log(Constants.Log.App.TaskDataLoader, "  [TaskResourceLoadQueue|removeTask]");
         mQueue.remove(t);
         mForceLoadSet.remove(t.key);
     }
 
     /** Clears all the tasks from the load queue */
     void clearTasks() {
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "  [TaskResourceLoadQueue|clearTasks]");
+        Console.log(Constants.Log.App.TaskDataLoader, "  [TaskResourceLoadQueue|clearTasks]");
         mQueue.clear();
         mForceLoadSet.clear();
     }
@@ -132,7 +131,7 @@
 
     /** Restarts the loader thread */
     void start(Context context) {
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "[TaskResourceLoader|start]");
+        Console.log(Constants.Log.App.TaskDataLoader, "[TaskResourceLoader|start]");
         mContext = context;
         mCancelled = false;
         mSystemServicesProxy = new SystemServicesProxy(context);
@@ -144,7 +143,7 @@
 
     /** Requests the loader thread to stop after the current iteration */
     void stop() {
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "[TaskResourceLoader|stop]");
+        Console.log(Constants.Log.App.TaskDataLoader, "[TaskResourceLoader|stop]");
         // Mark as cancelled for the thread to pick up
         mCancelled = true;
         mSystemServicesProxy = null;
@@ -158,10 +157,10 @@
     @Override
     public void run() {
         while (true) {
-            Console.log(Constants.DebugFlags.App.TaskDataLoader,
+            Console.log(Constants.Log.App.TaskDataLoader,
                     "[TaskResourceLoader|run|" + Thread.currentThread().getId() + "]");
             if (mCancelled) {
-                Console.log(Constants.DebugFlags.App.TaskDataLoader,
+                Console.log(Constants.Log.App.TaskDataLoader,
                         "[TaskResourceLoader|cancel|" + Thread.currentThread().getId() + "]");
                 // We have to unset the context here, since the background thread may be using it
                 // when we call stop()
@@ -169,7 +168,7 @@
                 // If we are cancelled, then wait until we are started again
                 synchronized(mLoadThread) {
                     try {
-                        Console.log(Constants.DebugFlags.App.TaskDataLoader,
+                        Console.log(Constants.Log.App.TaskDataLoader,
                                 "[TaskResourceLoader|waitOnLoadThreadCancelled]");
                         mLoadThread.wait();
                     } catch (InterruptedException ie) {
@@ -186,7 +185,7 @@
                 if (t != null) {
                     Drawable loadIcon = mApplicationIconCache.get(t.key);
                     Bitmap loadThumbnail = mThumbnailCache.get(t.key);
-                    Console.log(Constants.DebugFlags.App.TaskDataLoader,
+                    Console.log(Constants.Log.App.TaskDataLoader,
                             "  [TaskResourceLoader|load]",
                             t + " icon: " + loadIcon + " thumbnail: " + loadThumbnail +
                                     " forceLoad: " + forceLoadTask);
@@ -197,7 +196,7 @@
                         Drawable icon = ssp.getActivityIcon(info, t.userId);
                         if (!mCancelled) {
                             if (icon != null) {
-                                Console.log(Constants.DebugFlags.App.TaskDataLoader,
+                                Console.log(Constants.Log.App.TaskDataLoader,
                                         "    [TaskResourceLoader|loadIcon]",
                                         icon);
                                 loadIcon = icon;
@@ -210,7 +209,7 @@
                         Bitmap thumbnail = ssp.getTaskThumbnail(t.key.id);
                         if (!mCancelled) {
                             if (thumbnail != null) {
-                                Console.log(Constants.DebugFlags.App.TaskDataLoader,
+                                Console.log(Constants.Log.App.TaskDataLoader,
                                         "    [TaskResourceLoader|loadThumbnail]",
                                         thumbnail);
                                 thumbnail.setHasAlpha(false);
@@ -240,7 +239,7 @@
                 if (!mCancelled && mLoadQueue.isEmpty()) {
                     synchronized(mLoadQueue) {
                         try {
-                            Console.log(Constants.DebugFlags.App.TaskDataLoader,
+                            Console.log(Constants.Log.App.TaskDataLoader,
                                     "[TaskResourceLoader|waitOnLoadQueue]");
                             mWaitingOnLoadQueue = true;
                             mLoadQueue.wait();
@@ -300,6 +299,8 @@
     TaskResourceLoadQueue mLoadQueue;
     TaskResourceLoader mLoader;
 
+    RecentsPackageMonitor mPackageMonitor;
+
     int mMaxThumbnailCacheSize;
     int mMaxIconCacheSize;
 
@@ -319,12 +320,13 @@
         int thumbnailCacheSize = Constants.DebugFlags.App.DisableBackgroundCache ? 1 :
                 mMaxThumbnailCacheSize;
 
-        Console.log(Constants.DebugFlags.App.TaskDataLoader,
+        Console.log(Constants.Log.App.TaskDataLoader,
                 "[RecentsTaskLoader|init]", "thumbnailCache: " + thumbnailCacheSize +
                 " iconCache: " + iconCacheSize);
 
         // Initialize the proxy, cache and loaders
         mSystemServicesProxy = new SystemServicesProxy(context);
+        mPackageMonitor = new RecentsPackageMonitor(context);
         mLoadQueue = new TaskResourceLoadQueue();
         mApplicationIconCache = new DrawableLruCache(iconCacheSize);
         mThumbnailCache = new BitmapLruCache(thumbnailCacheSize);
@@ -336,7 +338,7 @@
         mDefaultThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
         mDefaultThumbnail.eraseColor(0x00000000);
         mDefaultApplicationIcon = new BitmapDrawable(context.getResources(), icon);
-        Console.log(Constants.DebugFlags.App.TaskDataLoader,
+        Console.log(Constants.Log.App.TaskDataLoader,
                 "[RecentsTaskLoader|defaultBitmaps]",
                 "icon: " + mDefaultApplicationIcon + " thumbnail: " + mDefaultThumbnail, Console.AnsiRed);
     }
@@ -359,36 +361,19 @@
         return mSystemServicesProxy;
     }
 
-    private List<ActivityManager.RecentTaskInfo> getRecentTasks(Context context) {
+    private List<ActivityManager.RecentTaskInfo> getRecentTasks() {
         long t1 = System.currentTimeMillis();
 
         SystemServicesProxy ssp = mSystemServicesProxy;
         List<ActivityManager.RecentTaskInfo> tasks =
                 ssp.getRecentTasks(25, UserHandle.CURRENT.getIdentifier());
         Collections.reverse(tasks);
-        Console.log(Constants.DebugFlags.App.TimeSystemCalls,
+        Console.log(Constants.Log.App.TimeSystemCalls,
                 "[RecentsTaskLoader|getRecentTasks]",
                 "" + (System.currentTimeMillis() - t1) + "ms");
-        Console.log(Constants.DebugFlags.App.TaskDataLoader,
+        Console.log(Constants.Log.App.TaskDataLoader,
                 "[RecentsTaskLoader|tasks]", "" + tasks.size());
 
-        // Remove home/recents tasks
-        Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
-        while (iter.hasNext()) {
-            ActivityManager.RecentTaskInfo t = iter.next();
-
-            // Skip tasks in the home stack
-            if (ssp.isInHomeStack(t.persistentId)) {
-                iter.remove();
-                continue;
-            }
-            // Skip tasks from this Recents package
-            if (t.baseIntent.getComponent().getPackageName().equals(context.getPackageName())) {
-                iter.remove();
-                continue;
-            }
-        }
-
         return tasks;
     }
 
@@ -396,7 +381,7 @@
     SpaceNode reload(Context context, int preloadCount) {
         long t1 = System.currentTimeMillis();
 
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|reload]");
+        Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|reload]");
         Resources res = context.getResources();
         ArrayList<Task> tasksToForceLoad = new ArrayList<Task>();
         TaskStack stack = new TaskStack(context);
@@ -405,7 +390,7 @@
 
         // Get the recent tasks
         SystemServicesProxy ssp = mSystemServicesProxy;
-        List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks(context);
+        List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks();
 
         // Add each task to the task stack
         t1 = System.currentTimeMillis();
@@ -415,21 +400,27 @@
             ActivityInfo info = ssp.getActivityInfo(t.baseIntent.getComponent(), t.userId);
             if (info == null) continue;
 
-            String activityLabel = (t.activityLabel == null ? ssp.getActivityLabel(info) :
-                    t.activityLabel.toString());
+            ActivityManager.RecentsActivityValues av = t.activityValues;
+            String activityLabel = null;
             BitmapDrawable activityIcon = null;
-            if (t.activityIcon != null) {
-                activityIcon = new BitmapDrawable(res, t.activityIcon);
+            int activityColor = 0;
+            if (av != null) {
+                activityLabel = (av.label != null ? av.label.toString() :
+                        ssp.getActivityLabel(info));
+                activityIcon = (av.icon != null) ? new BitmapDrawable(res, av.icon) : null;
+                activityColor = av.colorPrimary;
+            } else {
+                activityLabel = ssp.getActivityLabel(info);
             }
             boolean isForemostTask = (i == (taskCount - 1));
 
             // Create a new task
             Task task = new Task(t.persistentId, (t.id > -1), t.baseIntent, activityLabel,
-                    activityIcon, t.userId);
+                    activityIcon, activityColor, t.userId);
 
             // Preload the specified number of apps
             if (i >= (taskCount - preloadCount)) {
-                Console.log(Constants.DebugFlags.App.TaskDataLoader,
+                Console.log(Constants.Log.App.TaskDataLoader,
                         "[RecentsTaskLoader|preloadTask]",
                         "i: " + i + " task: " + t.baseIntent.getComponent().getPackageName());
 
@@ -461,7 +452,7 @@
                     }
                 }
                 if (task.thumbnail == null) {
-                    Console.log(Constants.DebugFlags.App.TaskDataLoader,
+                    Console.log(Constants.Log.App.TaskDataLoader,
                             "[RecentsTaskLoader|loadingTaskThumbnail]");
                     task.thumbnail = ssp.getTaskThumbnail(task.key.id);
                     if (task.thumbnail != null) {
@@ -474,11 +465,11 @@
             }
 
             // Add the task to the stack
-            Console.log(Constants.DebugFlags.App.TaskDataLoader,
+            Console.log(Constants.Log.App.TaskDataLoader,
                 "  [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName());
             stack.addTask(task);
         }
-        Console.log(Constants.DebugFlags.App.TimeSystemCalls,
+        Console.log(Constants.Log.App.TimeSystemCalls,
                 "[RecentsTaskLoader|getAllTaskTopThumbnail]",
                 "" + (System.currentTimeMillis() - t1) + "ms");
 
@@ -486,10 +477,10 @@
         // Get all the stacks
         t1 = System.currentTimeMillis();
         List<ActivityManager.StackInfo> stackInfos = ams.getAllStackInfos();
-        Console.log(Constants.DebugFlags.App.TimeSystemCalls, "[RecentsTaskLoader|getAllStackInfos]", "" + (System.currentTimeMillis() - t1) + "ms");
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|stacks]", "" + tasks.size());
+        Console.log(Constants.Log.App.TimeSystemCalls, "[RecentsTaskLoader|getAllStackInfos]", "" + (System.currentTimeMillis() - t1) + "ms");
+        Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|stacks]", "" + tasks.size());
         for (ActivityManager.StackInfo s : stackInfos) {
-            Console.log(Constants.DebugFlags.App.TaskDataLoader, "  [RecentsTaskLoader|stack]", s.toString());
+            Console.log(Constants.Log.App.TaskDataLoader, "  [RecentsTaskLoader|stack]", s.toString());
             if (stacks.containsKey(s.stackId)) {
                 stacks.get(s.stackId).setRect(s.bounds);
             }
@@ -504,6 +495,9 @@
             mLoadQueue.addTask(t, true);
         }
 
+        // Update the package monitor with the list of packages to listen for
+        mPackageMonitor.setTasks(tasks);
+
         return root;
     }
 
@@ -512,7 +506,7 @@
         Drawable applicationIcon = mApplicationIconCache.get(t.key);
         Bitmap thumbnail = mThumbnailCache.get(t.key);
 
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|loadTask]",
+        Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|loadTask]",
                 t + " applicationIcon: " + applicationIcon + " thumbnail: " + thumbnail +
                         " thumbnailCacheSize: " + mThumbnailCache.size());
 
@@ -533,7 +527,7 @@
 
     /** Releases the task resource data back into the pool. */
     public void unloadTaskData(Task t) {
-        Console.log(Constants.DebugFlags.App.TaskDataLoader,
+        Console.log(Constants.Log.App.TaskDataLoader,
                 "[RecentsTaskLoader|unloadTask]", t +
                 " thumbnailCacheSize: " + mThumbnailCache.size());
 
@@ -542,25 +536,42 @@
     }
 
     /** Completely removes the resource data from the pool. */
-    public void deleteTaskData(Task t) {
-        Console.log(Constants.DebugFlags.App.TaskDataLoader,
+    public void deleteTaskData(Task t, boolean notifyTaskDataUnloaded) {
+        Console.log(Constants.Log.App.TaskDataLoader,
                 "[RecentsTaskLoader|deleteTask]", t);
 
         mLoadQueue.removeTask(t);
         mThumbnailCache.remove(t.key);
         mApplicationIconCache.remove(t.key);
-        t.notifyTaskDataUnloaded(mDefaultThumbnail, mDefaultApplicationIcon);
+        if (notifyTaskDataUnloaded) {
+            t.notifyTaskDataUnloaded(mDefaultThumbnail, mDefaultApplicationIcon);
+        }
     }
 
     /** Stops the task loader and clears all pending tasks */
     void stopLoader() {
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|stopLoader]");
+        Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|stopLoader]");
         mLoader.stop();
         mLoadQueue.clearTasks();
     }
 
+    /** Registers any broadcast receivers. */
+    public void registerReceivers(Context context, RecentsPackageMonitor.PackageCallbacks cb) {
+        // Register the broadcast receiver to handle messages related to packages being added/removed
+        mPackageMonitor.register(context, cb);
+    }
+
+    /** Unregisters any broadcast receivers. */
+    public void unregisterReceivers() {
+        mPackageMonitor.unregister();
+    }
+
+    /**
+     * Handles signals from the system, trimming memory when requested to prevent us from running
+     * out of memory.
+     */
     void onTrimMemory(int level) {
-        Console.log(Constants.DebugFlags.App.Memory, "[RecentsTaskLoader|onTrimMemory]",
+        Console.log(Constants.Log.App.Memory, "[RecentsTaskLoader|onTrimMemory]",
                 Console.trimMemoryLevelToString(level));
 
         switch (level) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
index 33ac0a8..8d82883 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -20,7 +20,9 @@
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
 import android.app.SearchManager;
-import android.content.ActivityNotFoundException;
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -28,17 +30,16 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
-import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.text.TextUtils;
-import android.util.Log;
+import android.util.Pair;
 
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Random;
 
@@ -48,22 +49,31 @@
  */
 public class SystemServicesProxy {
     ActivityManager mAm;
+    AppWidgetManager mAwm;
     PackageManager mPm;
     IPackageManager mIpm;
     UserManager mUm;
     SearchManager mSm;
-    String mPackage;
+    String mRecentsPackage;
+    ComponentName mAssistComponent;
 
     Bitmap mDummyIcon;
 
     /** Private constructor */
     public SystemServicesProxy(Context context) {
         mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        mAwm = AppWidgetManager.getInstance(context);
         mPm = context.getPackageManager();
         mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
         mIpm = AppGlobals.getPackageManager();
         mSm = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE);
-        mPackage = context.getPackageName();
+        mRecentsPackage = context.getPackageName();
+
+        // Resolve the assist intent
+        Intent assist = mSm.getAssistIntent(context, false);
+        if (assist != null) {
+            mAssistComponent = assist.getComponent();
+        }
 
         if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
             // Create a dummy icon
@@ -73,14 +83,14 @@
     }
 
     /** Returns a list of the recents tasks */
-    public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
+    public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numLatestTasks, int userId) {
         if (mAm == null) return null;
 
         // If we are mocking, then create some recent tasks
         if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
             ArrayList<ActivityManager.RecentTaskInfo> tasks =
                     new ArrayList<ActivityManager.RecentTaskInfo>();
-            int count = Math.min(numTasks, Constants.DebugFlags.App.SystemServicesProxyMockTaskCount);
+            int count = Math.min(numLatestTasks, Constants.DebugFlags.App.SystemServicesProxyMockTaskCount);
             for (int i = 0; i < count; i++) {
                 // Create a dummy component name
                 int packageIndex = i % Constants.DebugFlags.App.SystemServicesProxyMockPackageCount;
@@ -91,19 +101,56 @@
                 rti.id = rti.persistentId = i;
                 rti.baseIntent = new Intent();
                 rti.baseIntent.setComponent(cn);
-                rti.description = rti.activityLabel = "" + i + " - " +
+                rti.activityValues = new ActivityManager.RecentsActivityValues();
+                rti.description = "" + i + " - " +
                         Long.toString(Math.abs(new Random().nextLong()), 36);
                 if (i % 2 == 0) {
-                    rti.activityIcon = Bitmap.createBitmap(mDummyIcon);
+                    rti.activityValues.label = rti.description;
+                    rti.activityValues.icon = Bitmap.createBitmap(mDummyIcon);
+                    rti.activityValues.colorPrimary = new Random().nextInt();
                 }
                 tasks.add(rti);
             }
             return tasks;
         }
 
-        return mAm.getRecentTasksForUser(numTasks,
+        // Remove home/recents/excluded tasks
+        int minNumTasksToQuery = 10;
+        int numTasksToQuery = Math.max(minNumTasksToQuery, numLatestTasks);
+        List<ActivityManager.RecentTaskInfo> tasks = mAm.getRecentTasksForUser(numTasksToQuery,
                 ActivityManager.RECENT_IGNORE_UNAVAILABLE |
-                ActivityManager.RECENT_INCLUDE_PROFILES, userId);
+                ActivityManager.RECENT_INCLUDE_PROFILES |
+                ActivityManager.RECENT_WITH_EXCLUDED, userId);
+        boolean isFirstValidTask = true;
+        Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
+        while (iter.hasNext()) {
+            ActivityManager.RecentTaskInfo t = iter.next();
+
+            // NOTE: The order of these checks happens in the expected order of the traversal of the
+            // tasks
+
+            // Skip tasks from this Recents package
+            if (t.baseIntent.getComponent().getPackageName().equals(mRecentsPackage)) {
+                iter.remove();
+                continue;
+            }
+            // Check the first non-recents task, include this task even if it is marked as excluded
+            // from recents.  In other words, only remove excluded tasks if it is not the first task
+            boolean isExcluded = (t.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+                    == Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+            if (isExcluded && !isFirstValidTask) {
+                iter.remove();
+                continue;
+            }
+            isFirstValidTask = false;
+            // Skip tasks in the home stack
+            if (isInHomeStack(t.persistentId)) {
+                iter.remove();
+                continue;
+            }
+        }
+
+        return tasks.subList(0, Math.min(tasks.size(), numLatestTasks));
     }
 
     /** Returns a list of the running tasks */
@@ -152,22 +199,23 @@
     }
 
     /** Removes the task and kills the process */
-    public void removeTask(int taskId) {
+    public void removeTask(int taskId, boolean isDocument) {
         if (mAm == null) return;
         if (Constants.DebugFlags.App.EnableSystemServicesProxy) return;
 
-        mAm.removeTask(taskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
+        // Remove the task, and only kill the process if it is not a document
+        mAm.removeTask(taskId, isDocument ? 0 : ActivityManager.REMOVE_TASK_KILL_PROCESS);
     }
 
     /**
      * Returns the activity info for a given component name.
      * 
-     * @param ComponentName The component name of the activity.
+     * @param cn The component name of the activity.
      * @param userId The userId of the user that this is for.
      */
     public ActivityInfo getActivityInfo(ComponentName cn, int userId) {
         if (mIpm == null) return null;
-        if (Constants.DebugFlags.App.EnableSystemServicesProxy) return null;
+        if (Constants.DebugFlags.App.EnableSystemServicesProxy) return new ActivityInfo();
 
         try {
             return mIpm.getActivityInfo(cn, PackageManager.GET_META_DATA, userId);
@@ -177,6 +225,23 @@
         }
     }
 
+    /**
+     * Returns the activity info for a given component name.
+     *
+     * @param cn The component name of the activity.
+     */
+    public ActivityInfo getActivityInfo(ComponentName cn) {
+        if (mPm == null) return null;
+        if (Constants.DebugFlags.App.EnableSystemServicesProxy) return new ActivityInfo();
+
+        try {
+            return mPm.getActivityInfo(cn, PackageManager.GET_META_DATA);
+        } catch (PackageManager.NameNotFoundException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
     /** Returns the activity label */
     public String getActivityLabel(ActivityInfo info) {
         if (mPm == null) return null;
@@ -208,27 +273,54 @@
         return icon;
     }
 
+    /**
+     * Resolves and binds the search app widget that is to appear in the recents.
+     */
+    public Pair<Integer, AppWidgetProviderInfo> bindSearchAppWidget(AppWidgetHost host) {
+        if (mAwm == null) return null;
+        if (mAssistComponent == null) return null;
+
+        // Find the first Recents widget from the same package as the global assist activity
+        List<AppWidgetProviderInfo> widgets = mAwm.getInstalledProviders(
+                AppWidgetProviderInfo.WIDGET_CATEGORY_RECENTS);
+        AppWidgetProviderInfo searchWidgetInfo = null;
+        for (AppWidgetProviderInfo info : widgets) {
+            if (info.provider.getPackageName().equals(mAssistComponent.getPackageName())) {
+                searchWidgetInfo = info;
+                break;
+            }
+        }
+
+        // Return early if there is no search widget
+        if (searchWidgetInfo == null) return null;
+
+        // Allocate a new widget id and try and bind the app widget (if that fails, then just skip)
+        int searchWidgetId = host.allocateAppWidgetId();
+        Bundle opts = new Bundle();
+        opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
+                AppWidgetProviderInfo.WIDGET_CATEGORY_RECENTS);
+        if (!mAwm.bindAppWidgetIdIfAllowed(searchWidgetId, searchWidgetInfo.provider, opts)) {
+            return null;
+        }
+        return new Pair<Integer, AppWidgetProviderInfo>(searchWidgetId, searchWidgetInfo);
+    }
 
     /**
-     * Composes an intent to launch the global search activity.
+     * Returns the app widget info for the specified app widget id.
      */
-    public Intent getGlobalSearchIntent(Rect sourceBounds) {
-        if (mSm == null) return null;
+    public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
+        if (mAwm == null) return null;
 
-        // Try and get the global search activity
-        ComponentName globalSearchActivity = mSm.getGlobalSearchActivity();
-        if (globalSearchActivity == null) return null;
+        return mAwm.getAppWidgetInfo(appWidgetId);
+    }
 
-        // Bundle the source of the search
-        Bundle appSearchData = new Bundle();
-        appSearchData.putString("source", mPackage);
+    /**
+     * Destroys the specified app widget.
+     */
+    public void unbindSearchAppWidget(AppWidgetHost host, int appWidgetId) {
+        if (mAwm == null) return;
 
-        // Compose the intent and Start the search activity
-        Intent intent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.setComponent(globalSearchActivity);
-        intent.putExtra(SearchManager.APP_DATA, appSearchData);
-        intent.setSourceBounds(sourceBounds);
-        return intent;
+        // Delete the app widget
+        host.deleteAppWidgetId(appWidgetId);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
index 4a1b3b2..46e6ee9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
@@ -16,7 +16,9 @@
 
 package com.android.systemui.recents;
 
+import android.graphics.Color;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 
 /* Common code */
 public class Utilities {
@@ -46,4 +48,22 @@
             r.offset(cx, cy);
         }
     }
+
+    /** Calculates the luminance-preserved greyscale of a given color. */
+    private static int colorToGreyscale(int color) {
+        return Math.round(0.2126f * Color.red(color) + 0.7152f * Color.green(color) +
+                0.0722f * Color.blue(color));
+    }
+
+    /** Returns the ideal color to draw on top of a specified background color. */
+    public static int getIdealColorForBackgroundColor(int color, int lightRes, int darkRes) {
+        int greyscale = colorToGreyscale(color);
+        return (greyscale < 128) ? lightRes : darkRes;
+    }
+    /** Returns the ideal drawable to draw on top of a specified background color. */
+    public static Drawable getIdealResourceForBackgroundColor(int color, Drawable lightRes,
+                                                           Drawable darkRes) {
+        int greyscale = colorToGreyscale(color);
+        return (greyscale < 128) ? lightRes : darkRes;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 1566a49..47a506c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -72,6 +72,7 @@
     public Drawable applicationIcon;
     public Drawable activityIcon;
     public String activityLabel;
+    public int colorPrimary;
     public Bitmap thumbnail;
     public boolean isActive;
     public int userId;
@@ -83,10 +84,11 @@
     }
 
     public Task(int id, boolean isActive, Intent intent, String activityTitle,
-                BitmapDrawable activityIcon, int userId) {
+                BitmapDrawable activityIcon, int colorPrimary, int userId) {
         this.key = new TaskKey(id, intent, userId);
         this.activityLabel = activityTitle;
         this.activityIcon = activityIcon;
+        this.colorPrimary = colorPrimary;
         this.isActive = isActive;
         this.userId = userId;
     }
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 a04cd3e..a6d7e67 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -19,6 +19,7 @@
 import android.app.ActivityOptions;
 import android.app.TaskStackBuilder;
 import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
@@ -27,28 +28,28 @@
 import android.net.Uri;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.FrameLayout;
-import android.widget.TextView;
 import com.android.systemui.recents.Console;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.RecentsPackageMonitor;
 import com.android.systemui.recents.RecentsTaskLoader;
 import com.android.systemui.recents.model.SpaceNode;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.R;
 
 import java.util.ArrayList;
+import java.util.Set;
 
 
 /**
  * This view is the the top level layout that contains TaskStacks (which are laid out according
  * to their SpaceNode bounds.
  */
-public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks {
+public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks,
+        RecentsPackageMonitor.PackageCallbacks {
 
     /** The RecentsView callbacks */
     public interface RecentsViewCallbacks {
@@ -57,6 +58,8 @@
 
     // The space partitioning root of this container
     SpaceNode mBSP;
+    // Whether there are any tasks
+    boolean mHasTasks;
     // Search bar view
     View mSearchBar;
     // Recents view callbacks
@@ -80,22 +83,14 @@
         mBSP = n;
 
         // Create and add all the stacks for this partition of space.
-        boolean hasTasks = false;
+        mHasTasks = false;
         removeAllViews();
         ArrayList<TaskStack> stacks = mBSP.getStacks();
         for (TaskStack stack : stacks) {
             TaskStackView stackView = new TaskStackView(getContext(), stack);
             stackView.setCallbacks(this);
             addView(stackView);
-            hasTasks |= (stack.getTaskCount() > 0);
-        }
-
-        // Create the search bar (and hide it if we have no recent tasks)
-        if (Constants.DebugFlags.App.EnableSearchButton) {
-            createSearchBar();
-            if (!hasTasks) {
-                mSearchBar.setVisibility(View.GONE);
-            }
+            mHasTasks |= (stack.getTaskCount() > 0);
         }
     }
 
@@ -130,19 +125,30 @@
         return false;
     }
 
-    /** Creates and adds the search bar */
-    void createSearchBar() {
-        // Create a temporary search bar
-        mSearchBar = mInflater.inflate(R.layout.recents_search_bar, this, false);
-        mSearchBar.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                onSearchTriggered();
+    /** Adds the search bar */
+    public void setSearchBar(View searchBar) {
+        // Create the search bar (and hide it if we have no recent tasks)
+        if (Constants.DebugFlags.App.EnableSearchLayout) {
+            // Remove the previous search bar if one exists
+            if (mSearchBar != null && indexOfChild(mSearchBar) > -1) {
+                removeView(mSearchBar);
             }
-        });
-        addView(mSearchBar);
+            // Add the new search bar
+            if (searchBar != null) {
+                mSearchBar = searchBar;
+                mSearchBar.setVisibility(mHasTasks ? View.VISIBLE : View.GONE);
+                addView(mSearchBar);
+
+                Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsView|setSearchBar]",
+                        "" + (mSearchBar.getVisibility() == View.VISIBLE),
+                        Console.AnsiBlue);
+            }
+        }
     }
 
+    /**
+     * This is called with the full size of the window since we are handling our own insets.
+     */
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int width = MeasureSpec.getSize(widthMeasureSpec);
@@ -150,27 +156,31 @@
         int height = MeasureSpec.getSize(heightMeasureSpec);
         int heightMode = MeasureSpec.getMode(heightMeasureSpec);
 
-        Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[RecentsView|measure]",
+        Console.log(Constants.Log.UI.MeasureAndLayout, "[RecentsView|measure]",
                 "width: " + width + " height: " + height, Console.AnsiGreen);
-        Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
-                Constants.DebugFlags.App.TimeRecentsStartupKey, "RecentsView.onMeasure");
+        Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                Constants.Log.App.TimeRecentsStartupKey, "RecentsView.onMeasure");
 
-        // Get the search bar bounds so that we can account for its height in the children
-        Rect searchBarSpaceBounds = new Rect();
-        Rect searchBarBounds = new Rect();
+        // Get the search bar bounds and measure the search bar layout
         RecentsConfiguration config = RecentsConfiguration.getInstance();
-        config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(),
-                searchBarSpaceBounds, searchBarBounds);
         if (mSearchBar != null) {
-            mSearchBar.measure(MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), widthMode),
-                    MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.height(), heightMode));
+            Rect searchBarSpaceBounds = new Rect();
+            config.getSearchBarBounds(width, height - config.systemInsets.top, searchBarSpaceBounds);
+            mSearchBar.measure(
+                    MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), MeasureSpec.EXACTLY),
+                    MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.height(), MeasureSpec.EXACTLY));
         }
 
-        // We measure our stack views sans the status bar.  It will handle the nav bar itself.
+        // We give the full width of the space, not including the right nav bar insets in landscape,
+        // to the stack view, since we want the tasks to render under the search bar in landscape.
+        // In addition, we give it the full height, not including the top inset or search bar space,
+        // since we want the tasks to render under the navigation buttons in portrait.
+        Rect taskStackBounds = new Rect();
+        config.getTaskStackBounds(width, height, taskStackBounds);
         int childWidth = width - config.systemInsets.right;
-        int childHeight = height - config.systemInsets.top - searchBarSpaceBounds.height();
+        int childHeight = taskStackBounds.height() - config.systemInsets.top;
 
-        // Measure each child
+        // Measure each TaskStackView
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
@@ -183,28 +193,34 @@
         setMeasuredDimension(width, height);
     }
 
+    /**
+     * This is called with the full size of the window since we are handling our own insets.
+     */
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[RecentsView|layout]",
+        Console.log(Constants.Log.UI.MeasureAndLayout, "[RecentsView|layout]",
                 new Rect(left, top, right, bottom) + " changed: " + changed, Console.AnsiGreen);
-        Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
-                Constants.DebugFlags.App.TimeRecentsStartupKey, "RecentsView.onLayout");
+        Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                Constants.Log.App.TimeRecentsStartupKey, "RecentsView.onLayout");
 
-        // Get the search bar bounds so that we can account for its height in the children
-        Rect searchBarSpaceBounds = new Rect();
-        Rect searchBarBounds = new Rect();
+        // Get the search bar bounds so that we lay it out
         RecentsConfiguration config = RecentsConfiguration.getInstance();
-        config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(),
-                searchBarSpaceBounds, searchBarBounds);
         if (mSearchBar != null) {
+            Rect searchBarSpaceBounds = new Rect();
+            config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(), searchBarSpaceBounds);
             mSearchBar.layout(config.systemInsets.left + searchBarSpaceBounds.left,
                     config.systemInsets.top + searchBarSpaceBounds.top,
                     config.systemInsets.left + mSearchBar.getMeasuredWidth(),
                     config.systemInsets.top + mSearchBar.getMeasuredHeight());
         }
 
-        // We offset our stack views by the status bar height.  It will handle the nav bar itself.
-        top += config.systemInsets.top + searchBarSpaceBounds.height();
+        // We offset the stack view by the left inset (if any), but lay it out under the search bar.
+        // In addition, we offset our stack views by the top inset and search bar height, but not
+        // the bottom insets because we want it to render under the navigation buttons.
+        Rect taskStackBounds = new Rect();
+        config.getTaskStackBounds(getMeasuredWidth(), getMeasuredHeight(), taskStackBounds);
+        left += config.systemInsets.left;
+        top += config.systemInsets.top + taskStackBounds.top;
 
         // Layout each child
         // XXX: Based on the space node for that task view
@@ -212,23 +228,22 @@
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
             if (child instanceof TaskStackView && child.getVisibility() != GONE) {
-                int width = child.getMeasuredWidth();
-                int height = child.getMeasuredHeight();
-                child.layout(left, top, left + width, top + height);
+                TaskStackView tsv = (TaskStackView) child;
+                child.layout(left, top, left + tsv.getMeasuredWidth(), top + tsv.getMeasuredHeight());
             }
         }
     }
 
     @Override
     protected void dispatchDraw(Canvas canvas) {
-        Console.log(Constants.DebugFlags.UI.Draw, "[RecentsView|dispatchDraw]", "",
+        Console.log(Constants.Log.UI.Draw, "[RecentsView|dispatchDraw]", "",
                 Console.AnsiPurple);
         super.dispatchDraw(canvas);
     }
 
     @Override
     protected boolean fitSystemWindows(Rect insets) {
-        Console.log(Constants.DebugFlags.UI.MeasureAndLayout,
+        Console.log(Constants.Log.UI.MeasureAndLayout,
                 "[RecentsView|fitSystemWindows]", "insets: " + insets, Console.AnsiGreen);
 
         // Update the configuration with the latest system insets and trigger a relayout
@@ -331,7 +346,7 @@
                     RecentsTaskLoader.getInstance().getSystemServicesProxy()
                             .moveTaskToFront(task.key.id, opts);
                 } else {
-                    // Launch the activity with the desired animation
+                    // Launch the activity anew with the desired animation
                     Intent i = new Intent(task.key.baseIntent);
                     i.setFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
                             | Intent.FLAG_ACTIVITY_TASK_ON_HOME
@@ -346,18 +361,21 @@
                     } catch (ActivityNotFoundException anfe) {
                         Console.logError(getContext(), "Could not start Activity");
                     }
+
+                    // And clean up the old task
+                    onTaskRemoved(task);
                 }
 
-                Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
-                        Constants.DebugFlags.App.TimeRecentsLaunchKey, "startActivity");
+                Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+                        Constants.Log.App.TimeRecentsLaunchKey, "startActivity");
             }
         };
 
-        Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
-                Constants.DebugFlags.App.TimeRecentsLaunchKey, "onTaskLaunched");
+        Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+                Constants.Log.App.TimeRecentsLaunchKey, "onTaskLaunched");
 
         // Launch the app right away if there is no task view, otherwise, animate the icon out first
-        if (tv == null || !Constants.Values.TaskView.AnimateFrontTaskBarOnLeavingRecents) {
+        if (tv == null) {
             post(launchRunnable);
         } else {
             tv.animateOnLeavingRecents(launchRunnable);
@@ -375,22 +393,33 @@
                 .addNextIntentWithParentStack(intent).startActivities();
     }
 
-    public void onSearchTriggered() {
-        // Get the search bar source bounds
-        Rect searchBarSpaceBounds = new Rect();
-        Rect searchBarBounds = new Rect();
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-        config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(),
-                searchBarSpaceBounds, searchBarBounds);
+    @Override
+    public void onTaskRemoved(Task t) {
+        // Remove any stored data from the loader.  We currently don't bother notifying the views
+        // that the data has been unloaded because at the point we call onTaskRemoved(), the views
+        // either don't need to be updated, or have already been removed.
+        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+        loader.deleteTaskData(t, false);
 
-        // Get the search intent and start it
-        Intent searchIntent = RecentsTaskLoader.getInstance().getSystemServicesProxy()
-                .getGlobalSearchIntent(searchBarBounds);
-        if (searchIntent != null) {
-            try {
-                getContext().startActivity(searchIntent);
-            } catch (ActivityNotFoundException anfe) {
-                Console.logError(getContext(), "Could not start Search activity");
+        // Remove the old task from activity manager
+        int flags = t.key.baseIntent.getFlags();
+        boolean isDocument = (flags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) ==
+                Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+        RecentsTaskLoader.getInstance().getSystemServicesProxy().removeTask(t.key.id,
+                isDocument);
+    }
+
+    /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
+
+    @Override
+    public void onComponentRemoved(Set<ComponentName> cns) {
+        // Propagate this event down to each task stack view
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+            if (child instanceof TaskStackView) {
+                TaskStackView stackView = (TaskStackView) child;
+                stackView.onComponentRemoved(cns);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
index 21ef9ff..c34300c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
@@ -178,7 +178,7 @@
     }
 
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        Console.log(Constants.DebugFlags.UI.TouchEvents,
+        Console.log(Constants.Log.UI.TouchEvents,
                 "[SwipeHelper|interceptTouchEvent]",
                 Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
         final int action = ev.getAction();
@@ -291,7 +291,7 @@
     }
 
     public boolean onTouchEvent(MotionEvent ev) {
-        Console.log(Constants.DebugFlags.UI.TouchEvents,
+        Console.log(Constants.Log.UI.TouchEvents,
                 "[SwipeHelper|touchEvent]",
                 Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
index 124f11e..07caa1b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
@@ -16,13 +16,18 @@
 
 package com.android.systemui.recents.views;
 
+import android.animation.ValueAnimator;
 import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
-import android.view.View;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.TextView;
 import com.android.systemui.R;
+import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.Utilities;
 import com.android.systemui.recents.model.Task;
 
 
@@ -30,9 +35,13 @@
 class TaskBarView extends FrameLayout {
     Task mTask;
 
+    ImageView mDismissButton;
     ImageView mApplicationIcon;
     TextView mActivityDescription;
 
+    Drawable mLightDismissDrawable;
+    Drawable mDarkDismissDrawable;
+
     public TaskBarView(Context context) {
         this(context, null);
     }
@@ -47,6 +56,9 @@
 
     public TaskBarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        Resources res = context.getResources();
+        mLightDismissDrawable = res.getDrawable(R.drawable.recents_dismiss_light);
+        mDarkDismissDrawable = res.getDrawable(R.drawable.recents_dismiss_dark);
     }
 
     @Override
@@ -54,10 +66,33 @@
         // Initialize the icon and description views
         mApplicationIcon = (ImageView) findViewById(R.id.application_icon);
         mActivityDescription = (TextView) findViewById(R.id.activity_description);
+        mDismissButton = (ImageView) findViewById(R.id.dismiss_task);
+    }
+
+    /** Synchronizes this bar view's properties with the task's transform */
+    void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
+                                             TaskViewTransform toTransform, int duration) {
+        RecentsConfiguration config = RecentsConfiguration.getInstance();
+        if (duration > 0) {
+            if (animateFromTransform != null) {
+                mDismissButton.setAlpha(animateFromTransform.dismissAlpha);
+            }
+            mDismissButton.animate()
+                    .alpha(toTransform.dismissAlpha)
+                    .setStartDelay(0)
+                    .setDuration(duration)
+                    .setInterpolator(config.defaultBezierInterpolator)
+                    .withLayer()
+                    .start();
+        } else {
+            mDismissButton.setAlpha(toTransform.dismissAlpha);
+        }
+        mDismissButton.invalidate();
     }
 
     /** Binds the bar view to the task */
     void rebindToTask(Task t, boolean animate) {
+        RecentsConfiguration configuration = RecentsConfiguration.getInstance();
         mTask = t;
         // If an activity icon is defined, then we use that as the primary icon to show in the bar,
         // otherwise, we fall back to the application icon
@@ -67,6 +102,18 @@
             mApplicationIcon.setImageDrawable(t.applicationIcon);
         }
         mActivityDescription.setText(t.activityLabel);
+        // Try and apply the system ui tint
+        int tint = t.colorPrimary;
+        if (Constants.DebugFlags.App.EnableTaskBarThemeColors && tint != 0) {
+            setBackgroundColor(tint);
+            mActivityDescription.setTextColor(Utilities.getIdealColorForBackgroundColor(tint,
+                    configuration.taskBarViewLightTextColor, configuration.taskBarViewDarkTextColor));
+            mDismissButton.setImageDrawable(Utilities.getIdealResourceForBackgroundColor(tint,
+                    mLightDismissDrawable, mDarkDismissDrawable));
+        } else {
+            setBackgroundColor(configuration.taskBarViewDefaultBackgroundColor);
+            mActivityDescription.setTextColor(configuration.taskBarViewDefaultTextColor);
+        }
         if (animate) {
             // XXX: Investigate how expensive it will be to create a second bitmap and crossfade
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
index a81d01c..f1c362a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
@@ -20,16 +20,20 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.graphics.Canvas;
 import android.graphics.Path;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.graphics.drawable.TouchFeedbackDrawable;
 import android.util.AttributeSet;
 import android.widget.Button;
 import android.widget.FrameLayout;
 import com.android.systemui.R;
-import com.android.systemui.recents.BakedBezierInterpolator;
+import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.Utilities;
+import com.android.systemui.recents.model.Task;
 
 
 /* The task info view */
@@ -106,7 +110,8 @@
         int duration = Utilities.calculateTranslationAnimationDuration((int) mMaxClipRadius);
         mCircularClipAnimator = ObjectAnimator.ofFloat(this, "circularClipRadius", toRadius);
         mCircularClipAnimator.setDuration(duration);
-        mCircularClipAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE);
+        mCircularClipAnimator.setInterpolator(
+                RecentsConfiguration.getInstance().defaultBezierInterpolator);
         mCircularClipAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
@@ -138,11 +143,30 @@
                 .scaleX(1f)
                 .scaleY(1f)
                 .setDuration(duration)
-                .setInterpolator(BakedBezierInterpolator.INSTANCE)
+                .setInterpolator(RecentsConfiguration.getInstance().defaultBezierInterpolator)
                 .withLayer()
                 .start();
     }
 
+    /** Binds the info view to the task */
+    void rebindToTask(Task t, boolean animate) {
+        RecentsConfiguration configuration = RecentsConfiguration.getInstance();
+        if (Constants.DebugFlags.App.EnableTaskBarThemeColors && t.colorPrimary != 0) {
+            setBackgroundColor(t.colorPrimary);
+            // Workaround: The button currently doesn't support setting a custom background tint
+            // not defined in the theme.  Just lower the alpha on the button to make it blend more
+            // into the background.
+            if (mAppInfoButton.getBackground() instanceof TouchFeedbackDrawable) {
+                TouchFeedbackDrawable d = (TouchFeedbackDrawable) mAppInfoButton.getBackground();
+                if (d != null) {
+                    d.setAlpha(96);
+                }
+            }
+        } else {
+            setBackgroundColor(configuration.taskBarViewDefaultBackgroundColor);
+        }
+    }
+
     @Override
     public void draw(Canvas canvas) {
         int saveCount = 0;
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 a77e61d..b64225e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -18,11 +18,12 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.app.Activity;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.Region;
@@ -36,10 +37,10 @@
 import android.widget.FrameLayout;
 import android.widget.OverScroller;
 import com.android.systemui.R;
-import com.android.systemui.recents.BakedBezierInterpolator;
 import com.android.systemui.recents.Console;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.RecentsPackageMonitor;
 import com.android.systemui.recents.RecentsTaskLoader;
 import com.android.systemui.recents.Utilities;
 import com.android.systemui.recents.model.Task;
@@ -47,17 +48,19 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Set;
 
 
 /* The visual representation of a task stack view */
 public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCallbacks,
         TaskView.TaskViewCallbacks, ViewPool.ViewPoolConsumer<TaskView, Task>,
-        View.OnClickListener, View.OnLongClickListener {
+        View.OnClickListener, View.OnLongClickListener, RecentsPackageMonitor.PackageCallbacks {
 
     /** The TaskView callbacks */
     interface TaskStackViewCallbacks {
         public void onTaskLaunched(TaskStackView stackView, TaskView tv, TaskStack stack, Task t);
         public void onTaskAppInfoLaunched(Task t);
+        public void onTaskRemoved(Task t);
     }
 
     TaskStack mStack;
@@ -110,7 +113,7 @@
         requestSynchronizeStackViewsWithModel(0);
     }
     void requestSynchronizeStackViewsWithModel(int duration) {
-        Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
+        Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
                 "[TaskStackView|requestSynchronize]", "" + duration + "ms", Console.AnsiYellow);
         if (!mStackViewsDirty) {
             invalidate();
@@ -166,6 +169,9 @@
             transform.translationY = (int) (boundedT * overlapHeight - scaleYOffset);
         }
 
+        // Set the alphas
+        transform.dismissAlpha = Math.max(-1f, Math.min(0f, t)) + 1f;
+
         // Update the rect and visibility
         transform.rect.set(mTaskRect);
         if (t < -(numPeekCards + 1)) {
@@ -215,7 +221,7 @@
 
     /** Synchronizes the views with the model */
     void synchronizeStackViewsWithModel() {
-        Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
+        Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
                 "[TaskStackView|synchronizeViewsWithModel]",
                 "mStackViewsDirty: " + mStackViewsDirty, Console.AnsiYellow);
         if (mStackViewsDirty) {
@@ -271,7 +277,7 @@
                 }
             }
 
-            Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
+            Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
                     "  [TaskStackView|viewChildren]", "" + getChildCount());
 
             mStackViewsAnimationDuration = 0;
@@ -334,7 +340,7 @@
         mScrollAnimator = ObjectAnimator.ofInt(this, "stackScroll", curScroll, newScroll);
         mScrollAnimator.setDuration(Utilities.calculateTranslationAnimationDuration(newScroll -
                 curScroll, 250));
-        mScrollAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE);
+        mScrollAnimator.setInterpolator(RecentsConfiguration.getInstance().defaultBezierInterpolator);
         mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
@@ -395,12 +401,20 @@
         return false;
     }
 
-    /** Returns whether the specified scroll is out of bounds */
-    boolean isScrollOutOfBounds(int scroll) {
-        return (scroll < mMinScroll) || (scroll > mMaxScroll);
+
+    /** Returns the amount that the scroll is out of bounds */
+    int getScrollAmountOutOfBounds(int scroll) {
+        if (scroll < mMinScroll) {
+            return mMinScroll - scroll;
+        } else if (scroll > mMaxScroll) {
+            return scroll - mMaxScroll;
+        }
+        return 0;
     }
+
+    /** Returns whether the specified scroll is out of bounds */
     boolean isScrollOutOfBounds() {
-        return isScrollOutOfBounds(getStackScroll());
+        return getScrollAmountOutOfBounds(getStackScroll()) != 0;
     }
 
     /** Updates the min and max virtual scroll bounds */
@@ -421,7 +435,7 @@
         }
 
         // Debug logging
-        if (Constants.DebugFlags.UI.MeasureAndLayout) {
+        if (Constants.Log.UI.MeasureAndLayout) {
             Console.log("  [TaskStack|minScroll] " + mMinScroll);
             Console.log("  [TaskStack|maxScroll] " + mMaxScroll);
         }
@@ -448,7 +462,7 @@
 
     /** Enables the hw layers and increments the hw layer requirement ref count */
     void addHwLayersRefCount(String reason) {
-        Console.log(Constants.DebugFlags.UI.HwLayers,
+        Console.log(Constants.Log.UI.HwLayers,
                 "[TaskStackView|addHwLayersRefCount] refCount: " +
                         mHwLayersRefCount + "->" + (mHwLayersRefCount + 1) + " " + reason);
         if (mHwLayersRefCount == 0) {
@@ -465,7 +479,7 @@
     /** Decrements the hw layer requirement ref count and disables the hw layers when we don't
         need them anymore. */
     void decHwLayersRefCount(String reason) {
-        Console.log(Constants.DebugFlags.UI.HwLayers,
+        Console.log(Constants.Log.UI.HwLayers,
                 "[TaskStackView|decHwLayersRefCount] refCount: " +
                         mHwLayersRefCount + "->" + (mHwLayersRefCount - 1) + " " + reason);
         mHwLayersRefCount--;
@@ -507,7 +521,7 @@
 
     @Override
     public void dispatchDraw(Canvas canvas) {
-        Console.log(Constants.DebugFlags.UI.Draw, "[TaskStackView|dispatchDraw]", "",
+        Console.log(Constants.Log.UI.Draw, "[TaskStackView|dispatchDraw]", "",
                 Console.AnsiPurple);
         synchronizeStackViewsWithModel();
         super.dispatchDraw(canvas);
@@ -547,7 +561,7 @@
     }
 
     /** Computes the stack and task rects */
-    public void computeRects(int width, int height, int insetBottom) {
+    public void computeRects(int width, int height, int insetLeft, int insetBottom) {
         // Note: We let the stack view be the full height because we want the cards to go under the
         //       navigation bar if possible.  However, the stack rects which we use to calculate
         //       max scroll, etc. need to take the nav bar into account
@@ -555,12 +569,13 @@
         // Compute the stack rects
         mRect.set(0, 0, width, height);
         mStackRect.set(mRect);
+        mStackRect.left += insetLeft;
         mStackRect.bottom -= insetBottom;
 
         int smallestDimension = Math.min(width, height);
         int padding = (int) (Constants.Values.TaskStackView.StackPaddingPct * smallestDimension / 2f);
-        if (Constants.DebugFlags.App.EnableSearchButton) {
-            // Don't need to pad the top since we have some padding on the search bar already
+        if (Constants.DebugFlags.App.EnableSearchLayout) {
+            mStackRect.top += padding;
             mStackRect.left += padding;
             mStackRect.right -= padding;
             mStackRect.bottom -= padding;
@@ -582,20 +597,27 @@
         updateMinMaxScroll(false);
     }
 
+    /**
+     * This is called with the size of the space not including the top or right insets, or the
+     * search bar height in portrait (but including the search bar width in landscape, since we want
+     * to draw under it.
+     */
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int width = MeasureSpec.getSize(widthMeasureSpec);
         int height = MeasureSpec.getSize(heightMeasureSpec);
-        Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[TaskStackView|measure]",
+        Console.log(Constants.Log.UI.MeasureAndLayout, "[TaskStackView|measure]",
                 "width: " + width + " height: " + height +
                 " awaitingFirstLayout: " + mAwaitingFirstLayout, Console.AnsiGreen);
 
         // Compute our stack/task rects
         RecentsConfiguration config = RecentsConfiguration.getInstance();
-        computeRects(width, height, config.systemInsets.bottom);
+        Rect taskStackBounds = new Rect();
+        config.getTaskStackBounds(width, height, taskStackBounds);
+        computeRects(width, height, taskStackBounds.left, config.systemInsets.bottom);
 
         // Debug logging
-        if (Constants.DebugFlags.UI.MeasureAndLayout) {
+        if (Constants.Log.UI.MeasureAndLayout) {
             Console.log("  [TaskStack|fullRect] " + mRect);
             Console.log("  [TaskStack|stackRect] " + mStackRect);
             Console.log("  [TaskStack|stackRectSansPeek] " + mStackRectSansPeek);
@@ -610,8 +632,7 @@
             synchronizeStackViewsWithModel();
 
             // Animate the task bar of the first task view
-            if (config.launchedWithThumbnailAnimation &&
-                    Constants.Values.TaskView.AnimateFrontTaskBarOnEnterRecents) {
+            if (config.launchedWithThumbnailAnimation) {
                 TaskView tv = (TaskView) getChildAt(getChildCount() - 1);
                 if (tv != null) {
                     tv.animateOnEnterRecents();
@@ -630,13 +651,18 @@
         setMeasuredDimension(width, height);
     }
 
+    /**
+     * This is called with the size of the space not including the top or right insets, or the
+     * search bar height in portrait (but including the search bar width in landscape, since we want
+     * to draw under it.
+     */
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[TaskStackView|layout]",
+        Console.log(Constants.Log.UI.MeasureAndLayout, "[TaskStackView|layout]",
                 "" + new Rect(left, top, right, bottom), Console.AnsiGreen);
 
         // Debug logging
-        if (Constants.DebugFlags.UI.MeasureAndLayout) {
+        if (Constants.Log.UI.MeasureAndLayout) {
             Console.log("  [TaskStack|fullRect] " + mRect);
             Console.log("  [TaskStack|stackRect] " + mStackRect);
             Console.log("  [TaskStack|stackRectSansPeek] " + mStackRectSansPeek);
@@ -686,9 +712,24 @@
             }
         }
 
+        // Update the min/max scroll and animate other task views into their new positions
         updateMinMaxScroll(true);
         int movement = (int) (Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height());
         requestSynchronizeStackViewsWithModel(Utilities.calculateTranslationAnimationDuration(movement));
+
+        // If there are no remaining tasks, then either unfilter the current stack, or just close
+        // the activity if there are no filtered stacks
+        if (mStack.getTaskCount() == 0) {
+            boolean shouldFinishActivity = true;
+            if (mStack.hasFilteredTasks()) {
+                mStack.unfilterTasks();
+                shouldFinishActivity = (mStack.getTaskCount() == 0);
+            }
+            if (shouldFinishActivity) {
+                Activity activity = (Activity) getContext();
+                activity.finish();
+            }
+        }
     }
 
     /**
@@ -890,7 +931,7 @@
 
     @Override
     public TaskView createView(Context context) {
-        Console.log(Constants.DebugFlags.ViewPool.PoolCallbacks, "[TaskStackView|createPoolView]");
+        Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|createPoolView]");
         return (TaskView) mInflater.inflate(R.layout.recents_task_view, this, false);
     }
 
@@ -898,7 +939,7 @@
     public void prepareViewToEnterPool(TaskView tv) {
         Task task = tv.getTask();
         tv.resetViewProperties();
-        Console.log(Constants.DebugFlags.ViewPool.PoolCallbacks, "[TaskStackView|returnToPool]",
+        Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|returnToPool]",
                 tv.getTask() + " tv: " + tv);
 
         // Report that this tasks's data is no longer being used
@@ -914,7 +955,7 @@
 
     @Override
     public void prepareViewToLeavePool(TaskView tv, Task prepareData, boolean isNewView) {
-        Console.log(Constants.DebugFlags.ViewPool.PoolCallbacks, "[TaskStackView|leavePool]",
+        Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|leavePool]",
                 "isNewView: " + isNewView);
 
         // Setup and attach the view to the window
@@ -937,7 +978,7 @@
         }
 
         // Add/attach the view to the hierarchy
-        Console.log(Constants.DebugFlags.ViewPool.PoolCallbacks, "  [TaskStackView|insertIndex]",
+        Console.log(Constants.Log.ViewPool.PoolCallbacks, "  [TaskStackView|insertIndex]",
                 "" + insertIndex);
         if (isNewView) {
             addView(tv, insertIndex);
@@ -967,7 +1008,7 @@
 
     @Override
     public void onTaskIconClicked(TaskView tv) {
-        Console.log(Constants.DebugFlags.UI.ClickEvents, "[TaskStack|Clicked|Icon]",
+        Console.log(Constants.Log.UI.ClickEvents, "[TaskStack|Clicked|Icon]",
                 tv.getTask() + " is currently filtered: " + mStack.hasFilteredTasks(),
                 Console.AnsiCyan);
         if (Constants.DebugFlags.App.EnableTaskFiltering) {
@@ -976,8 +1017,6 @@
             } else {
                 mStack.filterTasks(tv.getTask());
             }
-        } else {
-            Console.logError(getContext(), "Task Filtering TBD");
         }
     }
 
@@ -999,13 +1038,22 @@
         }
     }
 
+    @Override
+    public void onTaskDismissed(TaskView tv) {
+        Task task = tv.getTask();
+        // Remove the task from the view
+        mStack.removeTask(task);
+        // Notify the callback that we've removed the task and it can clean up after it
+        mCb.onTaskRemoved(task);
+    }
+
     /**** View.OnClickListener Implementation ****/
 
     @Override
     public void onClick(View v) {
         TaskView tv = (TaskView) v;
         Task task = tv.getTask();
-        Console.log(Constants.DebugFlags.UI.ClickEvents, "[TaskStack|Clicked|Thumbnail]",
+        Console.log(Constants.Log.UI.ClickEvents, "[TaskStack|Clicked|Thumbnail]",
                 task + " cb: " + mCb);
 
         // Close any open info panes if the user taps on another task
@@ -1053,6 +1101,33 @@
         tv.showInfoPane(new Rect(0, 0, 0, (int) overlapHeight));
         return true;
     }
+
+    /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
+
+    @Override
+    public void onComponentRemoved(Set<ComponentName> cns) {
+        RecentsConfiguration config = RecentsConfiguration.getInstance();
+        // For other tasks, just remove them directly if they no longer exist
+        ArrayList<Task> tasks = mStack.getTasks();
+        for (int i = tasks.size() - 1; i >= 0; i--) {
+            final Task t = tasks.get(i);
+            if (cns.contains(t.key.baseIntent.getComponent())) {
+                TaskView tv = getChildViewForTask(t);
+                if (tv != null) {
+                    // For visible children, defer removing the task until after the animation
+                    tv.animateRemoval(new Runnable() {
+                        @Override
+                        public void run() {
+                            mStack.removeTask(t);
+                        }
+                    });
+                } else {
+                    // Otherwise, remove the task from the stack immediately
+                    mStack.removeTask(t);
+                }
+            }
+        }
+    }
 }
 
 /* Handles touch events */
@@ -1130,7 +1205,7 @@
 
     /** Touch preprocessing for handling below */
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        Console.log(Constants.DebugFlags.UI.TouchEvents,
+        Console.log(Constants.Log.UI.TouchEvents,
                 "[TaskStackViewTouchHandler|interceptTouchEvent]",
                 Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
 
@@ -1214,7 +1289,7 @@
 
     /** Handles touch events once we have intercepted them */
     public boolean onTouchEvent(MotionEvent ev) {
-        Console.log(Constants.DebugFlags.UI.TouchEvents,
+        Console.log(Constants.Log.UI.TouchEvents,
                 "[TaskStackViewTouchHandler|touchEvent]",
                 Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
 
@@ -1286,9 +1361,13 @@
                 }
                 if (mIsScrolling) {
                     int curStackScroll = mSv.getStackScroll();
-                    if (mSv.isScrollOutOfBounds(curStackScroll + deltaY)) {
-                        // Scale the touch if we are overscrolling
-                        deltaY /= Constants.Values.TaskStackView.TouchOverscrollScaleFactor;
+                    int overScrollAmount = mSv.getScrollAmountOutOfBounds(curStackScroll + deltaY);
+                    if (overScrollAmount != 0) {
+                        // Bound the overscroll to a fixed amount, and inversely scale the y-movement
+                        // relative to how close we are to the max overscroll
+                        float maxOverScroll = mSv.mTaskRect.height() / 3f;
+                        deltaY = Math.round(deltaY * (1f - (Math.min(maxOverScroll, overScrollAmount)
+                                / maxOverScroll)));
                     }
                     mSv.setStackScroll(curStackScroll + deltaY);
                     if (mSv.isScrollOutOfBounds()) {
@@ -1308,11 +1387,12 @@
                 if (mIsScrolling && (Math.abs(velocity) > mMinimumVelocity)) {
                     // Enable HW layers on the stack
                     mSv.addHwLayersRefCount("flingScroll");
+                    // XXX: Make this animation a function of the velocity AND distance
                     int overscrollRange = (int) (Math.min(1f,
                             Math.abs((float) velocity / mMaximumVelocity)) *
                             Constants.Values.TaskStackView.TaskStackOverscrollRange);
 
-                    Console.log(Constants.DebugFlags.UI.TouchEvents,
+                    Console.log(Constants.Log.UI.TouchEvents,
                             "[TaskStackViewTouchHandler|fling]",
                             "scroll: " + mSv.getStackScroll() + " velocity: " + velocity +
                                     " maxVelocity: " + mMaximumVelocity +
@@ -1409,31 +1489,7 @@
     @Override
     public void onChildDismissed(View v) {
         TaskView tv = (TaskView) v;
-        Task task = tv.getTask();
-        Activity activity = (Activity) mSv.getContext();
-
-        // Remove the task from the view
-        mSv.mStack.removeTask(task);
-
-        // Remove any stored data from the loader
-        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
-        loader.deleteTaskData(task);
-
-        // Remove the task from activity manager
-        RecentsTaskLoader.getInstance().getSystemServicesProxy().removeTask(tv.getTask().key.id);
-
-        // If there are no remaining tasks, then either unfilter the current stack, or just close
-        // the activity if there are no filtered stacks
-        if (mSv.mStack.getTaskCount() == 0) {
-            boolean shouldFinishActivity = true;
-            if (mSv.mStack.hasFilteredTasks()) {
-                mSv.mStack.unfilterTasks();
-                shouldFinishActivity = (mSv.mStack.getTaskCount() == 0);
-            }
-            if (shouldFinishActivity) {
-                activity.finish();
-            }
-        }
+        mSv.onTaskDismissed(tv);
 
         // Disable HW layers
         mSv.decHwLayersRefCount("swipeComplete");
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index d3b79d6..5fad629 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -20,6 +20,7 @@
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.Canvas;
+import android.graphics.Outline;
 import android.graphics.Path;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -30,10 +31,8 @@
 import android.view.animation.AccelerateInterpolator;
 import android.widget.FrameLayout;
 import com.android.systemui.R;
-import com.android.systemui.recents.BakedBezierInterpolator;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.Utilities;
 import com.android.systemui.recents.model.Task;
 
 
@@ -46,6 +45,7 @@
         public void onTaskInfoPanelShown(TaskView tv);
         public void onTaskInfoPanelHidden(TaskView tv);
         public void onTaskAppInfoClicked(TaskView tv);
+        public void onTaskDismissed(TaskView tv);
 
         // public void onTaskViewReboundToTask(TaskView tv, Task t);
     }
@@ -108,6 +108,11 @@
         mRoundedRectClipPath.reset();
         mRoundedRectClipPath.addRoundRect(new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight()),
                 radius, radius, Path.Direction.CW);
+
+        // Update the outline
+        Outline o = new Outline();
+        o.setRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), radius);
+        setOutline(o);
     }
 
     @Override
@@ -134,19 +139,33 @@
     /** Synchronizes this view's properties with the task's transform */
     void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
                                              TaskViewTransform toTransform, int duration) {
+        RecentsConfiguration config = RecentsConfiguration.getInstance();
+        int minZ = config.taskViewTranslationZMinPx;
+        int incZ = config.taskViewTranslationZIncrementPx;
+
+        // Update the bar view
+        mBarView.updateViewPropertiesToTaskTransform(animateFromTransform, toTransform, duration);
+
+        // Update this task view
         if (duration > 0) {
             if (animateFromTransform != null) {
                 setTranslationY(animateFromTransform.translationY);
+                if (Constants.DebugFlags.App.EnableShadows) {
+                    setTranslationZ(Math.max(minZ, minZ + (animateFromTransform.t * incZ)));
+                }
                 setScaleX(animateFromTransform.scale);
                 setScaleY(animateFromTransform.scale);
                 setAlpha(animateFromTransform.alpha);
             }
+            if (Constants.DebugFlags.App.EnableShadows) {
+                animate().translationZ(Math.max(minZ, minZ + (toTransform.t * incZ)));
+            }
             animate().translationY(toTransform.translationY)
                     .scaleX(toTransform.scale)
                     .scaleY(toTransform.scale)
                     .alpha(toTransform.alpha)
                     .setDuration(duration)
-                    .setInterpolator(BakedBezierInterpolator.INSTANCE)
+                    .setInterpolator(config.defaultBezierInterpolator)
                     .withLayer()
                     .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                         @Override
@@ -157,6 +176,9 @@
                     .start();
         } else {
             setTranslationY(toTransform.translationY);
+            if (Constants.DebugFlags.App.EnableShadows) {
+                setTranslationZ(Math.max(minZ, minZ + (toTransform.t * incZ)));
+            }
             setScaleX(toTransform.scale);
             setScaleY(toTransform.scale);
             setAlpha(toTransform.alpha);
@@ -169,6 +191,9 @@
     void resetViewProperties() {
         setTranslationX(0f);
         setTranslationY(0f);
+        if (Constants.DebugFlags.App.EnableShadows) {
+            setTranslationZ(0f);
+        }
         setScaleX(1f);
         setScaleY(1f);
         setAlpha(1f);
@@ -197,20 +222,11 @@
     /** Animates this task view as it enters recents */
     public void animateOnEnterRecents() {
         RecentsConfiguration config = RecentsConfiguration.getInstance();
-        int translate = config.pxFromDp(10);
-        mBarView.setScaleX(1.25f);
-        mBarView.setScaleY(1.25f);
         mBarView.setAlpha(0f);
-        mBarView.setTranslationX(translate / 2);
-        mBarView.setTranslationY(-translate);
         mBarView.animate()
                 .alpha(1f)
-                .scaleX(1f)
-                .scaleY(1f)
-                .translationX(0)
-                .translationY(0)
-                .setStartDelay(235)
-                .setInterpolator(BakedBezierInterpolator.INSTANCE)
+                .setStartDelay(250)
+                .setInterpolator(config.defaultBezierInterpolator)
                 .setDuration(config.taskBarEnterAnimDuration)
                 .withLayer()
                 .start();
@@ -219,16 +235,29 @@
     /** Animates this task view as it exits recents */
     public void animateOnLeavingRecents(final Runnable r) {
         RecentsConfiguration config = RecentsConfiguration.getInstance();
-        int translate = config.pxFromDp(10);
         mBarView.animate()
             .alpha(0f)
-            .scaleX(1.1f)
-            .scaleY(1.1f)
-            .translationX(translate / 2)
-            .translationY(-translate)
             .setStartDelay(0)
-            .setInterpolator(BakedBezierInterpolator.INSTANCE)
-            .setDuration(Utilities.calculateTranslationAnimationDuration(translate))
+            .setInterpolator(config.defaultBezierInterpolator)
+            .setDuration(config.taskBarExitAnimDuration)
+            .withLayer()
+            .withEndAction(new Runnable() {
+                @Override
+                public void run() {
+                    post(r);
+                }
+            })
+            .start();
+    }
+
+    /** Animates the deletion of this task view */
+    public void animateRemoval(final Runnable r) {
+        RecentsConfiguration config = RecentsConfiguration.getInstance();
+        animate().translationX(config.taskViewRemoveAnimTranslationXPx)
+            .alpha(0f)
+            .setStartDelay(0)
+            .setInterpolator(config.defaultBezierInterpolator)
+            .setDuration(config.taskViewRemoveAnimDuration)
             .withLayer()
             .withEndAction(new Runnable() {
                 @Override
@@ -285,7 +314,7 @@
         mInfoView.animate()
                 .alpha(0f)
                 .setDuration(config.taskViewInfoPaneAnimDuration)
-                .setInterpolator(BakedBezierInterpolator.INSTANCE)
+                .setInterpolator(config.defaultBezierInterpolator)
                 .withLayer()
                 .withEndAction(new Runnable() {
                     @Override
@@ -352,8 +381,10 @@
             // Bind each of the views to the new task data
             mThumbnailView.rebindToTask(mTask, reloadingTaskData);
             mBarView.rebindToTask(mTask, reloadingTaskData);
+            mInfoView.rebindToTask(mTask, reloadingTaskData);
             // Rebind any listeners
             mBarView.mApplicationIcon.setOnClickListener(this);
+            mBarView.mDismissButton.setOnClickListener(this);
             mInfoView.mAppInfoButton.setOnClickListener(this);
         }
         mTaskDataLoaded = true;
@@ -376,9 +407,18 @@
     @Override
     public void onClick(View v) {
         if (v == mInfoView) {
-            // Do nothing
+            hideInfoPane();
         } else if (v == mBarView.mApplicationIcon) {
             mCb.onTaskIconClicked(this);
+        } else if (v == mBarView.mDismissButton) {
+            // Animate out the view and call the callback
+            final TaskView tv = this;
+            animateRemoval(new Runnable() {
+                @Override
+                public void run() {
+                    mCb.onTaskDismissed(tv);
+                }
+            });
         } else if (v == mInfoView.mAppInfoButton) {
             mCb.onTaskAppInfoClicked(this);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index 0748bbb..e6391a8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -24,6 +24,7 @@
     public int translationY = 0;
     public float scale = 1f;
     public float alpha = 1f;
+    public float dismissAlpha = 1f;
     public boolean visible = false;
     public Rect rect = new Rect();
     float t;
@@ -36,6 +37,7 @@
         translationY = o.translationY;
         scale = o.scale;
         alpha = o.alpha;
+        dismissAlpha = o.dismissAlpha;
         visible = o.visible;
         rect.set(o.rect);
         t = o.t;
@@ -44,6 +46,6 @@
     @Override
     public String toString() {
         return "TaskViewTransform y: " + translationY + " scale: " + scale + " alpha: " + alpha +
-                " visible: " + visible + " rect: " + rect;
+                " visible: " + visible + " rect: " + rect + " dismissAlpha: " + dismissAlpha;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index 327e715..a770f58 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -28,7 +28,6 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
 import android.widget.ImageView;
 
 import java.util.ArrayList;
@@ -36,6 +35,12 @@
 public class BrightnessController implements ToggleSlider.Listener {
     private static final String TAG = "StatusBar.BrightnessController";
 
+    /**
+     * {@link android.provider.Settings.System#SCREEN_AUTO_BRIGHTNESS_ADJ} uses the range [-1, 1].
+     * Using this factor, it is converted to [0, BRIGHTNESS_ADJ_RESOLUTION] for the SeekBar.
+     */
+    private static final float BRIGHTNESS_ADJ_RESOLUTION = 100;
+
     private final int mMinimumBacklight;
     private final int mMaximumBacklight;
 
@@ -51,6 +56,8 @@
     private ArrayList<BrightnessStateChangeCallback> mChangeCallbacks =
             new ArrayList<BrightnessStateChangeCallback>();
 
+    private boolean mAutomatic;
+
     public interface BrightnessStateChangeCallback {
         public void onBrightnessLevelChanged();
     }
@@ -62,6 +69,8 @@
                 Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE);
         private final Uri BRIGHTNESS_URI =
                 Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
+        private final Uri BRIGHTNESS_ADJ_URI =
+                Settings.System.getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ);
 
         public BrightnessObserver(Handler handler) {
             super(handler);
@@ -77,7 +86,10 @@
             if (selfChange) return;
             if (BRIGHTNESS_MODE_URI.equals(uri)) {
                 updateMode();
-            } else if (BRIGHTNESS_URI.equals(uri)) {
+                updateSlider();
+            } else if (BRIGHTNESS_URI.equals(uri) && !mAutomatic) {
+                updateSlider();
+            } else if (BRIGHTNESS_ADJ_URI.equals(uri) && mAutomatic) {
                 updateSlider();
             } else {
                 updateMode();
@@ -97,6 +109,9 @@
             cr.registerContentObserver(
                     BRIGHTNESS_URI,
                     false, this, UserHandle.USER_ALL);
+            cr.registerContentObserver(
+                    BRIGHTNESS_ADJ_URI,
+                    false, this, UserHandle.USER_ALL);
         }
 
         public void stopObserving() {
@@ -119,7 +134,6 @@
             }
         };
         mBrightnessObserver = new BrightnessObserver(mHandler);
-        mBrightnessObserver.startObserving();
 
         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mMinimumBacklight = pm.getMinimumScreenBrightnessSetting();
@@ -128,13 +142,6 @@
         mAutomaticAvailable = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_automatic_brightness_available);
         mPower = IPowerManager.Stub.asInterface(ServiceManager.getService("power"));
-
-        // Update the slider and mode before attaching the listener so we don't receive the
-        // onChanged notifications for the initial values.
-        updateMode();
-        updateSlider();
-
-        control.setOnChangedListener(this);
     }
 
     public void addStateChangedCallback(BrightnessStateChangeCallback cb) {
@@ -150,18 +157,29 @@
         // Do nothing
     }
 
+    public void registerCallbacks() {
+        mBrightnessObserver.startObserving();
+        mUserTracker.startTracking();
+
+        // Update the slider and mode before attaching the listener so we don't receive the
+        // onChanged notifications for the initial values.
+        updateMode();
+        updateSlider();
+
+        mControl.setOnChangedListener(this);
+    }
+
     /** Unregister all call backs, both to and from the controller */
     public void unregisterCallbacks() {
         mBrightnessObserver.stopObserving();
         mChangeCallbacks.clear();
         mUserTracker.stopTracking();
+        mControl.setOnChangedListener(null);
     }
 
     public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value) {
-        setMode(automatic ? Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC
-                : Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
-        updateIcon(automatic);
-        if (!automatic) {
+        updateIcon(mAutomatic);
+        if (!mAutomatic) {
             final int val = value + mMinimumBacklight;
             setBrightness(val);
             if (!tracking) {
@@ -173,6 +191,18 @@
                         }
                     });
             }
+        } else {
+            final float adj = value / (BRIGHTNESS_ADJ_RESOLUTION / 2f) - 1;
+            setBrightnessAdj(adj);
+            if (!tracking) {
+                AsyncTask.execute(new Runnable() {
+                    public void run() {
+                        Settings.System.putFloatForUser(mContext.getContentResolver(),
+                                Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adj,
+                                UserHandle.USER_CURRENT);
+                    }
+                });
+            }
         }
 
         for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
@@ -193,6 +223,13 @@
         }
     }
 
+    private void setBrightnessAdj(float adj) {
+        try {
+            mPower.setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(adj);
+        } catch (RemoteException ex) {
+        }
+    }
+
     private void updateIcon(boolean automatic) {
         if (mIcon != null) {
             mIcon.setImageResource(automatic ?
@@ -205,15 +242,12 @@
     private void updateMode() {
         if (mAutomaticAvailable) {
             int automatic;
-            try {
-                automatic = Settings.System.getIntForUser(mContext.getContentResolver(),
-                        Settings.System.SCREEN_BRIGHTNESS_MODE,
-                        UserHandle.USER_CURRENT);
-            } catch (SettingNotFoundException snfe) {
-                automatic = 0;
-            }
-            mControl.setChecked(automatic != 0);
-            updateIcon(automatic != 0);
+            automatic = Settings.System.getIntForUser(mContext.getContentResolver(),
+                    Settings.System.SCREEN_BRIGHTNESS_MODE,
+                    Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
+                    UserHandle.USER_CURRENT);
+            mAutomatic = automatic != Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
+            updateIcon(mAutomatic);
         } else {
             mControl.setChecked(false);
             updateIcon(false /*automatic*/);
@@ -222,16 +256,20 @@
 
     /** Fetch the brightness from the system settings and update the slider */
     private void updateSlider() {
-        int value;
-        try {
-            value = Settings.System.getIntForUser(mContext.getContentResolver(),
-                    Settings.System.SCREEN_BRIGHTNESS,
+        if (mAutomatic) {
+            float value = Settings.System.getFloatForUser(mContext.getContentResolver(),
+                    Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0,
                     UserHandle.USER_CURRENT);
-        } catch (SettingNotFoundException ex) {
-            value = mMaximumBacklight;
+            mControl.setMax((int) BRIGHTNESS_ADJ_RESOLUTION);
+            mControl.setValue((int) ((value + 1) * BRIGHTNESS_ADJ_RESOLUTION / 2f));
+        } else {
+            int value;
+            value = Settings.System.getIntForUser(mContext.getContentResolver(),
+                    Settings.System.SCREEN_BRIGHTNESS, mMaximumBacklight,
+                    UserHandle.USER_CURRENT);
+            mControl.setMax(mMaximumBacklight - mMinimumBacklight);
+            mControl.setValue(value - mMinimumBacklight);
         }
-        mControl.setMax(mMaximumBacklight - mMinimumBacklight);
-        mControl.setValue(value - mMinimumBacklight);
     }
 
 }
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
index bd5e5e8..27881c4 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
@@ -92,6 +92,7 @@
         mBrightnessController = new BrightnessController(getContext(),
                 (ImageView) findViewById(R.id.brightness_icon),
                 (ToggleSlider) findViewById(R.id.brightness_slider));
+        mBrightnessController.registerCallbacks();
         dismissBrightnessDialog(mBrightnessDialogLongTimeout);
         mBrightnessController.addStateChangedCallback(this);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
index 036bd4f..f8ff616 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
@@ -29,9 +29,6 @@
     private int mCurrentUserId;
 
     public CurrentUserTracker(Context context) {
-        IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
-        context.registerReceiver(this, filter);
-        mCurrentUserId = ActivityManager.getCurrentUser();
         mContext = context;
     }
 
@@ -50,6 +47,12 @@
         }
     }
 
+    public void startTracking() {
+        mCurrentUserId = ActivityManager.getCurrentUser();
+        IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
+        mContext.registerReceiver(this, filter);
+    }
+
     public void stopTracking() {
         mContext.unregisterReceiver(this);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
index 7d38058..4b78072 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
@@ -62,7 +62,6 @@
 
         mToggle = (CompoundButton) findViewById(R.id.toggle);
         mToggle.setOnCheckedChangeListener(mCheckListener);
-        mToggle.setBackground(res.getDrawable(R.drawable.status_bar_toggle_button));
 
         mSlider = (SeekBar) findViewById(R.id.slider);
         mSlider.setOnSeekBarChangeListener(mSeekListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 0f32dc0..91df9ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -16,12 +16,18 @@
 
 package com.android.systemui.statusbar;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
 import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
-import android.widget.FrameLayout;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 
 import com.android.internal.R;
 
@@ -32,9 +38,9 @@
 public abstract class ActivatableNotificationView extends ExpandableOutlineView {
 
     private static final long DOUBLETAP_TIMEOUT_MS = 1000;
+    private static final int BACKGROUND_ANIMATION_LENGTH_MS = 220;
 
     private boolean mDimmed;
-    private boolean mLocked;
 
     private int mBgResId = R.drawable.notification_quantum_bg;
     private int mDimmedBgResId = R.drawable.notification_quantum_bg_dim;
@@ -51,13 +57,20 @@
 
     private OnActivatedListener mOnActivatedListener;
 
+    protected Drawable mBackgroundNormal;
+    protected Drawable mBackgroundDimmed;
+    private ObjectAnimator mBackgroundAnimator;
+    private Interpolator mFastOutSlowInInterpolator;
+
     public ActivatableNotificationView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
         updateBackgroundResource();
+        setWillNotDraw(false);
+        mFastOutSlowInInterpolator =
+                AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
     }
 
-
     private final Runnable mTapTimeoutRunnable = new Runnable() {
         @Override
         public void run() {
@@ -66,20 +79,51 @@
     };
 
     @Override
+    protected void onDraw(Canvas canvas) {
+        draw(canvas, mBackgroundNormal);
+        draw(canvas, mBackgroundDimmed);
+    }
+
+    private void draw(Canvas canvas, Drawable drawable) {
+        if (drawable != null) {
+            drawable.setBounds(0, mClipTopAmount, getWidth(), mActualHeight);
+            drawable.draw(canvas);
+        }
+    }
+
+    @Override
+    protected boolean verifyDrawable(Drawable who) {
+        return super.verifyDrawable(who) || who == mBackgroundNormal
+                || who == mBackgroundDimmed;
+    }
+
+    @Override
+    protected void drawableStateChanged() {
+        drawableStateChanged(mBackgroundNormal);
+        drawableStateChanged(mBackgroundDimmed);
+    }
+
+    private void drawableStateChanged(Drawable d) {
+        if (d != null && d.isStateful()) {
+            d.setState(getDrawableState());
+        }
+    }
+
+    @Override
     public void setOnClickListener(OnClickListener l) {
         super.setOnClickListener(l);
     }
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
-        if (mLocked) {
-            return handleTouchEventLocked(event);
+        if (mDimmed) {
+            return handleTouchEventDimmed(event);
         } else {
             return super.onTouchEvent(event);
         }
     }
 
-    private boolean handleTouchEventLocked(MotionEvent event) {
+    private boolean handleTouchEventDimmed(MotionEvent event) {
         int action = event.getActionMasked();
         switch (action) {
             case MotionEvent.ACTION_DOWN:
@@ -88,14 +132,6 @@
                 if (mDownY > getActualHeight()) {
                     return false;
                 }
-
-                // Call the listener tentatively directly, even if we don't know whether the user
-                // will stay within the touch slop, as the listener is implemented as a scale
-                // animation, which is cancellable without jarring effects when swiping away
-                // notifications.
-                if (mOnActivatedListener != null) {
-                    mOnActivatedListener.onActivated(this);
-                }
                 break;
             case MotionEvent.ACTION_MOVE:
                 if (!isWithinTouchSlop(event)) {
@@ -109,8 +145,8 @@
                         makeActive(event.getX(), event.getY());
                         postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS);
                     } else {
-                        performClick();
                         makeInactive();
+                        performClick();
                     }
                 } else {
                     makeInactive();
@@ -126,8 +162,11 @@
     }
 
     private void makeActive(float x, float y) {
-        mCustomBackground.setHotspot(0, x, y);
+        mBackgroundDimmed.setHotspot(0, x, y);
         mActivated = true;
+        if (mOnActivatedListener != null) {
+            mOnActivatedListener.onActivated(this);
+        }
     }
 
     /**
@@ -136,12 +175,14 @@
     private void makeInactive() {
         if (mActivated) {
             // Make sure that we clear the hotspot from the center.
-            mCustomBackground.setHotspot(0, getWidth() / 2, getActualHeight() / 2);
-            mCustomBackground.removeHotspot(0);
+            if (mBackgroundDimmed != null) {
+                mBackgroundDimmed.setHotspot(0, getWidth() / 2, getActualHeight() / 2);
+                mBackgroundDimmed.removeHotspot(0);
+            }
             mActivated = false;
         }
         if (mOnActivatedListener != null) {
-            mOnActivatedListener.onReset(this);
+            mOnActivatedListener.onActivationReset(this);
         }
         removeCallbacks(mTapTimeoutRunnable);
     }
@@ -151,25 +192,18 @@
                 && Math.abs(event.getY() - mDownY) < mTouchSlop;
     }
 
-    /**
-     * Sets the notification as dimmed, meaning that it will appear in a more gray variant.
-     */
-    public void setDimmed(boolean dimmed) {
+    public void setDimmed(boolean dimmed, boolean fade) {
         if (mDimmed != dimmed) {
             mDimmed = dimmed;
-            updateBackgroundResource();
+            if (fade) {
+                fadeBackgroundResource();
+            } else {
+                updateBackgroundResource();
+            }
         }
     }
 
     /**
-     * Sets the notification as locked. In the locked state, the first tap will produce a quantum
-     * ripple to make the notification brighter and only the second tap will cause a click.
-     */
-    public void setLocked(boolean locked) {
-        mLocked = locked;
-    }
-
-    /**
      * Sets the resource id for the background of this notification.
      *
      * @param bgResId The background resource to use in normal state.
@@ -181,20 +215,111 @@
         updateBackgroundResource();
     }
 
+    private void fadeBackgroundResource() {
+        if (mDimmed) {
+            setBackgroundDimmed(mDimmedBgResId);
+        } else {
+            setBackgroundNormal(mBgResId);
+        }
+        int startAlpha = mDimmed ? 255 : 0;
+        int endAlpha = mDimmed ? 0 : 255;
+        int duration = BACKGROUND_ANIMATION_LENGTH_MS;
+        // Check whether there is already a background animation running.
+        if (mBackgroundAnimator != null) {
+            startAlpha = (Integer) mBackgroundAnimator.getAnimatedValue();
+            duration = (int) mBackgroundAnimator.getCurrentPlayTime();
+            mBackgroundAnimator.removeAllListeners();
+            mBackgroundAnimator.cancel();
+            if (duration <= 0) {
+                updateBackgroundResource();
+                return;
+            }
+        }
+        mBackgroundNormal.setAlpha(startAlpha);
+        mBackgroundAnimator =
+                ObjectAnimator.ofInt(mBackgroundNormal, "alpha", startAlpha, endAlpha);
+        mBackgroundAnimator.setInterpolator(mFastOutSlowInInterpolator);
+        mBackgroundAnimator.setDuration(duration);
+        mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (mDimmed) {
+                    setBackgroundNormal(null);
+                } else {
+                    setBackgroundDimmed(null);
+                }
+                mBackgroundAnimator = null;
+            }
+        });
+        mBackgroundAnimator.start();
+    }
+
     private void updateBackgroundResource() {
-        setCustomBackgroundResource(mDimmed ? mDimmedBgResId : mBgResId);
+        if (mDimmed) {
+            setBackgroundDimmed(mDimmedBgResId);
+            mBackgroundDimmed.setAlpha(255);
+            setBackgroundNormal(null);
+        } else {
+            setBackgroundDimmed(null);
+            setBackgroundNormal(mBgResId);
+            mBackgroundNormal.setAlpha(255);
+        }
+    }
+
+    /**
+     * Sets a background drawable for the normal state. As we need to change our bounds
+     * independently of layout, we need the notion of a background independently of the regular View
+     * background..
+     */
+    private void setBackgroundNormal(Drawable backgroundNormal) {
+        if (mBackgroundNormal != null) {
+            mBackgroundNormal.setCallback(null);
+            unscheduleDrawable(mBackgroundNormal);
+        }
+        mBackgroundNormal = backgroundNormal;
+        if (mBackgroundNormal != null) {
+            mBackgroundNormal.setCallback(this);
+        }
+        invalidate();
+    }
+
+    private void setBackgroundDimmed(Drawable overlay) {
+        if (mBackgroundDimmed != null) {
+            mBackgroundDimmed.setCallback(null);
+            unscheduleDrawable(mBackgroundDimmed);
+        }
+        mBackgroundDimmed = overlay;
+        if (mBackgroundDimmed != null) {
+            mBackgroundDimmed.setCallback(this);
+        }
+        invalidate();
+    }
+
+    private void setBackgroundNormal(int drawableResId) {
+        setBackgroundNormal(getResources().getDrawable(drawableResId));
+    }
+
+    private void setBackgroundDimmed(int drawableResId) {
+        setBackgroundDimmed(getResources().getDrawable(drawableResId));
     }
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        setPivotX(getWidth()/2);
+        setPivotX(getWidth() / 2);
     }
 
     @Override
-    public void setActualHeight(int actualHeight) {
-        super.setActualHeight(actualHeight);
-        setPivotY(actualHeight/2);
+    public void setActualHeight(int actualHeight, boolean notifyListeners) {
+        super.setActualHeight(actualHeight, notifyListeners);
+        invalidate();
+        setPivotY(actualHeight / 2);
+    }
+
+    @Override
+    public void setClipTopAmount(int clipTopAmount) {
+        super.setClipTopAmount(clipTopAmount);
+        invalidate();
     }
 
     public void setOnActivatedListener(OnActivatedListener onActivatedListener) {
@@ -203,6 +328,6 @@
 
     public interface OnActivatedListener {
         void onActivated(View view);
-        void onReset(View view);
+        void onActivationReset(View view);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 9149e2d..898f06e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -70,7 +70,7 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarIconList;
-import com.android.internal.util.LegacyNotificationUtil;
+import com.android.internal.util.NotificationColorUtil;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.SearchPanelView;
@@ -143,7 +143,7 @@
     // public mode, private notifications, etc
     private boolean mLockscreenPublicMode = false;
     private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
-    private LegacyNotificationUtil mLegacyNotificationUtil = LegacyNotificationUtil.getInstance();
+    private NotificationColorUtil mNotificationColorUtil = NotificationColorUtil.getInstance();
 
     private UserManager mUserManager;
 
@@ -167,7 +167,12 @@
 
     protected int mZenMode;
 
-    protected boolean mOnKeyguard;
+    /**
+     * The {@link StatusBarState} of the status bar.
+     */
+    protected int mState;
+    protected boolean mBouncerShowing;
+
     protected NotificationOverflowContainer mKeyguardIconOverflowContainer;
 
     public boolean isDeviceProvisioned() {
@@ -297,7 +302,7 @@
         ArrayList<StatusBarNotification> notifications = new ArrayList<StatusBarNotification>();
         mCommandQueue = new CommandQueue(this, iconList);
 
-        int[] switches = new int[7];
+        int[] switches = new int[8];
         ArrayList<IBinder> binders = new ArrayList<IBinder>();
         try {
             mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications,
@@ -312,7 +317,7 @@
         setSystemUiVisibility(switches[1], 0xffffffff);
         topAppWindowChanged(switches[2] != 0);
         // StatusBarManagerService has a back up of IME token and it's restored here.
-        setImeWindowStatus(binders.get(0), switches[3], switches[4]);
+        setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[7] != 0);
         setHardKeyboardStatus(switches[5] != 0, switches[6] != 0);
 
         // Set up the initial icon state
@@ -768,8 +773,8 @@
 
         PendingIntent contentIntent = sbn.getNotification().contentIntent;
         if (contentIntent != null) {
-            final View.OnClickListener listener = makeClicker(contentIntent,
-                    sbn.getPackageName(), sbn.getTag(), sbn.getId(), isHeadsUp, sbn.getUserId());
+            final View.OnClickListener listener = makeClicker(contentIntent, sbn.getKey(),
+                    isHeadsUp);
             row.setOnClickListener(listener);
         } else {
             row.setOnClickListener(null);
@@ -847,7 +852,7 @@
 
             Drawable iconDrawable = StatusBarIconView.getIcon(mContext, ic);
             icon.setImageDrawable(iconDrawable);
-            if (mLegacyNotificationUtil.isGrayscale(iconDrawable)) {
+            if (mNotificationColorUtil.isGrayscale(iconDrawable)) {
                 icon.setBackgroundResource(
                         com.android.internal.R.drawable.notification_icon_legacy_bg_inset);
             }
@@ -879,27 +884,20 @@
         return true;
     }
 
-    public NotificationClicker makeClicker(PendingIntent intent, String pkg, String tag,
-            int id, boolean forHun, int userId) {
-        return new NotificationClicker(intent, pkg, tag, id, forHun, userId);
+    public NotificationClicker makeClicker(PendingIntent intent, String notificationKey,
+            boolean forHun) {
+        return new NotificationClicker(intent, notificationKey, forHun);
     }
 
     protected class NotificationClicker implements View.OnClickListener {
         private PendingIntent mIntent;
-        private String mPkg;
-        private String mTag;
-        private int mId;
+        private final String mNotificationKey;
         private boolean mIsHeadsUp;
-        private int mUserId;
 
-        public NotificationClicker(PendingIntent intent, String pkg, String tag, int id,
-                boolean forHun, int userId) {
+        public NotificationClicker(PendingIntent intent, String notificationKey, boolean forHun) {
             mIntent = intent;
-            mPkg = pkg;
-            mTag = tag;
-            mId = id;
+            mNotificationKey = notificationKey;
             mIsHeadsUp = forHun;
-            mUserId = userId;
         }
 
         public void onClick(View v) {
@@ -935,7 +933,7 @@
                 if (mIsHeadsUp) {
                     mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
                 }
-                mBarService.onNotificationClick(mPkg, mTag, mId, mUserId);
+                mBarService.onNotificationClick(mNotificationKey);
             } catch (RemoteException ex) {
                 // system process is dead if we're here.
             }
@@ -1031,6 +1029,9 @@
     }
 
     protected void addNotificationViews(NotificationData.Entry entry) {
+        if (entry == null) {
+            return;
+        }
         // Add the expanded view and icon.
         int pos = mNotificationData.add(entry);
         if (DEBUG) {
@@ -1057,9 +1058,10 @@
         mKeyguardIconOverflowContainer.getIconsView().removeAllViews();
         int n = mNotificationData.size();
         int visibleNotifications = 0;
+        boolean onKeyguard = mState == StatusBarState.KEYGUARD;
         for (int i = n-1; i >= 0; i--) {
             NotificationData.Entry entry = mNotificationData.get(i);
-            if (mOnKeyguard) {
+            if (onKeyguard) {
                 entry.row.setExpansionDisabled(true);
             } else {
                 entry.row.setExpansionDisabled(false);
@@ -1068,10 +1070,8 @@
                     entry.row.setSystemExpanded(top);
                 }
             }
-            entry.row.setDimmed(mOnKeyguard);
-            entry.row.setLocked(mOnKeyguard);
             boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
-            if (mOnKeyguard && (visibleNotifications >= maxKeyguardNotifications
+            if (onKeyguard && (visibleNotifications >= maxKeyguardNotifications
                     || !showOnKeyguard)) {
                 entry.row.setVisibility(View.GONE);
                 if (showOnKeyguard) {
@@ -1087,49 +1087,13 @@
             }
         }
 
-        if (mOnKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) {
+        if (onKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) {
             mKeyguardIconOverflowContainer.setVisibility(View.VISIBLE);
         } else {
             mKeyguardIconOverflowContainer.setVisibility(View.GONE);
         }
     }
 
-    @Override
-    public void onActivated(View view) {
-        int n = mNotificationData.size();
-        for (int i = 0; i < n; i++) {
-            NotificationData.Entry entry = mNotificationData.get(i);
-            if (entry.row.getVisibility() != View.GONE) {
-                if (view == entry.row) {
-                    entry.row.getActivator().activate();
-                } else {
-                    entry.row.getActivator().activateInverse();
-                }
-            }
-        }
-        if (mKeyguardIconOverflowContainer.getVisibility() != View.GONE) {
-            if (view == mKeyguardIconOverflowContainer) {
-                mKeyguardIconOverflowContainer.getActivator().activate();
-            } else {
-                mKeyguardIconOverflowContainer.getActivator().activateInverse();
-            }
-        }
-    }
-
-    @Override
-    public void onReset(View view) {
-        int n = mNotificationData.size();
-        for (int i = 0; i < n; i++) {
-            NotificationData.Entry entry = mNotificationData.get(i);
-            if (entry.row.getVisibility() != View.GONE) {
-                entry.row.getActivator().reset();
-            }
-        }
-        if (mKeyguardIconOverflowContainer.getVisibility() != View.GONE) {
-            mKeyguardIconOverflowContainer.getActivator().reset();
-        }
-    }
-
     private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
         return sbn.getNotification().priority >= Notification.PRIORITY_LOW;
     }
@@ -1145,7 +1109,6 @@
     protected abstract void updateNotificationIcons();
     protected abstract void tick(IBinder key, StatusBarNotification n, boolean firstTime);
     protected abstract void updateExpandedViewPos(int expandedPosition);
-    protected abstract int getExpandedViewMaxHeight();
     protected abstract boolean shouldDisableNavbarGestures();
 
     protected boolean isTopNotification(ViewGroup parent, NotificationData.Entry entry) {
@@ -1283,7 +1246,7 @@
             if (userChangedExpansion) {
                 boolean userExpanded = oldEntry.row.isUserExpanded();
                 newEntry.row.setUserExpanded(userExpanded);
-                newEntry.row.applyExpansionToLayout();
+                newEntry.row.notifyHeightChanged();
             }
         }
 
@@ -1338,9 +1301,8 @@
         // update the contentIntent
         final PendingIntent contentIntent = notification.getNotification().contentIntent;
         if (contentIntent != null) {
-            final View.OnClickListener listener = makeClicker(contentIntent,
-                    notification.getPackageName(), notification.getTag(), notification.getId(),
-                    isHeadsUp, notification.getUserId());
+            final View.OnClickListener listener = makeClicker(contentIntent, notification.getKey(),
+                    isHeadsUp);
             entry.row.setOnClickListener(listener);
         } else {
             entry.row.setOnClickListener(null);
@@ -1398,6 +1360,17 @@
         // hook for subclasses
     }
 
+    public void setBouncerShowing(boolean bouncerShowing) {
+        mBouncerShowing = bouncerShowing;
+    }
+
+    /**
+     * @return Whether the security bouncer from Keyguard is showing.
+     */
+    public boolean isBouncerShowing() {
+        return mBouncerShowing;
+    }
+
     public void destroy() {
         if (mSearchPanelView != null) {
             mWindowManager.removeViewImmediate(mSearchPanelView);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index bbbe8fa..5362af5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -65,6 +65,8 @@
     public static final int FLAG_EXCLUDE_INPUT_METHODS_PANEL = 1 << 3;
     public static final int FLAG_EXCLUDE_COMPAT_MODE_PANEL = 1 << 4;
 
+    private static final String SHOW_IME_SWITCHER_KEY = "showImeSwitcherKey";
+
     private StatusBarIconList mList;
     private Callbacks mCallbacks;
     private Handler mHandler = new H();
@@ -91,7 +93,8 @@
         public void animateExpandSettingsPanel();
         public void setSystemUiVisibility(int vis, int mask);
         public void topAppWindowChanged(boolean visible);
-        public void setImeWindowStatus(IBinder token, int vis, int backDisposition);
+        public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+                boolean showImeSwitcher);
         public void setHardKeyboardStatus(boolean available, boolean enabled);
         public void toggleRecentApps();
         public void preloadRecentApps();
@@ -190,11 +193,13 @@
         }
     }
 
-    public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
+    public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+            boolean showImeSwitcher) {
         synchronized (mList) {
             mHandler.removeMessages(MSG_SHOW_IME_BUTTON);
-            mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, vis, backDisposition, token)
-                    .sendToTarget();
+            Message m = mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, vis, backDisposition, token);
+            m.getData().putBoolean(SHOW_IME_SWITCHER_KEY, showImeSwitcher);
+            m.sendToTarget();
         }
     }
 
@@ -298,7 +303,8 @@
                     mCallbacks.topAppWindowChanged(msg.arg1 != 0);
                     break;
                 case MSG_SHOW_IME_BUTTON:
-                    mCallbacks.setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2);
+                    mCallbacks.setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2,
+                            msg.getData().getBoolean(SHOW_IME_SWITCHER_KEY, false));
                     break;
                 case MSG_SET_HARD_KEYBOARD_STATUS:
                     mCallbacks.setHardKeyboardStatus(msg.arg1 != 0, msg.arg2 != 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
new file mode 100644
index 0000000..5b2ea0b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+
+import com.android.systemui.ExpandHelper;
+import com.android.systemui.Gefingerpoken;
+import com.android.systemui.R;
+
+/**
+ * A utility class to enable the downward swipe on the lockscreen to go to the full shade and expand
+ * the notification where the drag started.
+ */
+public class DragDownHelper implements Gefingerpoken {
+
+    private static final float RUBBERBAND_FACTOR_EXPANDABLE = 0.5f;
+    private static final float RUBBERBAND_FACTOR_STATIC = 0.15f;
+
+    private static final int SPRING_BACK_ANIMATION_LENGTH_MS = 375;
+
+    private int mMinDragDistance;
+    private ExpandHelper.Callback mCallback;
+    private float mInitialTouchX;
+    private float mInitialTouchY;
+    private boolean mDraggingDown;
+    private float mTouchSlop;
+    private OnDragDownListener mOnDragDownListener;
+    private View mHost;
+    private final int[] mTemp2 = new int[2];
+    private boolean mDraggedFarEnough;
+    private ExpandableView mStartingChild;
+    private Interpolator mInterpolator;
+
+    public DragDownHelper(Context context, View host, ExpandHelper.Callback callback,
+            OnDragDownListener onDragDownListener) {
+        mMinDragDistance = context.getResources().getDimensionPixelSize(
+                R.dimen.keyguard_drag_down_min_distance);
+        mInterpolator =
+                AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
+        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+        mCallback = callback;
+        mOnDragDownListener = onDragDownListener;
+        mHost = host;
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent event) {
+        final float x = event.getX();
+        final float y = event.getY();
+
+        switch (event.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+                mDraggedFarEnough = false;
+                mDraggingDown = false;
+                mStartingChild = null;
+                mInitialTouchY = y;
+                mInitialTouchX = x;
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                final float h = y - mInitialTouchY;
+                if (h > mTouchSlop && h > Math.abs(x - mInitialTouchX)) {
+                    mDraggingDown = true;
+                    captureStartingChild(mInitialTouchX, mInitialTouchY);
+                    mInitialTouchY = y;
+                    mInitialTouchX = x;
+                    return true;
+                }
+                break;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (!mDraggingDown) {
+            return false;
+        }
+        final float x = event.getX();
+        final float y = event.getY();
+
+        switch (event.getActionMasked()) {
+            case MotionEvent.ACTION_MOVE:
+                final float h = y - mInitialTouchY;
+                captureStartingChild(mInitialTouchX, mInitialTouchY);
+                if (mStartingChild != null) {
+                    handleExpansion(h, mStartingChild);
+                }
+                if (h > mMinDragDistance) {
+                    if (!mDraggedFarEnough) {
+                        mDraggedFarEnough = true;
+                        mOnDragDownListener.onThresholdReached();
+                    }
+                } else {
+                    if (mDraggedFarEnough) {
+                        mDraggedFarEnough = false;
+                        mOnDragDownListener.onDragDownReset();
+                    }
+                }
+                return true;
+            case MotionEvent.ACTION_UP:
+                if (mDraggedFarEnough) {
+                    if (mStartingChild != null) {
+                        mCallback.setUserLockedChild(mStartingChild, false);
+                    }
+                    mOnDragDownListener.onDraggedDown(mStartingChild);
+                    mDraggingDown = false;
+                } else {
+                    stopDragging();
+                    return false;
+                }
+                break;
+            case MotionEvent.ACTION_CANCEL:
+                stopDragging();
+                return false;
+        }
+        return false;
+    }
+
+    private void captureStartingChild(float x, float y) {
+        if (mStartingChild == null) {
+            mStartingChild = findView(x, y);
+            if (mStartingChild != null) {
+                mCallback.setUserLockedChild(mStartingChild, true);
+            }
+        }
+    }
+
+    private void handleExpansion(float heightDelta, ExpandableView child) {
+        if (heightDelta < 0) {
+            heightDelta = 0;
+        }
+        boolean expandable = child.isContentExpandable();
+        float rubberbandFactor = expandable
+                ? RUBBERBAND_FACTOR_EXPANDABLE
+                : RUBBERBAND_FACTOR_STATIC;
+        float rubberband = heightDelta * rubberbandFactor;
+        if (expandable && (rubberband + child.getMinHeight()) > child.getMaxHeight()) {
+            float overshoot = (rubberband + child.getMinHeight()) - child.getMaxHeight();
+            overshoot *= (1 - RUBBERBAND_FACTOR_STATIC);
+            rubberband -= overshoot;
+        }
+        child.setActualHeight((int) (child.getMinHeight() + rubberband));
+    }
+
+    private void cancelExpansion(final ExpandableView child) {
+        if (child.getActualHeight() == child.getMinHeight()) {
+            return;
+        }
+        ObjectAnimator anim = ObjectAnimator.ofInt(child, "actualHeight",
+                child.getActualHeight(), child.getMinHeight());
+        anim.setInterpolator(mInterpolator);
+        anim.setDuration(SPRING_BACK_ANIMATION_LENGTH_MS);
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mCallback.setUserLockedChild(child, false);
+            }
+        });
+        anim.start();
+    }
+
+    private void stopDragging() {
+        if (mStartingChild != null) {
+            cancelExpansion(mStartingChild);
+        }
+        mDraggingDown = false;
+        mOnDragDownListener.onDragDownReset();
+    }
+
+    private ExpandableView findView(float x, float y) {
+        mHost.getLocationOnScreen(mTemp2);
+        x += mTemp2[0];
+        y += mTemp2[1];
+        return mCallback.getChildAtRawPosition(x, y);
+    }
+
+    public interface OnDragDownListener {
+        void onDraggedDown(View startingChild);
+        void onDragDownReset();
+        void onThresholdReached();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 61aad6f..39f2bb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -52,7 +52,6 @@
     private NotificationContentView mPublicLayout;
     private NotificationContentView mPrivateLayout;
     private int mMaxExpandHeight;
-    private NotificationActivator mActivator;
 
     public ExpandableNotificationRow(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -63,8 +62,6 @@
         super.onFinishInflate();
         mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
         mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
-
-        mActivator = new NotificationActivator(this);
     }
 
     @Override
@@ -137,7 +134,7 @@
      */
     public void setSystemExpanded(boolean expand) {
         mIsSystemExpanded = expand;
-        applyExpansionToLayout();
+        notifyHeightChanged();
     }
 
     /**
@@ -145,7 +142,7 @@
      */
     public void setExpansionDisabled(boolean expansionDisabled) {
         mExpansionDisabled = expansionDisabled;
-        applyExpansionToLayout();
+        notifyHeightChanged();
     }
 
     /**
@@ -160,13 +157,8 @@
         }
     }
 
-    /**
-     * If {@link #isExpanded()} then this is the greatest possible height this view can
-     * get and otherwise it is {@link #mRowMinHeight}.
-     *
-     * @return the maximum allowed expansion height of this view.
-     */
-    public int getMaximumAllowedExpandHeight() {
+    @Override
+    public int getIntrinsicHeight() {
         if (isUserLocked()) {
             return getActualHeight();
         }
@@ -213,34 +205,27 @@
         mPrivateLayout.setVisibility(show ? View.GONE : View.VISIBLE);
     }
 
-    /**
-     * Sets the notification as dimmed, meaning that it will appear in a more gray variant.
-     */
-    public void setDimmed(boolean dimmed) {
-        super.setDimmed(dimmed);
-        mActivator.setDimmed(dimmed);
-    }
-
     public int getMaxExpandHeight() {
         return mMaxExpandHeight;
     }
 
-    public NotificationActivator getActivator() {
-        return mActivator;
-    }
-
     /**
      * @return the potential height this view could expand in addition.
      */
     public int getExpandPotential() {
-        return getMaximumAllowedExpandHeight() - getActualHeight();
+        return getIntrinsicHeight() - getActualHeight();
     }
 
     @Override
-    public void setActualHeight(int height) {
-        mPrivateLayout.setActualHeight(height);
+    public boolean isContentExpandable() {
+        return mPrivateLayout.isContentExpandable();
+    }
+
+    @Override
+    public void setActualHeight(int height, boolean notifyListeners) {
+        mPrivateLayout.setActualHeight(height, notifyListeners);
         invalidate();
-        super.setActualHeight(height);
+        super.setActualHeight(height, notifyListeners);
     }
 
     @Override
@@ -249,6 +234,11 @@
     }
 
     @Override
+    public int getMinHeight() {
+        return mPrivateLayout.getMinHeight();
+    }
+
+    @Override
     public void setClipTopAmount(int clipTopAmount) {
         super.setClipTopAmount(clipTopAmount);
         mPrivateLayout.setClipTopAmount(clipTopAmount);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index 43eb5b5..a42c194 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -33,8 +33,8 @@
     }
 
     @Override
-    public void setActualHeight(int actualHeight) {
-        super.setActualHeight(actualHeight);
+    public void setActualHeight(int actualHeight, boolean notifyListeners) {
+        super.setActualHeight(actualHeight, notifyListeners);
         updateOutline();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 35913fa..4bd0e1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -17,12 +17,8 @@
 package com.android.systemui.statusbar;
 
 import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Outline;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
 import android.view.View;
 import android.widget.FrameLayout;
 
@@ -34,7 +30,6 @@
     private OnHeightChangedListener mOnHeightChangedListener;
     protected int mActualHeight;
     protected int mClipTopAmount;
-    protected Drawable mCustomBackground;
     private boolean mActualHeightInitialized;
 
     public ExpandableView(Context context, AttributeSet attrs) {
@@ -42,27 +37,6 @@
     }
 
     @Override
-    protected void onDraw(Canvas canvas) {
-        if (mCustomBackground != null) {
-            mCustomBackground.setBounds(0, mClipTopAmount, getWidth(), mActualHeight);
-            mCustomBackground.draw(canvas);
-        }
-    }
-
-    @Override
-    protected boolean verifyDrawable(Drawable who) {
-        return super.verifyDrawable(who) || who == mCustomBackground;
-    }
-
-    @Override
-    protected void drawableStateChanged() {
-        final Drawable d = mCustomBackground;
-        if (d != null && d.isStateful()) {
-            d.setState(getDrawableState());
-        }
-    }
-
-    @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
         if (!mActualHeightInitialized && mActualHeight == 0) {
@@ -71,22 +45,41 @@
         mActualHeightInitialized = true;
     }
 
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        if (filterMotionEvent(ev)) {
+            return super.dispatchTouchEvent(ev);
+        }
+        return false;
+    }
+
+    private boolean filterMotionEvent(MotionEvent event) {
+        return event.getActionMasked() != MotionEvent.ACTION_DOWN
+                || event.getY() > mClipTopAmount && event.getY() < mActualHeight;
+    }
+
     /**
      * Sets the actual height of this notification. This is different than the laid out
      * {@link View#getHeight()}, as we want to avoid layouting during scrolling and expanding.
+     *
+     * @param actualHeight The height of this notification.
+     * @param notifyListeners Whether the listener should be informed about the change.
      */
-    public void setActualHeight(int actualHeight) {
+    public void setActualHeight(int actualHeight, boolean notifyListeners) {
         mActualHeight = actualHeight;
-        invalidate();
-        if (mOnHeightChangedListener != null) {
-            mOnHeightChangedListener.onHeightChanged(this);
+        if (notifyListeners) {
+            notifyHeightChanged();
         }
     }
 
+    public void setActualHeight(int actualHeight) {
+        setActualHeight(actualHeight, true);
+    }
+
     /**
      * See {@link #setActualHeight}.
      *
-     * @return The actual height of this notification.
+     * @return The current actual height of this notification.
      */
     public int getActualHeight() {
         return mActualHeight;
@@ -95,7 +88,32 @@
     /**
      * @return The maximum height of this notification.
      */
-    public abstract int getMaxHeight();
+    public int getMaxHeight() {
+        return getHeight();
+    }
+
+    /**
+     * @return The minimum height of this notification.
+     */
+    public int getMinHeight() {
+        return getHeight();
+    }
+
+    /**
+     * Sets the notification as dimmed. The default implementation does nothing.
+     *
+     * @param dimmed Whether the notification should be dimmed.
+     * @param fade Whether an animation should be played to change the state.
+     */
+    public void setDimmed(boolean dimmed, boolean fade) {
+    }
+
+    /**
+     * @return The desired notification height.
+     */
+    public int getIntrinsicHeight() {
+        return getHeight();
+    }
 
     /**
      * Sets the amount this view should be clipped from the top. This is used when an expanded
@@ -105,7 +123,10 @@
      */
     public void setClipTopAmount(int clipTopAmount) {
         mClipTopAmount = clipTopAmount;
-        invalidate();
+    }
+
+    public int getClipTopAmount() {
+        return mClipTopAmount;
     }
 
     public void setOnHeightChangedListener(OnHeightChangedListener listener) {
@@ -113,22 +134,16 @@
     }
 
     /**
-     * Sets a custom background drawable. As we need to change our bounds independently of layout,
-     * we need the notition of a custom background.
+     * @return Whether we can expand this views content.
      */
-    public void setCustomBackground(Drawable customBackground) {
-        if (mCustomBackground != null) {
-            mCustomBackground.setCallback(null);
-            unscheduleDrawable(mCustomBackground);
-        }
-        mCustomBackground = customBackground;
-        mCustomBackground.setCallback(this);
-        setWillNotDraw(customBackground == null);
-        invalidate();
+    public boolean isContentExpandable() {
+        return false;
     }
 
-    public void setCustomBackgroundResource(int drawableResId) {
-        setCustomBackground(getResources().getDrawable(drawableResId));
+    public void notifyHeightChanged() {
+        if (mOnHeightChangedListener != null) {
+            mOnHeightChangedListener.onHeightChanged(this);
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
new file mode 100644
index 0000000..0606a94
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+
+/**
+ * Utility class to calculate general fling animation when the finger is released.
+ */
+public class FlingAnimationUtils {
+
+    private static final float LINEAR_OUT_SLOW_IN_Y2 = 0.35f;
+    private static final float MAX_LENGTH_SECONDS = 0.4f;
+    private static final float MIN_VELOCITY_DP_PER_SECOND = 250;
+
+    /**
+     * Crazy math. http://en.wikipedia.org/wiki/B%C3%A9zier_curve
+     */
+    private static final float LINEAR_OUT_SLOW_IN_START_GRADIENT = 1/LINEAR_OUT_SLOW_IN_Y2;
+
+    private Interpolator mLinearOutSlowIn;
+    private Interpolator mFastOutSlowIn;
+    private float mMinVelocityPxPerSecond;
+
+    public FlingAnimationUtils(Context ctx) {
+        mLinearOutSlowIn = new PathInterpolator(0, 0, LINEAR_OUT_SLOW_IN_Y2, 1);
+        mFastOutSlowIn
+                = AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_slow_in);
+        mMinVelocityPxPerSecond
+                = MIN_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density;
+    }
+
+    /**
+     * Applies the interpolator and length to the animator, such that the fling animation is
+     * consistent with the finger motion.
+     *
+     * @param animator the animator to apply
+     * @param currValue the current value
+     * @param endValue the end value of the animator
+     * @param velocity the current velocity of the motion
+     */
+    public void apply(ValueAnimator animator, float currValue, float endValue, float velocity) {
+        float diff = Math.abs(endValue - currValue);
+        float velAbs = Math.abs(velocity);
+        float durationSeconds = LINEAR_OUT_SLOW_IN_START_GRADIENT * diff / velAbs;
+        if (durationSeconds <= MAX_LENGTH_SECONDS) {
+            animator.setInterpolator(mLinearOutSlowIn);
+        } else if (velAbs >= mMinVelocityPxPerSecond) {
+
+            // Cross fade between fast-out-slow-in and linear interpolator with current velocity.
+            durationSeconds = MAX_LENGTH_SECONDS;
+            VelocityInterpolator velocityInterpolator
+                    = new VelocityInterpolator(durationSeconds, velAbs, diff);
+            InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator(
+                    velocityInterpolator, mLinearOutSlowIn, mLinearOutSlowIn);
+            animator.setInterpolator(superInterpolator);
+        } else {
+
+            // Just use a normal interpolator which doesn't take the velocity into account.
+            durationSeconds = MAX_LENGTH_SECONDS;
+            animator.setInterpolator(mFastOutSlowIn);
+        }
+        animator.setDuration((long) (durationSeconds * 1000));
+    }
+
+    /**
+     * An interpolator which interpolates two interpolators with an interpolator.
+     */
+    private static final class InterpolatorInterpolator implements Interpolator {
+
+        private Interpolator mInterpolator1;
+        private Interpolator mInterpolator2;
+        private Interpolator mCrossfader;
+
+        InterpolatorInterpolator(Interpolator interpolator1, Interpolator interpolator2,
+                Interpolator crossfader) {
+            mInterpolator1 = interpolator1;
+            mInterpolator2 = interpolator2;
+            mCrossfader = crossfader;
+        }
+
+        @Override
+        public float getInterpolation(float input) {
+            float t = mCrossfader.getInterpolation(input);
+            return (1 - t) * mInterpolator1.getInterpolation(input)
+                    + t * mInterpolator2.getInterpolation(input);
+        }
+    }
+
+    /**
+     * An interpolator which interpolates with a fixed velocity.
+     */
+    private static final class VelocityInterpolator implements Interpolator {
+
+        private float mDurationSeconds;
+        private float mVelocity;
+        private float mDiff;
+
+        private VelocityInterpolator(float durationSeconds, float velocity, float diff) {
+            mDurationSeconds = durationSeconds;
+            mVelocity = velocity;
+            mDiff = diff;
+        }
+
+        @Override
+        public float getInterpolation(float input) {
+            float time = input * mDurationSeconds;
+            return time * mVelocity / mDiff;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java
deleted file mode 100644
index 620e457..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar;
-
-import android.content.Context;
-import android.view.View;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-import com.android.systemui.R;
-
-/**
- * A helper class used by both {@link com.android.systemui.statusbar.ExpandableNotificationRow} and
- * {@link com.android.systemui.statusbar.NotificationOverflowIconsView} to make a notification look
- * active after tapping it once on the Keyguard.
- */
-public class NotificationActivator {
-
-    private static final int ANIMATION_LENGTH_MS = 220;
-    private static final float INVERSE_ALPHA = 0.9f;
-    private static final float DIMMED_SCALE = 0.95f;
-
-    private final View mTargetView;
-
-    private final Interpolator mFastOutSlowInInterpolator;
-    private final Interpolator mLinearOutSlowInInterpolator;
-    private final int mTranslationZ;
-
-    public NotificationActivator(View targetView) {
-        mTargetView = targetView;
-        Context ctx = targetView.getContext();
-        mFastOutSlowInInterpolator =
-                AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_slow_in);
-        mLinearOutSlowInInterpolator =
-                AnimationUtils.loadInterpolator(ctx, android.R.interpolator.linear_out_slow_in);
-        mTranslationZ =
-                ctx.getResources().getDimensionPixelSize(R.dimen.z_distance_between_notifications);
-        mTargetView.animate().setDuration(ANIMATION_LENGTH_MS);
-    }
-
-    public void activateInverse() {
-        mTargetView.animate().withLayer().alpha(INVERSE_ALPHA);
-    }
-
-    public void activate() {
-        mTargetView.animate()
-                .setInterpolator(mLinearOutSlowInInterpolator)
-                .scaleX(1)
-                .scaleY(1)
-                .translationZBy(mTranslationZ);
-    }
-
-    public void reset() {
-        mTargetView.animate()
-                .setInterpolator(mFastOutSlowInInterpolator)
-                .scaleX(DIMMED_SCALE)
-                .scaleY(DIMMED_SCALE)
-                .translationZBy(-mTranslationZ);
-        if (mTargetView.getAlpha() != 1.0f) {
-            mTargetView.animate().withLayer().alpha(1);
-        }
-    }
-
-    public void setDimmed(boolean dimmed) {
-        if (dimmed) {
-            mTargetView.setScaleX(DIMMED_SCALE);
-            mTargetView.setScaleY(DIMMED_SCALE);
-        } else {
-            mTargetView.setScaleX(1);
-            mTargetView.setScaleY(1);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index fd0cb08..9df2701 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -70,8 +70,8 @@
     }
 
     @Override
-    public void setActualHeight(int actualHeight) {
-        super.setActualHeight(actualHeight);
+    public void setActualHeight(int actualHeight, boolean notifyListeners) {
+        super.setActualHeight(actualHeight, notifyListeners);
         selectLayout();
         updateClipping();
     }
@@ -84,15 +84,16 @@
     }
 
     @Override
+    public int getMinHeight() {
+        return mSmallHeight;
+    }
+
+    @Override
     public void setClipTopAmount(int clipTopAmount) {
         super.setClipTopAmount(clipTopAmount);
         updateClipping();
     }
 
-    public int getClipTopAmount() {
-        return mClipTopAmount;
-    }
-
     private void updateClipping() {
         mClipBounds.set(0, mClipTopAmount, getWidth(), mActualHeight);
         setClipBounds(mClipBounds);
@@ -125,4 +126,9 @@
     public void notifyContentUpdated() {
         selectLayout();
     }
+
+    @Override
+    public boolean isContentExpandable() {
+        return mExpandedChild != null;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
index 8ebd50d..451c5c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
@@ -28,49 +28,19 @@
 public class NotificationOverflowContainer extends ActivatableNotificationView {
 
     private NotificationOverflowIconsView mIconsView;
-    private NotificationActivator mActivator;
 
     public NotificationOverflowContainer(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
-    public void setActualHeight(int currentHeight) {
-        // noop
-    }
-
-    @Override
-    public int getActualHeight() {
-        return getHeight();
-    }
-
-    @Override
-    public int getMaxHeight() {
-        return getHeight();
-    }
-
-    @Override
-    public void setClipTopAmount(int clipTopAmount) {
-        // noop
-    }
-
-    @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
         mIconsView = (NotificationOverflowIconsView) findViewById(R.id.overflow_icons_view);
         mIconsView.setMoreText((TextView) findViewById(R.id.more_text));
-
-        mActivator = new NotificationActivator(this);
-        mActivator.setDimmed(true);
-        setLocked(true);
-        setDimmed(true);
     }
 
     public NotificationOverflowIconsView getIconsView() {
         return mIconsView;
     }
-
-    public NotificationActivator getActivator() {
-        return mActivator;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 89da08f..2bc6f9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -28,19 +28,19 @@
 import android.widget.LinearLayout;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl;
 
 // Intimately tied to the design of res/layout/signal_cluster_view.xml
 public class SignalClusterView
         extends LinearLayout
-        implements NetworkController.SignalCluster {
+        implements NetworkControllerImpl.SignalCluster {
 
     static final boolean DEBUG = false;
     static final String TAG = "SignalClusterView";
     static final PorterDuffColorFilter PROBLEM_FILTER
             = new PorterDuffColorFilter(0xffab653b, PorterDuff.Mode.SRC_ATOP);
 
-    NetworkController mNC;
+    NetworkControllerImpl mNC;
 
     private boolean mWifiVisible = false;
     private int mWifiStrengthId = 0;
@@ -67,7 +67,7 @@
         super(context, attrs, defStyle);
     }
 
-    public void setNetworkController(NetworkController nc) {
+    public void setNetworkController(NetworkControllerImpl nc) {
         if (DEBUG) Log.d(TAG, "NetworkController=" + nc);
         mNC = nc;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java
new file mode 100644
index 0000000..9d75228
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+
+/**
+ * Class to encapsulate all possible status bar states regarding Keyguard.
+ */
+public class StatusBarState {
+
+    /**
+     * The status bar is in the "normal" shade mode.
+     */
+    public static final int SHADE = 0;
+
+    /**
+     * Status bar is currently the Keyguard.
+     */
+    public static final int KEYGUARD = 1;
+
+    /**
+     * Status bar is in the special mode, where it is fully interactive but still locked. So
+     * dismissing the shade will still show the bouncer.
+     */
+    public static final int SHADE_LOCKED = 2;
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java
new file mode 100644
index 0000000..5bc7e5a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java
@@ -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 com.android.systemui.statusbar.phone;
+
+import android.content.Intent;
+
+/**
+ * An interface to start activities. This is used to as a callback from the views to
+ * {@link PhoneStatusBar} to allow custom handling for starting the activity, i.e. dismissing the
+ * Keyguard.
+ */
+public interface ActivityStarter {
+    public void startActivity(Intent intent);
+}
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 a3cf0f2..869edff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -27,7 +27,7 @@
 import com.android.systemui.DemoMode;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.StatusBarIconView;
-import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.LocationControllerImpl;
 
 public class DemoStatusIcons extends LinearLayout implements DemoMode {
     private final LinearLayout mStatusIcons;
@@ -74,9 +74,9 @@
             }
             String location = args.getString("location");
             if (location != null) {
-                int iconId = location.equals("show") ? LocationController.LOCATION_STATUS_ICON_ID
+                int iconId = location.equals("show") ? LocationControllerImpl.LOCATION_STATUS_ICON_ID
                         : 0;
-                updateSlot(LocationController.LOCATION_STATUS_ICON_PLACEHOLDER, null, iconId);
+                updateSlot(LocationControllerImpl.LOCATION_STATUS_ICON_PLACEHOLDER, null, iconId);
             }
             String alarm = args.getString("alarm");
             if (alarm != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 3cc22ef..58b3f2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -42,14 +43,18 @@
  * Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
  * text.
  */
-public class KeyguardBottomAreaView extends FrameLayout {
+public class KeyguardBottomAreaView extends FrameLayout
+        implements SwipeAffordanceView.AffordanceListener {
 
     final static String TAG = "PhoneStatusBar/KeyguardBottomAreaView";
 
-    private View mCameraButton;
-    private float mCameraDragDistance;
+    private static final Intent PHONE_INTENT = new Intent(Intent.ACTION_DIAL);
+
+    private SwipeAffordanceView mCameraButton;
+    private SwipeAffordanceView mPhoneButton;
+
     private PowerManager mPowerManager;
-    private int mScaledTouchSlop;
+    private ActivityStarter mActivityStarter;
 
     public KeyguardBottomAreaView(Context context) {
         super(context);
@@ -71,20 +76,37 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mCameraButton = findViewById(R.id.camera_button);
+        mCameraButton = (SwipeAffordanceView) findViewById(R.id.camera_button);
+        mPhoneButton = (SwipeAffordanceView) findViewById(R.id.phone_button);
+        mCameraButton.setAffordanceListener(this);
+        mPhoneButton.setAffordanceListener(this);
         watchForDevicePolicyChanges();
         watchForAccessibilityChanges();
         updateCameraVisibility();
-        mCameraDragDistance = getResources().getDimension(R.dimen.camera_drag_distance);
-        mScaledTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
+        updatePhoneVisibility();
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
     }
 
+    public void setActivityStarter(ActivityStarter activityStarter) {
+        mActivityStarter = activityStarter;
+    }
+
     private void updateCameraVisibility() {
         boolean visible = !isCameraDisabledByDpm();
         mCameraButton.setVisibility(visible ? View.VISIBLE : View.GONE);
     }
 
+    private void updatePhoneVisibility() {
+        boolean visible = isPhoneVisible();
+        mPhoneButton.setVisibility(visible ? View.VISIBLE : View.GONE);
+    }
+
+    private boolean isPhoneVisible() {
+        PackageManager pm = mContext.getPackageManager();
+        return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
+                && pm.resolveActivity(PHONE_INTENT, 0) != null;
+    }
+
     private boolean isCameraDisabledByDpm() {
         final DevicePolicyManager dpm =
                 (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
@@ -136,15 +158,8 @@
     }
 
     private void enableAccessibility(boolean touchExplorationEnabled) {
-
-        // Add a touch handler or accessibility click listener for camera button.
-        if (touchExplorationEnabled) {
-            mCameraButton.setOnTouchListener(null);
-            mCameraButton.setOnClickListener(mCameraClickListener);
-        } else {
-            mCameraButton.setOnTouchListener(mCameraTouchListener);
-            mCameraButton.setOnClickListener(null);
-        }
+        mCameraButton.enableAccessibility(touchExplorationEnabled);
+        mPhoneButton.enableAccessibility(touchExplorationEnabled);
     }
 
     private void launchCamera() {
@@ -153,80 +168,21 @@
                 UserHandle.CURRENT);
     }
 
-    private final OnClickListener mCameraClickListener = new OnClickListener() {
-        @Override
-        public void onClick(View v) {
+    private void launchPhone() {
+        mActivityStarter.startActivity(PHONE_INTENT);
+    }
+
+    @Override
+    public void onUserActivity(long when) {
+        mPowerManager.userActivity(when, false);
+    }
+
+    @Override
+    public void onActionPerformed(SwipeAffordanceView view) {
+        if (view == mCameraButton) {
             launchCamera();
+        } else if (view == mPhoneButton) {
+            launchPhone();
         }
-    };
-
-    private final OnTouchListener mCameraTouchListener = new OnTouchListener() {
-        private float mStartX;
-        private boolean mTouchSlopReached;
-        private boolean mSkipCancelAnimation;
-
-        @Override
-        public boolean onTouch(final View cameraButtonView, MotionEvent event) {
-            float realX = event.getRawX();
-            switch (event.getAction()) {
-                case MotionEvent.ACTION_DOWN:
-                    mStartX = realX;
-                    mTouchSlopReached = false;
-                    mSkipCancelAnimation = false;
-                    break;
-                case MotionEvent.ACTION_MOVE:
-                    if (realX > mStartX) {
-                        realX = mStartX;
-                    }
-                    if (realX < mStartX - mCameraDragDistance) {
-                        cameraButtonView.setPressed(true);
-                        mPowerManager.userActivity(event.getEventTime(), false);
-                    } else {
-                        cameraButtonView.setPressed(false);
-                    }
-                    if (realX < mStartX - mScaledTouchSlop) {
-                        mTouchSlopReached = true;
-                    }
-                    cameraButtonView.setTranslationX(Math.max(realX - mStartX,
-                            -mCameraDragDistance));
-                    break;
-                case MotionEvent.ACTION_UP:
-                    if (realX < mStartX - mCameraDragDistance) {
-                        launchCamera();
-                        cameraButtonView.animate().x(-cameraButtonView.getWidth())
-                                .setInterpolator(new AccelerateInterpolator(2f)).withEndAction(
-                                new Runnable() {
-                                    @Override
-                                    public void run() {
-                                        cameraButtonView.setTranslationX(0);
-                                    }
-                                });
-                        mSkipCancelAnimation = true;
-                    }
-                    if (realX < mStartX - mScaledTouchSlop) {
-                        mTouchSlopReached = true;
-                    }
-                    if (!mTouchSlopReached) {
-                        mSkipCancelAnimation = true;
-                        cameraButtonView.animate().translationX(-mCameraDragDistance / 2).
-                                setInterpolator(new DecelerateInterpolator()).withEndAction(
-                                new Runnable() {
-                                    @Override
-                                    public void run() {
-                                        cameraButtonView.animate().translationX(0).
-                                                setInterpolator(new AccelerateInterpolator());
-                                    }
-                                });
-                    }
-                case MotionEvent.ACTION_CANCEL:
-                    cameraButtonView.setPressed(false);
-                    if (!mSkipCancelAnimation) {
-                        cameraButtonView.animate().translationX(0)
-                                .setInterpolator(new AccelerateInterpolator(2f));
-                    }
-                    break;
-            }
-            return true;
-        }
-    };
+    }
 }
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 1ffb4ee..d8e1766 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.phone;
 
 import android.content.Context;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -160,4 +161,9 @@
             return false;
         }
     }
+
+    public boolean interceptMediaKey(KeyEvent event) {
+        ensureView();
+        return mKeyguardView.interceptMediaKey(event);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
new file mode 100644
index 0000000..c26f15e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.Intent;
+import android.graphics.Canvas;
+import android.graphics.Path;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.ContactsContract;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
+
+import com.android.systemui.R;
+import com.android.systemui.settings.UserSwitcherHostView;
+import com.android.systemui.statusbar.policy.UserInfoController;
+
+/**
+ * Image button for the multi user switcher.
+ */
+public class MultiUserSwitch extends ImageButton implements View.OnClickListener,
+        UserInfoController.OnUserInfoChangedListener {
+
+    private ViewGroup mOverlayParent;
+
+    public MultiUserSwitch(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        setOnClickListener(this);
+    }
+
+    public void setOverlayParent(ViewGroup parent) {
+        mOverlayParent = parent;
+    }
+
+    @Override
+    public void onClick(View v) {
+        final UserManager um = UserManager.get(getContext());
+        if (um.isUserSwitcherEnabled()) {
+            final UserSwitcherHostView switcher =
+                    (UserSwitcherHostView) LayoutInflater.from(getContext()).inflate(
+                            R.layout.user_switcher_host, mOverlayParent, false);
+            switcher.setFinishRunnable(new Runnable() {
+                @Override
+                public void run() {
+                    mOverlayParent.removeView(switcher);
+                }
+            });
+            switcher.refreshUsers();
+            mOverlayParent.addView(switcher);
+        } else {
+            Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
+                    getContext(), v, ContactsContract.Profile.CONTENT_URI,
+                    ContactsContract.QuickContact.MODE_LARGE, null);
+            getContext().startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+        }
+    }
+
+    public void setUserInfoController(UserInfoController userInfoController) {
+        userInfoController.addListener(this);
+    }
+
+    @Override
+    public void onUserInfoChanged(String name, Drawable picture) {
+        setImageDrawable(picture);
+    }
+}
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 3fae3f0..089757a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -39,6 +39,7 @@
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
+import android.view.inputmethod.InputMethodManager;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
@@ -142,6 +143,14 @@
         }
     };
 
+    private final OnClickListener mImeSwitcherClickListener = new OnClickListener() {
+        @Override
+        public void onClick(View view) {
+            ((InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE))
+                    .showInputMethodPicker();
+        }
+    };
+
     private class H extends Handler {
         public void handleMessage(Message m) {
             switch (m.what) {
@@ -233,6 +242,10 @@
         return mCurrentView.findViewById(R.id.home);
     }
 
+    public View getImeSwitchButton() {
+        return mCurrentView.findViewById(R.id.ime_switcher);
+    }
+
     // for when home is disabled, but search isn't
     public View getSearchLight() {
         return mCurrentView.findViewById(R.id.search_light);
@@ -283,6 +296,12 @@
 
         ((ImageView)getRecentsButton()).setImageDrawable(mVertical ? mRecentLandIcon : mRecentIcon);
 
+        final boolean showImeButton = ((hints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
+        getImeSwitchButton().setVisibility(showImeButton ? View.VISIBLE : View.INVISIBLE);
+        // Update menu button in case the IME state has changed.
+        setMenuVisibility(mShowMenu, true);
+
+
         setDisabledFlags(mDisabledFlags, true);
     }
 
@@ -363,7 +382,10 @@
 
         mShowMenu = show;
 
-        getMenuButton().setVisibility(mShowMenu ? View.VISIBLE : View.INVISIBLE);
+        // Only show Menu if IME switcher not shown.
+        final boolean shouldShow = mShowMenu &&
+                ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) == 0);
+        getMenuButton().setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE);
     }
 
     @Override
@@ -379,6 +401,8 @@
 
         mCurrentView = mRotatedViews[Surface.ROTATION_0];
 
+        getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
+
         watchForAccessibilityChanges();
     }
 
@@ -424,6 +448,8 @@
         mCurrentView = mRotatedViews[rot];
         mCurrentView.setVisibility(View.VISIBLE);
 
+        getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
+
         mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);
 
         // force the low profile & disabled states into compliance
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 712eec8..9054fe3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -16,28 +16,68 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
+import android.view.VelocityTracker;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.LinearLayout;
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.FlingAnimationUtils;
 import com.android.systemui.statusbar.GestureRecorder;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 public class NotificationPanelView extends PanelView implements
-        ExpandableView.OnHeightChangedListener {
+        ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
+        View.OnClickListener {
     public static final boolean DEBUG_GESTURES = true;
+    private static final int EXPANSION_ANIMATION_LENGTH = 375;
 
     PhoneStatusBar mStatusBar;
-    private View mHeader;
+    private StatusBarHeaderView mHeader;
+    private View mQsContainer;
     private View mKeyguardStatusView;
+    private ObservableScrollView mScrollView;
+    private View mStackScrollerContainer;
 
     private NotificationStackScrollLayout mNotificationStackScroller;
-    private boolean mTrackingSettings;
     private int mNotificationTopPadding;
+    private boolean mAnimateNextTopPaddingChange;
+
+    private int mTrackingPointer;
+    private VelocityTracker mVelocityTracker;
+    private boolean mTracking;
+
+    /**
+     * Whether we are currently handling a motion gesture in #onInterceptTouchEvent, but haven't
+     * intercepted yet.
+     */
+    private boolean mIntercepting;
+    private boolean mQsExpanded;
+    private float mInitialHeightOnTouch;
+    private float mInitialTouchX;
+    private float mInitialTouchY;
+    private float mLastTouchX;
+    private float mLastTouchY;
+    private float mQsExpansionHeight;
+    private int mQsMinExpansionHeight;
+    private int mQsMaxExpansionHeight;
+    private int mMinStackHeight;
+    private float mNotificationTranslation;
+    private int mStackScrollerIntrinsicPadding;
+    private boolean mQsExpansionEnabled = true;
+    private ValueAnimator mQsExpansionAnimator;
+    private FlingAnimationUtils mFlingAnimationUtils;
 
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -61,14 +101,21 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-
-        mHeader = findViewById(R.id.header);
+        mHeader = (StatusBarHeaderView) findViewById(R.id.header);
+        mHeader.getBackgroundView().setOnClickListener(this);
+        mHeader.setOverlayParent(this);
         mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
+        mStackScrollerContainer = findViewById(R.id.notification_container_parent);
+        mQsContainer = findViewById(R.id.quick_settings_container);
+        mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
+        mScrollView.setListener(this);
         mNotificationStackScroller = (NotificationStackScrollLayout)
                 findViewById(R.id.notification_stack_scroller);
         mNotificationStackScroller.setOnHeightChangedListener(this);
         mNotificationTopPadding = getResources().getDimensionPixelSize(
                 R.dimen.notifications_top_padding);
+        mMinStackHeight = getResources().getDimensionPixelSize(R.dimen.collapsed_stack_height);
+        mFlingAnimationUtils = new FlingAnimationUtils(getContext());
     }
 
     @Override
@@ -76,9 +123,49 @@
         super.onLayout(changed, left, top, right, bottom);
         int keyguardBottomMargin =
                 ((MarginLayoutParams) mKeyguardStatusView.getLayoutParams()).bottomMargin;
-        mNotificationStackScroller.setTopPadding(mStatusBar.isOnKeyguard()
-                ? mKeyguardStatusView.getBottom() + keyguardBottomMargin
-                : mHeader.getBottom() + mNotificationTopPadding);
+        if (!mQsExpanded) {
+            mStackScrollerIntrinsicPadding = mStatusBar.getBarState() == StatusBarState.KEYGUARD
+                    ? mKeyguardStatusView.getBottom() + keyguardBottomMargin
+                    : mHeader.getBottom() + mNotificationTopPadding;
+            mNotificationStackScroller.setTopPadding(mStackScrollerIntrinsicPadding,
+                    mAnimateNextTopPaddingChange);
+            mAnimateNextTopPaddingChange = false;
+        }
+
+        // Calculate quick setting heights.
+        mQsMinExpansionHeight = mHeader.getCollapsedHeight();
+        mQsMaxExpansionHeight = mHeader.getExpandedHeight() + mQsContainer.getHeight();
+        if (mQsExpansionHeight == 0) {
+            mQsExpansionHeight = mQsMinExpansionHeight;
+        }
+    }
+
+    public void animateNextTopPaddingChange() {
+        mAnimateNextTopPaddingChange = true;
+        requestLayout();
+    }
+
+    /**
+     * @return Whether Quick Settings are currently expanded.
+     */
+    public boolean isQsExpanded() {
+        return mQsExpanded;
+    }
+
+    public void setQsExpansionEnabled(boolean qsExpansionEnabled) {
+        mQsExpansionEnabled = qsExpansionEnabled;
+    }
+
+    public void closeQs() {
+        cancelAnimation();
+        setQsExpansion(mQsMinExpansionHeight);
+    }
+
+    public void openQs() {
+        cancelAnimation();
+        if (mQsExpansionEnabled) {
+            setQsExpansion(mQsMaxExpansionHeight);
+        }
     }
 
     @Override
@@ -105,38 +192,317 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
-        // intercept for quick settings
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            final View target = mStatusBar.isOnKeyguard() ?  mKeyguardStatusView : mHeader;
-            final boolean inTarget = PhoneStatusBar.inBounds(target, event, true);
-            if (inTarget && !isInSettings()) {
-                mTrackingSettings = true;
-                return true;
-            }
-            if (!inTarget && isInSettings()) {
-                mTrackingSettings = true;
-                return true;
-            }
+        int pointerIndex = event.findPointerIndex(mTrackingPointer);
+        if (pointerIndex < 0) {
+            pointerIndex = 0;
+            mTrackingPointer = event.getPointerId(pointerIndex);
         }
-        return super.onInterceptTouchEvent(event);
+        final float x = event.getX(pointerIndex);
+        final float y = event.getY(pointerIndex);
+
+        switch (event.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+                mIntercepting = true;
+                mInitialTouchY = y;
+                mInitialTouchX = x;
+                initVelocityTracker();
+                trackMovement(event);
+                if (shouldIntercept(mInitialTouchX, mInitialTouchY, 0)) {
+                    getParent().requestDisallowInterceptTouchEvent(true);
+                }
+                break;
+            case MotionEvent.ACTION_POINTER_UP:
+                final int upPointer = event.getPointerId(event.getActionIndex());
+                if (mTrackingPointer == upPointer) {
+                    // gesture is ongoing, find a new pointer to track
+                    final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
+                    mTrackingPointer = event.getPointerId(newIndex);
+                    mInitialTouchX = event.getX(newIndex);
+                    mInitialTouchY = event.getY(newIndex);
+                }
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                final float h = y - mInitialTouchY;
+                trackMovement(event);
+                if (mTracking) {
+
+                    // Already tracking because onOverscrolled was called. We need to update here
+                    // so we don't stop for a frame until the next touch event gets handled in
+                    // onTouchEvent.
+                    setQsExpansion(h + mInitialHeightOnTouch);
+                    trackMovement(event);
+                    mIntercepting = false;
+                    return true;
+                }
+                if (Math.abs(h) > mTouchSlop && Math.abs(h) > Math.abs(x - mInitialTouchX)
+                        && shouldIntercept(mInitialTouchX, mInitialTouchY, h)) {
+                    onQsExpansionStarted();
+                    mInitialHeightOnTouch = mQsExpansionHeight;
+                    mInitialTouchY = y;
+                    mInitialTouchX = x;
+                    mTracking = true;
+                    mIntercepting = false;
+                    return true;
+                }
+                break;
+
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                trackMovement(event);
+                if (mTracking) {
+                    flingWithCurrentVelocity();
+                    mTracking = false;
+                }
+                mIntercepting = false;
+                break;
+        }
+        return !mQsExpanded && super.onInterceptTouchEvent(event);
+    }
+
+    @Override
+    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+
+        // Block request so we can still intercept the scrolling when QS is expanded.
+        if (!mQsExpanded) {
+            super.requestDisallowInterceptTouchEvent(disallowIntercept);
+        }
+    }
+
+    private void flingWithCurrentVelocity() {
+        float vel = getCurrentVelocity();
+
+        // TODO: Better logic whether we should expand or not.
+        flingSettings(vel, vel > 0);
     }
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         // TODO: Handle doublefinger swipe to notifications again. Look at history for a reference
         // implementation.
-        if (mTrackingSettings) {
-            mStatusBar.onSettingsEvent(event);
-            if (event.getAction() == MotionEvent.ACTION_UP
-                    || event.getAction() == MotionEvent.ACTION_CANCEL) {
-                mTrackingSettings = false;
+        if (mTracking) {
+            int pointerIndex = event.findPointerIndex(mTrackingPointer);
+            if (pointerIndex < 0) {
+                pointerIndex = 0;
+                mTrackingPointer = event.getPointerId(pointerIndex);
+            }
+            final float y = event.getY(pointerIndex);
+            final float x = event.getX(pointerIndex);
+
+            switch (event.getActionMasked()) {
+                case MotionEvent.ACTION_DOWN:
+                    mTracking = true;
+                    mInitialTouchY = y;
+                    mInitialTouchX = x;
+                    onQsExpansionStarted();
+                    mInitialHeightOnTouch = mQsExpansionHeight;
+                    initVelocityTracker();
+                    trackMovement(event);
+                    break;
+
+                case MotionEvent.ACTION_POINTER_UP:
+                    final int upPointer = event.getPointerId(event.getActionIndex());
+                    if (mTrackingPointer == upPointer) {
+                        // gesture is ongoing, find a new pointer to track
+                        final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
+                        final float newY = event.getY(newIndex);
+                        final float newX = event.getX(newIndex);
+                        mTrackingPointer = event.getPointerId(newIndex);
+                        mInitialHeightOnTouch = mQsExpansionHeight;
+                        mInitialTouchY = newY;
+                        mInitialTouchX = newX;
+                    }
+                    break;
+
+                case MotionEvent.ACTION_MOVE:
+                    final float h = y - mInitialTouchY;
+                    setQsExpansion(h + mInitialHeightOnTouch);
+                    trackMovement(event);
+                    break;
+
+                case MotionEvent.ACTION_UP:
+                case MotionEvent.ACTION_CANCEL:
+                    mTracking = false;
+                    mTrackingPointer = -1;
+                    trackMovement(event);
+                    flingWithCurrentVelocity();
+                    if (mVelocityTracker != null) {
+                        mVelocityTracker.recycle();
+                        mVelocityTracker = null;
+                    }
+                    break;
             }
             return true;
         }
-        if (isInSettings()) {
-            return true;
+
+        // Consume touch events when QS are expanded.
+        return mQsExpanded || super.onTouchEvent(event);
+    }
+
+    @Override
+    public void onOverscrolled(int amount) {
+        if (mIntercepting) {
+            onQsExpansionStarted(amount);
+            mInitialHeightOnTouch = mQsExpansionHeight;
+            mInitialTouchY = mLastTouchY;
+            mInitialTouchX = mLastTouchX;
+            mTracking = true;
         }
-        return super.onTouchEvent(event);
+    }
+
+    private void onQsExpansionStarted() {
+        onQsExpansionStarted(0);
+    }
+
+    private void onQsExpansionStarted(int overscrollAmount) {
+        cancelAnimation();
+
+        // Reset scroll position and apply that position to the expanded height.
+        float height = mQsExpansionHeight - mScrollView.getScrollY() - overscrollAmount;
+        mScrollView.scrollTo(0, 0);
+        setQsExpansion(height);
+    }
+
+    private void expandQs() {
+        mHeader.setExpanded(true);
+        mNotificationStackScroller.setEnabled(false);
+        mScrollView.setVisibility(View.VISIBLE);
+        mQsExpanded = true;
+    }
+
+    private void collapseQs() {
+        mHeader.setExpanded(false);
+        mNotificationStackScroller.setEnabled(true);
+        mScrollView.setVisibility(View.INVISIBLE);
+        mQsExpanded = false;
+    }
+
+    private void setQsExpansion(float height) {
+        height = Math.min(Math.max(height, mQsMinExpansionHeight), mQsMaxExpansionHeight);
+        if (height > mQsMinExpansionHeight && !mQsExpanded) {
+            expandQs();
+        } else if (height <= mQsMinExpansionHeight && mQsExpanded) {
+            collapseQs();
+        }
+        mQsExpansionHeight = height;
+        mHeader.setExpansion(height);
+        setQsTranslation(height);
+        setQsStackScrollerPadding(height);
+    }
+
+    private void setQsTranslation(float height) {
+        mQsContainer.setY(height - mQsContainer.getHeight());
+    }
+
+    private void setQsStackScrollerPadding(float height) {
+        float start = height - mScrollView.getScrollY() + mNotificationTopPadding;
+        float stackHeight = mNotificationStackScroller.getHeight() - start;
+        if (stackHeight <= mMinStackHeight) {
+            float overflow = mMinStackHeight - stackHeight;
+            stackHeight = mMinStackHeight;
+            start = mNotificationStackScroller.getHeight() - stackHeight;
+            mNotificationStackScroller.setTranslationY(overflow);
+            mNotificationTranslation = overflow + mScrollView.getScrollY();
+        } else {
+            mNotificationStackScroller.setTranslationY(0);
+            mNotificationTranslation = mScrollView.getScrollY();
+        }
+        mNotificationStackScroller.setTopPadding(clampQsStackScrollerPadding((int) start), false);
+    }
+
+    private int clampQsStackScrollerPadding(int desiredPadding) {
+        return Math.max(desiredPadding, mStackScrollerIntrinsicPadding);
+    }
+
+    private void trackMovement(MotionEvent event) {
+        if (mVelocityTracker != null) mVelocityTracker.addMovement(event);
+        mLastTouchX = event.getX();
+        mLastTouchY = event.getY();
+    }
+
+    private void initVelocityTracker() {
+        if (mVelocityTracker != null) {
+            mVelocityTracker.recycle();
+        }
+        mVelocityTracker = VelocityTracker.obtain();
+    }
+
+    private float getCurrentVelocity() {
+        if (mVelocityTracker == null) {
+            return 0;
+        }
+        mVelocityTracker.computeCurrentVelocity(1000);
+        return mVelocityTracker.getYVelocity();
+    }
+
+    private void cancelAnimation() {
+        if (mQsExpansionAnimator != null) {
+            mQsExpansionAnimator.cancel();
+        }
+    }
+    private void flingSettings(float vel, boolean expand) {
+        float target = expand ? mQsMaxExpansionHeight : mQsMinExpansionHeight;
+        ValueAnimator animator = ValueAnimator.ofFloat(mQsExpansionHeight, target);
+        mFlingAnimationUtils.apply(animator, mQsExpansionHeight, target, vel);
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                setQsExpansion((Float) animation.getAnimatedValue());
+            }
+        });
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mQsExpansionAnimator = null;
+            }
+        });
+        animator.start();
+        mQsExpansionAnimator = animator;
+    }
+
+    /**
+     * @return Whether we should intercept a gesture to open Quick Settings.
+     */
+    private boolean shouldIntercept(float x, float y, float yDiff) {
+        if (!mQsExpansionEnabled) {
+            return false;
+        }
+        boolean onHeader = x >= mHeader.getLeft() && x <= mHeader.getRight()
+                && y >= mHeader.getTop() && y <= mHeader.getBottom();
+        if (mQsExpanded) {
+            return onHeader || (mScrollView.isScrolledToBottom() && yDiff < 0);
+        } else {
+            return onHeader;
+        }
+    }
+
+    @Override
+    public void setVisibility(int visibility) {
+        int oldVisibility = getVisibility();
+        super.setVisibility(visibility);
+        if (visibility != oldVisibility) {
+            reparentStatusIcons(visibility == VISIBLE);
+        }
+    }
+
+    /**
+     * When the notification panel gets expanded, we need to move the status icons in the header
+     * card.
+     */
+    private void reparentStatusIcons(boolean toHeader) {
+        if (mStatusBar == null) {
+            return;
+        }
+        LinearLayout systemIcons = mStatusBar.getSystemIcons();
+        if (systemIcons.getParent() != null) {
+            ((ViewGroup) systemIcons.getParent()).removeView(systemIcons);
+        }
+        if (toHeader) {
+            mHeader.attachSystemIcons(systemIcons);
+        } else {
+            mHeader.onSystemIconsDetached();
+            mStatusBar.reattachSystemIcons();
+        }
     }
 
     @Override
@@ -151,14 +517,16 @@
     protected int getMaxPanelHeight() {
         if (!isInSettings()) {
             int maxPanelHeight = super.getMaxPanelHeight();
-            int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin();
+            int notificationMarginBottom = mStackScrollerContainer.getPaddingBottom();
+            int emptyBottomMargin = notificationMarginBottom
+                    + mNotificationStackScroller.getEmptyBottomMargin();
             return maxPanelHeight - emptyBottomMargin;
         }
         return super.getMaxPanelHeight();
     }
 
     private boolean isInSettings() {
-        return mStatusBar != null && mStatusBar.isFlippedToSettings();
+        return mQsExpanded;
     }
 
     @Override
@@ -187,4 +555,24 @@
     public void onHeightChanged(ExpandableView view) {
         requestPanelHeightUpdate();
     }
+
+    @Override
+    public void onScrollChanged() {
+        if (mQsExpanded) {
+            mNotificationStackScroller.setTranslationY(
+                    mNotificationTranslation - mScrollView.getScrollY());
+        }
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v == mHeader.getBackgroundView()) {
+            onQsExpansionStarted();
+            if (mQsExpanded) {
+                flingSettings(0 /* vel */, false /* expand */);
+            } else if (mQsExpansionEnabled) {
+                flingSettings(0 /* vel */, true /* expand */);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
new file mode 100644
index 0000000..f41e78d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+/**
+ * The container with notification stack scroller and quick settings inside.
+ */
+public class NotificationsQuickSettingsContainer extends FrameLayout {
+
+    public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected boolean fitSystemWindows(Rect insets) {
+        setPadding(0, 0, 0, insets.bottom);
+        insets.bottom = 0;
+        return true;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java
new file mode 100644
index 0000000..ba0b66e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ScrollView;
+
+/**
+ * A scroll view which can be observed for scroll change events.
+ */
+public class ObservableScrollView extends ScrollView {
+
+    private Listener mListener;
+    private int mLastOverscrollAmount;
+
+    public ObservableScrollView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public void setListener(Listener listener) {
+        mListener = listener;
+    }
+
+    public boolean isScrolledToBottom() {
+        return getScrollY() == getMaxScrollY();
+    }
+
+    private int getMaxScrollY() {
+        int scrollRange = 0;
+        if (getChildCount() > 0) {
+            View child = getChildAt(0);
+            scrollRange = Math.max(0,
+                    child.getHeight() - (getHeight() - mPaddingBottom - mPaddingTop));
+        }
+        return scrollRange;
+    }
+
+    @Override
+    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+        super.onScrollChanged(l, t, oldl, oldt);
+        if (mListener != null) {
+            mListener.onScrollChanged();
+        }
+    }
+
+    @Override
+    protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY,
+            int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY,
+            boolean isTouchEvent) {
+        mLastOverscrollAmount = Math.max(0, scrollY + deltaY - getMaxScrollY());
+        return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY,
+                        maxOverScrollX, maxOverScrollY, isTouchEvent);
+    }
+
+    @Override
+    protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
+        super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
+        if (mListener != null && mLastOverscrollAmount > 0) {
+            mListener.onOverscrolled(mLastOverscrollAmount);
+        }
+    }
+
+    public interface Listener {
+        void onScrollChanged();
+        void onOverscrolled(int amount);
+    }
+}
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 328a172..8c70517 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -75,7 +75,7 @@
     private boolean mClosing;
     private boolean mTracking;
     private int mTrackingPointer;
-    private int mTouchSlop;
+    protected int mTouchSlop;
 
     private TimeAnimator mTimeAnimator;
     private ObjectAnimator mPeekAnimator;
@@ -220,9 +220,9 @@
     private float mVel, mAccel;
     protected int mMaxPanelHeight = 0;
     private String mViewName;
-    protected float mInitialTouchY;
-    protected float mInitialTouchX;
-    protected float mFinalTouchY;
+    private float mInitialTouchY;
+    private float mInitialTouchX;
+    private float mFinalTouchY;
 
     protected void onExpandingFinished() {
     }
@@ -526,11 +526,14 @@
 
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
+                if (mTimeAnimator.isRunning()) {
+                    mTimeAnimator.cancel(); // end any outstanding animations
+                    return true;
+                }
                 mInitialTouchY = y;
                 mInitialTouchX = x;
                 initVelocityTracker();
                 trackMovement(event);
-                mTimeAnimator.cancel(); // end any outstanding animations
                 break;
             case MotionEvent.ACTION_POINTER_UP:
                 final int upPointer = event.getPointerId(event.getActionIndex());
@@ -569,7 +572,7 @@
     }
 
     protected boolean isScrolledToBottom() {
-        return false;
+        return true;
     }
 
     protected float getContentHeight() {
@@ -623,9 +626,7 @@
                 mExpandedHeight = mMaxPanelHeight;
             }
         }
-        heightMeasureSpec = MeasureSpec.makeMeasureSpec(
-                getDesiredMeasureHeight(), MeasureSpec.AT_MOST);
-        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
+        setMeasuredDimension(getMeasuredWidth(), getDesiredMeasureHeight());
     }
 
     protected int getDesiredMeasureHeight() {
@@ -705,11 +706,6 @@
      * @return the default implementation simply returns the maximum height.
      */
     protected int getMaxPanelHeight() {
-        if (mMaxPanelHeight <= 0) {
-            if (DEBUG) logf("Forcing measure() since mMaxPanelHeight=" + mMaxPanelHeight);
-            measure(MeasureSpec.makeMeasureSpec(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY),
-                    MeasureSpec.makeMeasureSpec(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY));
-        }
         return mMaxPanelHeight;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 545352c..23b0594 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -18,6 +18,7 @@
 
 
 import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
+import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
 import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
 import static android.app.StatusBarManager.windowStateToString;
@@ -28,7 +29,6 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
@@ -68,11 +68,11 @@
 import android.util.Log;
 import android.view.Display;
 import android.view.Gravity;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewPropertyAnimator;
@@ -93,8 +93,12 @@
 import com.android.systemui.EventLogTags;
 import com.android.systemui.R;
 import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.qs.QSPanel;
+import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.DragDownHelper;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.GestureRecorder;
 import com.android.systemui.statusbar.InterceptedNotifications;
 import com.android.systemui.statusbar.NotificationData;
@@ -102,13 +106,17 @@
 import com.android.systemui.statusbar.NotificationOverflowContainer;
 import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
+import com.android.systemui.statusbar.policy.CastControllerImpl;
 import com.android.systemui.statusbar.policy.DateView;
 import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.LocationControllerImpl;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl;
+import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
+import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
 import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
@@ -119,7 +127,8 @@
 import java.util.Collection;
 import java.util.Collections;
 
-public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
+public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
+        DragDownHelper.OnDragDownListener, ActivityStarter {
     static final String TAG = "PhoneStatusBar";
     public static final boolean DEBUG = BaseStatusBar.DEBUG;
     public static final boolean SPEW = false;
@@ -176,19 +185,20 @@
     PhoneStatusBarPolicy mIconPolicy;
 
     // These are no longer handled by the policy, because we need custom strategies for them
-    BluetoothController mBluetoothController;
+    BluetoothControllerImpl mBluetoothController;
     BatteryController mBatteryController;
-    LocationController mLocationController;
-    NetworkController mNetworkController;
-    RotationLockController mRotationLockController;
+    LocationControllerImpl mLocationController;
+    NetworkControllerImpl mNetworkController;
+    RotationLockControllerImpl mRotationLockController;
+    UserInfoController mUserInfoController;
+    ZenModeControllerImpl mZenModeController;
+    CastControllerImpl mCastController;
 
     int mNaturalBarHeight = -1;
     int mIconSize = -1;
     int mIconHPadding = -1;
     Display mDisplay;
     Point mCurrentDisplaySize = new Point();
-    private float mHeadsUpVerticalOffset;
-    private int[] mStackScrollerPosition = new int[2];
 
     StatusBarWindowView mStatusBarWindow;
     PhoneStatusBarView mStatusBarView;
@@ -203,6 +213,7 @@
 
     // right-hand icons
     LinearLayout mSystemIconArea;
+    LinearLayout mSystemIcons;
 
     // left-hand icons
     LinearLayout mStatusIcons;
@@ -217,37 +228,32 @@
     NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
     View mExpandedContents;
     int mNotificationPanelGravity;
-    int mNotificationPanelMarginBottomPx, mNotificationPanelMarginPx;
+    int mNotificationPanelMarginBottomPx;
     float mNotificationPanelMinHeightFrac;
-    boolean mNotificationPanelIsFullScreenWidth;
     TextView mNotificationPanelDebugText;
 
     // settings
-    QuickSettings mQS;
-    boolean mHasQuickSettings;
     View mFlipSettingsView;
-    QuickSettingsContainerView mSettingsContainer;
+    private QSPanel mQSPanel;
 
     // top bar
-    View mNotificationPanelHeader;
+    StatusBarHeaderView mHeader;
     View mKeyguardStatusView;
-    View mKeyguardBottomArea;
+    KeyguardBottomAreaView mKeyguardBottomArea;
+    boolean mLeaveOpenOnKeyguardHide;
     KeyguardIndicationTextView mKeyguardIndicationTextView;
 
     // TODO: Fetch phrase from search/hotword provider.
     String mKeyguardHotwordPhrase = "";
     int mKeyguardMaxNotificationCount;
     View mDateTimeView;
-    View mClearButton;
-    FlipperButton mHeaderFlipper, mKeyguardFlipper;
 
     // carrier/wifi label
     private TextView mCarrierLabel;
     private boolean mCarrierLabelVisible = false;
     private int mCarrierLabelHeight;
     private TextView mEmergencyCallLabel;
-    private int mNotificationHeaderHeight;
-    private View mKeyguardCarrierLabel;
+    private int mStatusBarHeaderHeight;
 
     private boolean mShowCarrierInPanel = false;
 
@@ -320,11 +326,12 @@
             if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " +
                     "selfChange=%s userSetup=%s mUserSetup=%s",
                     selfChange, userSetup, mUserSetup));
-            mHeaderFlipper.userSetup(userSetup);
-            mKeyguardFlipper.userSetup(userSetup);
 
             if (userSetup != mUserSetup) {
                 mUserSetup = userSetup;
+                if (mNotificationPanel != null) {
+                    mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned() && userSetup);
+                }
                 if (!mUserSetup && mStatusBarView != null)
                     animateCollapseQuickSettings();
             }
@@ -379,7 +386,7 @@
     private boolean mSettingsStarted;
     private boolean mSettingsCancelled;
     private boolean mSettingsClosing;
-    private int mNotificationPadding;
+    private boolean mVisible;
 
     private final OnChildLocationsChangedListener mOnChildLocationsChangedListener =
             new OnChildLocationsChangedListener() {
@@ -469,6 +476,13 @@
         }
     };
 
+    private final View.OnClickListener mOverflowClickListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            goToLockedShade(null);
+        }
+    };
+
     @Override
     public void setZenMode(int mode) {
         super.setZenMode(mode);
@@ -544,8 +558,6 @@
         mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
                 R.id.notification_panel);
         mNotificationPanel.setStatusBar(this);
-        mNotificationPanelIsFullScreenWidth =
-            (mNotificationPanel.getLayoutParams().width == ViewGroup.LayoutParams.MATCH_PARENT);
 
         // make the header non-responsive to clicks
         mNotificationPanel.findViewById(R.id.header).setOnTouchListener(
@@ -599,6 +611,7 @@
         mPixelFormat = PixelFormat.OPAQUE;
 
         mSystemIconArea = (LinearLayout) mStatusBarView.findViewById(R.id.system_icon_area);
+        mSystemIcons = (LinearLayout) mStatusBarView.findViewById(R.id.system_icons);
         mStatusIcons = (LinearLayout)mStatusBarView.findViewById(R.id.statusIcons);
         mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons);
         mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon);
@@ -617,39 +630,30 @@
                 (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate(
                         R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false);
         mKeyguardIconOverflowContainer.setOnActivatedListener(this);
-        mKeyguardCarrierLabel = mStatusBarWindow.findViewById(R.id.keyguard_carrier_text);
+        mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
         mStackScroller.addView(mKeyguardIconOverflowContainer);
 
         mExpandedContents = mStackScroller;
 
-        mNotificationPanelHeader = mStatusBarWindow.findViewById(R.id.header);
+        mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header);
+        mHeader.setActivityStarter(this);
         mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
-        mKeyguardBottomArea = mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
+        mKeyguardBottomArea =
+                (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
+        mKeyguardBottomArea.setActivityStarter(this);
         mKeyguardIndicationTextView = (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
                 R.id.keyguard_indication_text);
-        mClearButton = mStatusBarWindow.findViewById(R.id.clear_all_button);
-        mClearButton.setOnClickListener(mClearButtonListener);
-        mClearButton.setAlpha(0f);
-        mClearButton.setVisibility(View.INVISIBLE);
-        mClearButton.setEnabled(false);
         mDateView = (DateView)mStatusBarWindow.findViewById(R.id.date);
 
-        mHasQuickSettings = res.getBoolean(R.bool.config_hasQuickSettings);
-
-        mDateTimeView = mNotificationPanelHeader.findViewById(R.id.datetime);
+        mDateTimeView = mHeader.findViewById(R.id.datetime);
         if (mDateTimeView != null) {
             mDateTimeView.setOnClickListener(mClockClickListener);
             mDateTimeView.setEnabled(true);
         }
 
-        mHeaderFlipper = new FlipperButton(mStatusBarWindow.findViewById(R.id.header_flipper));
-        mKeyguardFlipper =new FlipperButton(mStatusBarWindow.findViewById(R.id.keyguard_flipper));
-
-        if (!mNotificationPanelIsFullScreenWidth) {
-            mNotificationPanel.setSystemUiVisibility(
-                    View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS |
-                    View.STATUS_BAR_DISABLE_CLOCK);
-        }
+        mNotificationPanel.setSystemUiVisibility(
+                View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS |
+                View.STATUS_BAR_DISABLE_CLOCK);
 
         mTicker = new MyTicker(context, mStatusBarView);
 
@@ -662,14 +666,16 @@
         setAreThereNotifications();
 
         // Other icons
-        mLocationController = new LocationController(mContext); // will post a notification
+        mLocationController = new LocationControllerImpl(mContext); // will post a notification
         mBatteryController = new BatteryController(mContext);
-        mNetworkController = new NetworkController(mContext);
-        mBluetoothController = new BluetoothController(mContext);
-        if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)
-                || QuickSettings.DEBUG_GONE_TILES) {
-            mRotationLockController = new RotationLockController(mContext);
+        mNetworkController = new NetworkControllerImpl(mContext);
+        mBluetoothController = new BluetoothControllerImpl(mContext);
+        if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)) {
+            mRotationLockController = new RotationLockControllerImpl(mContext);
         }
+        mUserInfoController = new UserInfoController(mContext);
+        mZenModeController = new ZenModeControllerImpl(mContext, mHandler);
+        mCastController = new CastControllerImpl(mContext);
         final SignalClusterView signalCluster =
                 (SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster);
 
@@ -718,30 +724,23 @@
 //                    updateCarrierLabelVisibility(false);
         }
 
-        // Quick Settings (where available, some restrictions apply)
-        mNotificationPadding = mContext.getResources()
-                .getDimensionPixelSize(R.dimen.notification_side_padding);
-        if (mHasQuickSettings) {
-            // Quick Settings needs a container to survive
-            mSettingsContainer = (QuickSettingsContainerView)
-                    mStatusBarWindow.findViewById(R.id.quick_settings_container);
-            mFlipSettingsView = mSettingsContainer;
-            if (mSettingsContainer != null) {
-                mQS = new QuickSettings(mContext, mSettingsContainer);
-                if (!mNotificationPanelIsFullScreenWidth) {
-                    mSettingsContainer.setSystemUiVisibility(
-                            View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS
-                            | View.STATUS_BAR_DISABLE_SYSTEM_INFO);
-                }
-                mQS.setService(this);
-                mQS.setBar(mStatusBarView);
-                mQS.setup(mNetworkController, mBluetoothController, mBatteryController,
-                        mLocationController, mRotationLockController);
-            } else {
-                mQS = null; // fly away, be free
+        // Set up the quick settings tile panel
+        mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel);
+        if (mQSPanel != null) {
+            final QSTileHost qsh = new QSTileHost(mContext, this,
+                    mBluetoothController, mLocationController, mRotationLockController,
+                    mNetworkController, mZenModeController, null /*tethering*/,
+                    mCastController);
+            for (QSTile<?> tile : qsh.getTiles()) {
+                mQSPanel.addTile(tile);
             }
+            mHeader.setQSPanel(mQSPanel);
         }
 
+        // User info. Trigger first load.
+        mHeader.setUserInfoController(mUserInfoController);
+        mUserInfoController.reloadUserInfo();
+
         PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mBroadcastReceiver.onReceive(mContext,
                 new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF));
@@ -760,99 +759,6 @@
         return mStatusBarView;
     }
 
-    public boolean onSettingsEvent(MotionEvent event) {
-        userActivity();
-        if (mSettingsClosing
-                && mFlipSettingsViewAnim != null && mFlipSettingsViewAnim.isRunning()) {
-            return true;
-        }
-        if (mSettingsTracker != null) {
-            mSettingsTracker.addMovement(event);
-        }
-        final int slop = ViewConfiguration.get(mContext).getScaledTouchSlop();
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            mSettingsTracker = VelocityTracker.obtain();
-            mSettingsDownY = event.getY();
-            mSettingsCancelled = false;
-            mSettingsStarted = false;
-            mSettingsClosing = mFlipSettingsView.getVisibility() == View.VISIBLE;
-            if (mSettingsClosing) {
-                mStackScroller.setVisibility(View.VISIBLE);
-            } else {
-                mFlipSettingsView.setTranslationY(-mNotificationPanel.getMeasuredHeight());
-            }
-            dispatchSettingsEvent(event);
-        } else if (mSettingsTracker != null && (event.getAction() == MotionEvent.ACTION_UP
-                || event.getAction() == MotionEvent.ACTION_CANCEL)) {
-            final float dy = event.getY() - mSettingsDownY;
-            final FlipperButton flipper = mOnKeyguard ? mKeyguardFlipper : mHeaderFlipper;
-            final boolean inButton = flipper.inHolderBounds(event);
-            final boolean qsTap = mSettingsClosing && Math.abs(dy) < slop;
-            if (!qsTap && !inButton) {
-                mSettingsTracker.computeCurrentVelocity(1000);
-                final float vy = mSettingsTracker.getYVelocity();
-                final boolean animate = true;
-                if (dy <= slop || vy <= 0) {
-                    flipToNotifications(animate);
-                } else {
-                    flipToSettings(animate);
-                }
-            }
-            mSettingsTracker.recycle();
-            mSettingsTracker = null;
-            dispatchSettingsEvent(event);
-        } else if (mSettingsTracker != null && event.getAction() == MotionEvent.ACTION_MOVE) {
-            final float dy = event.getY() - mSettingsDownY;
-            if (mSettingsClosing) {
-                positionSettings(dy);
-                final boolean qsTap = Math.abs(dy) < slop;
-                if (!mSettingsCancelled && !qsTap) {
-                    MotionEvent cancelEvent = MotionEvent.obtainNoHistory(event);
-                    cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
-                    dispatchSettingsEvent(cancelEvent);
-                    mSettingsCancelled = true;
-                }
-            } else {
-                if (!mSettingsStarted && dy > slop) {
-                    mSettingsStarted = true;
-                    mFlipSettingsView.setVisibility(View.VISIBLE);
-                    mStackScroller.setVisibility(View.VISIBLE);
-                }
-                if (mSettingsStarted) {
-                    positionSettings(dy);
-                }
-                dispatchSettingsEvent(event);
-            }
-        }
-        return true;
-    }
-
-    private void dispatchSettingsEvent(MotionEvent event) {
-        final View target = mSettingsClosing ? mFlipSettingsView : mNotificationPanelHeader;
-        final int[] targetLoc = new int[2];
-        target.getLocationInWindow(targetLoc);
-        final int[] panelLoc = new int[2];
-        mNotificationPanel.getLocationInWindow(panelLoc);
-        final int dx = targetLoc[0] - panelLoc[0];
-        final int dy = targetLoc[1] - panelLoc[1];
-        event.offsetLocation(-dx, -dy);
-        target.dispatchTouchEvent(event);
-    }
-
-    private void positionSettings(float dy) {
-        if (mSettingsClosing) {
-            final int ph = mNotificationPanel.getMeasuredHeight();
-            dy = Math.min(Math.max(-ph, dy), 0);
-            mFlipSettingsView.setTranslationY(dy);
-            mStackScroller.setTranslationY(ph + dy);
-        } else {
-            final int h = mFlipSettingsView.getBottom();
-            dy = Math.min(Math.max(0, dy), h);
-            mFlipSettingsView.setTranslationY(-h + dy);
-            mStackScroller.setTranslationY(dy);
-        }
-    }
-
     private void startKeyguard() {
         KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
         mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
@@ -1193,7 +1099,7 @@
             }
 
             if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0
-                    && !mNotificationPanel.isTracking() && !mOnKeyguard) {
+                    && !mNotificationPanel.isTracking() && mState != StatusBarState.KEYGUARD) {
                 animateCollapsePanels();
             }
         }
@@ -1206,16 +1112,6 @@
         if (mNavigationBarView != null) {
             mNavigationBarView.setLayoutDirection(layoutDirection);
         }
-
-        if (mClearButton != null && mClearButton instanceof ImageView) {
-            // Force asset reloading
-            ((ImageView)mClearButton).setImageDrawable(null);
-            ((ImageView)mClearButton).setImageResource(R.drawable.ic_notify_clear);
-        }
-
-        mHeaderFlipper.refreshLayout();
-        mKeyguardFlipper.refreshLayout();
-
         refreshAllStatusBarIcons();
     }
 
@@ -1269,8 +1165,7 @@
             }
         }
 
-        mHeaderFlipper.provisionCheck(provisioned);
-        mKeyguardFlipper.provisionCheck(provisioned);
+        mNotificationPanel.setQsExpansionEnabled(provisioned && mUserSetup);
     }
 
     @Override
@@ -1345,9 +1240,9 @@
         final boolean makeVisible =
             !(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly())
             && mStackScroller.getHeight() < (mNotificationPanel.getHeight()
-                    - mCarrierLabelHeight - mNotificationHeaderHeight)
+                    - mCarrierLabelHeight - mStatusBarHeaderHeight)
             && mStackScroller.getVisibility() == View.VISIBLE
-            && !mOnKeyguard;
+            && mState != StatusBarState.KEYGUARD;
 
         if (force || mCarrierLabelVisible != makeVisible) {
             mCarrierLabelVisible = makeVisible;
@@ -1387,38 +1282,6 @@
                     + " any=" + any + " clearable=" + clearable);
         }
 
-        if (mFlipSettingsView != null
-                && mFlipSettingsView.getVisibility() == View.VISIBLE
-                && mStackScroller.getVisibility() != View.VISIBLE) {
-            // the flip settings panel is unequivocally showing; we should not be shown
-            mClearButton.setVisibility(View.INVISIBLE);
-        } else if (mClearButton.isShown()) {
-            if (clearable != (mClearButton.getAlpha() == 1.0f)) {
-                ObjectAnimator clearAnimation = ObjectAnimator.ofFloat(
-                        mClearButton, "alpha", clearable ? 1.0f : 0.0f).setDuration(250);
-                clearAnimation.addListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        if (mClearButton.getAlpha() <= 0.0f) {
-                            mClearButton.setVisibility(View.INVISIBLE);
-                        }
-                    }
-
-                    @Override
-                    public void onAnimationStart(Animator animation) {
-                        if (mClearButton.getAlpha() <= 0.0f) {
-                            mClearButton.setVisibility(View.VISIBLE);
-                        }
-                    }
-                });
-                clearAnimation.start();
-            }
-        } else {
-            mClearButton.setAlpha(clearable ? 1.0f : 0.0f);
-            mClearButton.setVisibility(clearable ? View.VISIBLE : View.INVISIBLE);
-        }
-        mClearButton.setEnabled(clearable);
-
         final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out);
         final boolean showDot = (any&&!areLightsOn());
         if (showDot != (nlo.getAlpha() == 1.0f)) {
@@ -1563,6 +1426,11 @@
         return new PhoneStatusBar.H();
     }
 
+    @Override
+    public void startActivity(Intent intent) {
+        startActivityDismissingKeyguard(intent, false);
+    }
+
     /**
      * All changes to the status bar and notifications funnel through here and are batched.
      */
@@ -1609,7 +1477,7 @@
         }
     }
 
-    public Handler getHandler() {
+    private Handler getHandler() {
         return mHandler;
     }
 
@@ -1652,7 +1520,21 @@
         animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
     }
 
+    private final Runnable mAnimateCollapsePanels = new Runnable() {
+        @Override
+        public void run() {
+            animateCollapsePanels();
+        }
+    };
+
+    public void postAnimateCollapsePanels() {
+        mHandler.post(mAnimateCollapsePanels);
+    }
+
     public void animateCollapsePanels(int flags) {
+        if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
+            return;
+        }
         if (SPEW) {
             Log.d(TAG, "animateCollapse():"
                     + " mExpandedVisible=" + mExpandedVisible
@@ -1726,7 +1608,7 @@
     final int FLIP_DURATION_IN = 225;
     final int FLIP_DURATION = (FLIP_DURATION_IN + FLIP_DURATION_OUT);
 
-    Animator mScrollViewAnim, mFlipSettingsViewAnim, mClearButtonAnim;
+    Animator mScrollViewAnim, mClearButtonAnim;
 
     @Override
     public void animateExpandNotificationsPanel() {
@@ -1750,47 +1632,8 @@
     }
 
     public void flipToNotifications(boolean animate) {
-        cancelAnim(mFlipSettingsViewAnim);
-        cancelAnim(mScrollViewAnim);
-        cancelAnim(mClearButtonAnim);
-        mHeaderFlipper.cancel();
-        mKeyguardFlipper.cancel();
-        mStackScroller.setVisibility(View.VISIBLE);
-        final int h = mNotificationPanel.getMeasuredHeight();
-        if (animate) {
-            final float settingsY =
-                    mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : 0;
-            final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : h;
-            mScrollViewAnim = start(
-                    interpolator(mDecelerateInterpolator,
-                        ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, 0)
-                            .setDuration(FLIP_DURATION)
-                        ));
-            mFlipSettingsViewAnim = start(
-                setVisibilityWhenDone(
-                    interpolator(mDecelerateInterpolator,
-                            ObjectAnimator.ofFloat(
-                                    mFlipSettingsView, View.TRANSLATION_Y, settingsY, -h))
-                        .setDuration(FLIP_DURATION),
-                    mFlipSettingsView, View.INVISIBLE));
-        } else {
-            mStackScroller.setTranslationY(0);
-            mFlipSettingsView.setTranslationY(-h);
-            mFlipSettingsView.setVisibility(View.INVISIBLE);
-        }
-        mHeaderFlipper.flipToNotifications(animate);
-        mKeyguardFlipper.flipToNotifications(animate);
-        mClearButton.setVisibility(View.VISIBLE);
-        mClearButton.setAlpha(0f);
-        setAreThereNotifications(); // this will show/hide the button as necessary
-        mNotificationPanel.postDelayed(new Runnable() {
-            public void run() {
-                updateCarrierLabelVisibility(false);
-            }
-        }, animate ? FLIP_DURATION - 150 : 0);
-        if (mOnFlipRunnable != null) {
-            mOnFlipRunnable.run();
-        }
+        // TODO: Animation
+        mNotificationPanel.closeQs();
     }
 
     @Override
@@ -1804,78 +1647,18 @@
         if (!mUserSetup) return;
 
         mNotificationPanel.expand();
-        if (mFlipSettingsView.getVisibility() != View.VISIBLE
-                || mFlipSettingsView.getTranslationY() < 0) {
-            flipToSettings(true /*animate*/);
-        }
+        mNotificationPanel.openQs();
 
         if (false) postStartTracing();
     }
 
     public boolean isFlippedToSettings() {
-        if (mFlipSettingsView != null) {
-            return mFlipSettingsView.getVisibility() == View.VISIBLE;
+        if (mNotificationPanel != null) {
+            return mNotificationPanel.isQsExpanded();
         }
         return false;
     }
 
-    public void flipToSettings(boolean animate) {
-        // Settings are not available in setup
-        if (!mUserSetup) return;
-
-        cancelAnim(mFlipSettingsViewAnim);
-        cancelAnim(mScrollViewAnim);
-        mHeaderFlipper.cancel();
-        mKeyguardFlipper.cancel();
-        cancelAnim(mClearButtonAnim);
-
-        mFlipSettingsView.setVisibility(View.VISIBLE);
-        final int h = mNotificationPanel.getMeasuredHeight();
-        if (animate) {
-            final float settingsY
-                    = mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : -h;
-            final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : 0;
-            mFlipSettingsViewAnim = start(
-                    startDelay(0,
-                        interpolator(mDecelerateInterpolator,
-                            ObjectAnimator.ofFloat(mFlipSettingsView, View.TRANSLATION_Y,
-                                    settingsY, 0f)
-                                .setDuration(FLIP_DURATION)
-                            )));
-            mScrollViewAnim = start(
-                setVisibilityWhenDone(
-                    interpolator(mDecelerateInterpolator,
-                            ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, h)
-                            )
-                        .setDuration(FLIP_DURATION),
-                        mStackScroller, View.INVISIBLE));
-        } else {
-            mFlipSettingsView.setTranslationY(0);
-            mStackScroller.setTranslationY(h);
-            mStackScroller.setVisibility(View.INVISIBLE);
-        }
-        mHeaderFlipper.flipToSettings(animate);
-        mKeyguardFlipper.flipToSettings(animate);
-        if (animate) {
-            mClearButtonAnim = start(
-                setVisibilityWhenDone(
-                    ObjectAnimator.ofFloat(mClearButton, View.ALPHA, 0f)
-                    .setDuration(FLIP_DURATION),
-                    mClearButton, View.INVISIBLE));
-        } else {
-            mClearButton.setAlpha(0);
-            mClearButton.setVisibility(View.INVISIBLE);
-        }
-        mNotificationPanel.postDelayed(new Runnable() {
-            public void run() {
-                updateCarrierLabelVisibility(false);
-            }
-        }, animate ? FLIP_DURATION - 150 : 0);
-        if (mOnFlipRunnable != null) {
-            mOnFlipRunnable.run();
-        }
-    }
-
     public void animateCollapseQuickSettings() {
         mStatusBarView.collapseAllPanels(true);
     }
@@ -1896,18 +1679,15 @@
         mStatusBarView.collapseAllPanels(/*animate=*/ false);
 
         // reset things to their proper state
-        if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
         if (mScrollViewAnim != null) mScrollViewAnim.cancel();
         if (mClearButtonAnim != null) mClearButtonAnim.cancel();
 
         mStackScroller.setVisibility(View.VISIBLE);
         mNotificationPanel.setVisibility(View.GONE);
-        mFlipSettingsView.setVisibility(View.GONE);
 
         setAreThereNotifications(); // show the clear button
 
-        mHeaderFlipper.reset();
-        mKeyguardFlipper.reset();
+        mNotificationPanel.closeQs();
 
         mExpandedVisible = false;
         if (mNavigationBarView != null)
@@ -2096,13 +1876,7 @@
 
     private void checkBarModes() {
         if (mDemoMode) return;
-        int sbMode = mStatusBarMode;
-        if (panelsEnabled() && (mInteractingWindows & StatusBarManager.WINDOW_STATUS_BAR) != 0
-                && !mOnKeyguard) {
-            // if panels are expandable, force the status bar opaque on any interaction
-            sbMode = MODE_OPAQUE;
-        }
-        checkBarMode(sbMode, mStatusBarWindowState, mStatusBarView.getBarTransitions());
+        checkBarMode(mStatusBarMode, mStatusBarWindowState, mStatusBarView.getBarTransitions());
         if (mNavigationBarView != null) {
             checkBarMode(mNavigationBarMode,
                     mNavigationBarWindowState, mNavigationBarView.getBarTransitions());
@@ -2210,14 +1984,22 @@
     }
 
     @Override
-    public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
-        boolean altBack = (backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS)
-            || ((vis & InputMethodService.IME_VISIBLE) != 0);
+    public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+            boolean showImeSwitcher) {
+        boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
+        int flags = mNavigationIconHints;
+        if ((backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) || imeShown) {
+            flags |= NAVIGATION_HINT_BACK_ALT;
+        } else {
+            flags &= ~NAVIGATION_HINT_BACK_ALT;
+        }
+        if (showImeSwitcher) {
+            flags |= NAVIGATION_HINT_IME_SHOWN;
+        } else {
+            flags &= ~NAVIGATION_HINT_IME_SHOWN;
+        }
 
-        setNavigationIconHints(
-                altBack ? (mNavigationIconHints | NAVIGATION_HINT_BACK_ALT)
-                        : (mNavigationIconHints & ~NAVIGATION_HINT_BACK_ALT));
-        if (mQS != null) mQS.setImeWindowStatus(vis > 0);
+        setNavigationIconHints(flags);
     }
 
     @Override
@@ -2429,20 +2211,11 @@
         }
     }
 
-    void updateExpandedInvisiblePosition() {
-        mTrackingPosition = -mDisplayMetrics.heightPixels;
-    }
-
     static final float saturate(float a) {
         return a < 0f ? 0f : (a > 1f ? 1f : a);
     }
 
     @Override
-    protected int getExpandedViewMaxHeight() {
-        return mDisplayMetrics.heightPixels - mNotificationPanelMarginBottomPx;
-    }
-
-    @Override
     public void updateExpandedViewPos(int thingy) {
         if (SPEW) Log.v(TAG, "updateExpandedViewPos");
 
@@ -2452,15 +2225,8 @@
 
         FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mNotificationPanel.getLayoutParams();
         lp.gravity = mNotificationPanelGravity;
-        lp.setMarginStart(mNotificationPanelMarginPx);
         mNotificationPanel.setLayoutParams(lp);
 
-        if (ENABLE_HEADS_UP && mHeadsUpNotificationView != null) {
-            mHeadsUpNotificationView.setMargin(mNotificationPanelMarginPx);
-            mStackScroller.getLocationOnScreen(mStackScrollerPosition);
-            mHeadsUpVerticalOffset = mStackScrollerPosition[1] - mNaturalBarHeight;
-        }
-
         updateCarrierLabelVisibility(false);
     }
 
@@ -2508,17 +2274,6 @@
         animateCollapsePanels();
     }
 
-    private View.OnClickListener mSettingsButtonListener = new View.OnClickListener() {
-        public void onClick(View v) {
-            if (mHasQuickSettings) {
-                animateExpandSettingsPanel();
-            } else {
-                startActivityDismissingKeyguard(
-                        new Intent(android.provider.Settings.ACTION_SETTINGS), true);
-            }
-        }
-    };
-
     private View.OnClickListener mClockClickListener = new View.OnClickListener() {
         public void onClick(View v) {
             startActivityDismissingKeyguard(
@@ -2551,12 +2306,14 @@
                 notifyNavigationBarScreenOn(false);
                 notifyHeadsUpScreenOn(false);
                 finishBarAnimations();
+                stopNotificationLogging();
             }
             else if (Intent.ACTION_SCREEN_ON.equals(action)) {
                 mScreenOn = true;
                 // work around problem where mDisplay.getRotation() is not stable while screen is off (bug 7086018)
                 repositionNavigationBar();
                 notifyNavigationBarScreenOn(true);
+                startNotificationLoggingIfScreenOnAndVisible();
             }
             else if (ACTION_DEMO.equals(action)) {
                 Bundle bundle = intent.getExtras();
@@ -2617,17 +2374,6 @@
         }
     }
 
-    public void animateHeadsUp(boolean animateInto, float frac) {
-        if (!ENABLE_HEADS_UP || mHeadsUpNotificationView == null) return;
-        frac = frac / 0.4f;
-        frac = frac < 1.0f ? frac : 1.0f;
-        float alpha = 1.0f - frac;
-        float offset = mHeadsUpVerticalOffset * frac;
-        offset = animateInto ? offset : 0f;
-        mHeadsUpNotificationView.setAlpha(alpha);
-        mHeadsUpNotificationView.setY(offset);
-    }
-
     public void onHeadsUpDismissed() {
         if (mInterruptingNotificationEntry == null) return;
         mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
@@ -2652,15 +2398,8 @@
      * meantime, just update the things that we know change.
      */
     void updateResources() {
-        final Context context = mContext;
-        final Resources res = context.getResources();
-
-        if (mClearButton instanceof TextView) {
-            ((TextView)mClearButton).setText(context.getText(R.string.status_bar_clear_all_button));
-        }
-
-        // Update the QuickSettings container
-        if (mQS != null) mQS.updateResources();
+        // Update the quick setting tiles
+        if (mQSPanel != null) mQSPanel.updateResources();
 
         loadDimens();
     }
@@ -2700,17 +2439,13 @@
 
         mFlingGestureMaxOutputVelocityPx = res.getDimension(R.dimen.fling_gesture_max_output_velocity);
 
-        mNotificationPanelMarginBottomPx
-            = (int) res.getDimension(R.dimen.notification_panel_margin_bottom);
-        mNotificationPanelMarginPx
-            = (int) res.getDimension(R.dimen.notification_panel_margin_left);
         mNotificationPanelGravity = res.getInteger(R.integer.notification_panel_layout_gravity);
         if (mNotificationPanelGravity <= 0) {
             mNotificationPanelGravity = Gravity.START | Gravity.TOP;
         }
 
         mCarrierLabelHeight = res.getDimensionPixelSize(R.dimen.carrier_label_height);
-        mNotificationHeaderHeight = res.getDimensionPixelSize(R.dimen.notification_panel_header_height);
+        mStatusBarHeaderHeight = res.getDimensionPixelSize(R.dimen.status_bar_header_height);
 
         mNotificationPanelMinHeightFrac = res.getFraction(R.dimen.notification_panel_min_height_frac, 1, 1);
         if (mNotificationPanelMinHeightFrac < 0f || mNotificationPanelMinHeightFrac > 1f) {
@@ -2730,22 +2465,40 @@
 
     @Override
     protected void visibilityChanged(boolean visible) {
+        mVisible = visible;
         if (visible) {
-            mStackScroller.setChildLocationsChangedListener(mNotificationLocationsChangedListener);
+            startNotificationLoggingIfScreenOnAndVisible();
         } else {
-            // Report all notifications as invisible and turn down the
-            // reporter.
-            if (!mCurrentlyVisibleNotifications.isEmpty()) {
-                logNotificationVisibilityChanges(
-                        Collections.<String>emptyList(), mCurrentlyVisibleNotifications);
-                mCurrentlyVisibleNotifications.clear();
-            }
-            mHandler.removeCallbacks(mVisibilityReporter);
-            mStackScroller.setChildLocationsChangedListener(null);
+            stopNotificationLogging();
         }
         super.visibilityChanged(visible);
     }
 
+    private void stopNotificationLogging() {
+        // Report all notifications as invisible and turn down the
+        // reporter.
+        if (!mCurrentlyVisibleNotifications.isEmpty()) {
+            logNotificationVisibilityChanges(
+                    Collections.<String>emptyList(), mCurrentlyVisibleNotifications);
+            mCurrentlyVisibleNotifications.clear();
+        }
+        mHandler.removeCallbacks(mVisibilityReporter);
+        mStackScroller.setChildLocationsChangedListener(null);
+    }
+
+    private void startNotificationLoggingIfScreenOnAndVisible() {
+        if (mVisible && mScreenOn) {
+            mStackScroller.setChildLocationsChangedListener(mNotificationLocationsChangedListener);
+            // Some transitions like mScreenOn=false -> mScreenOn=true don't
+            // cause the scroller to emit child location events. Hence generate
+            // one ourselves to guarantee that we're reporting visible
+            // notifications.
+            // (Note that in cases where the scroller does emit events, this
+            // additional event doesn't break anything.)
+            mNotificationLocationsChangedListener.onChildLocationsChanged(mStackScroller);
+        }
+    }
+
     private void logNotificationVisibilityChanges(
             Collection<String> newlyVisible, Collection<String> noLongerVisible) {
         if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) {
@@ -2805,10 +2558,29 @@
                 || (mDisabled & StatusBarManager.DISABLE_SEARCH) != 0;
     }
 
-    public void startSettingsActivity(String action) {
-        if (mQS != null) {
-            mQS.startSettingsActivity(action);
+    public void postStartSettingsActivity(final Intent intent) {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                handleStartSettingsActivity(intent, true /*onlyProvisioned*/);
+            }
+        });
+    }
+
+    private void handleStartSettingsActivity(Intent intent, boolean onlyProvisioned) {
+        if (onlyProvisioned && !isDeviceProvisioned()) return;
+        try {
+            // Dismiss the lock screen when Settings starts.
+            ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
+        } catch (RemoteException e) {
         }
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+        animateCollapsePanels();
+    }
+
+    public void startSettingsActivity(String action) {
+        postStartSettingsActivity(new Intent(action));
     }
 
     private static class FastColorDrawable extends Drawable {
@@ -2930,51 +2702,55 @@
         }
     }
 
-    public boolean isOnKeyguard() {
-        return mOnKeyguard;
+    /**
+     * @return The {@link StatusBarState} the status bar is in.
+     */
+    public int getBarState() {
+        return mState;
     }
 
     public void showKeyguard() {
-        mOnKeyguard = true;
+        setBarState(StatusBarState.KEYGUARD);
         updateKeyguardState();
         instantExpandNotificationsPanel();
+        mLeaveOpenOnKeyguardHide = false;
     }
 
     public void hideKeyguard() {
-        mOnKeyguard = false;
+        setBarState(StatusBarState.SHADE);
+        if (mLeaveOpenOnKeyguardHide) {
+            mLeaveOpenOnKeyguardHide = false;
+            mNotificationPanel.animateNextTopPaddingChange();
+        } else {
+            instantCollapseNotificationPanel();
+        }
         updateKeyguardState();
-        instantCollapseNotificationPanel();
     }
 
     private void updatePublicMode() {
-        setLockscreenPublicMode(mOnKeyguard && mStatusBarKeyguardViewManager.isSecure());
+        setLockscreenPublicMode(mState == StatusBarState.KEYGUARD
+                && mStatusBarKeyguardViewManager.isSecure());
     }
 
     private void updateKeyguardState() {
-        if (mOnKeyguard) {
-            if (isFlippedToSettings()) {
-                flipToNotifications(false /*animate*/);
-            }
+        if (mState == StatusBarState.KEYGUARD) {
             mKeyguardStatusView.setVisibility(View.VISIBLE);
-            mKeyguardBottomArea.setVisibility(View.VISIBLE);
             mKeyguardIndicationTextView.setVisibility(View.VISIBLE);
             mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
-            mKeyguardCarrierLabel.setVisibility(View.VISIBLE);
-            mNotificationPanelHeader.setVisibility(View.GONE);
-
-            mKeyguardFlipper.setVisibility(View.VISIBLE);
-            mSettingsContainer.setKeyguardShowing(true);
+            mNotificationPanel.closeQs();
         } else {
             mKeyguardStatusView.setVisibility(View.GONE);
-            mKeyguardBottomArea.setVisibility(View.GONE);
             mKeyguardIndicationTextView.setVisibility(View.GONE);
-            mKeyguardCarrierLabel.setVisibility(View.GONE);
-            mNotificationPanelHeader.setVisibility(View.VISIBLE);
-
-            mKeyguardFlipper.setVisibility(View.GONE);
-            mSettingsContainer.setKeyguardShowing(false);
+        }
+        if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
+            mKeyguardBottomArea.setVisibility(View.VISIBLE);
+            mHeader.setKeyguardShowing(true);
+        } else {
+            mKeyguardBottomArea.setVisibility(View.GONE);
+            mHeader.setKeyguardShowing(false);
         }
 
+        updateStackScrollerState();
         updatePublicMode();
         updateRowStates();
         checkBarModes();
@@ -2982,18 +2758,27 @@
         updateCarrierLabelVisibility(false);
     }
 
+    public void updateStackScrollerState() {
+        mStackScroller.setDimmed(mState == StatusBarState.KEYGUARD, false /* animate */);
+    }
+
     public void userActivity() {
-        if (mOnKeyguard) {
+        if (mState == StatusBarState.KEYGUARD) {
             mKeyguardViewMediatorCallback.userActivity();
         }
     }
 
+    public boolean interceptMediaKey(KeyEvent event) {
+        return mState == StatusBarState.KEYGUARD
+                && mStatusBarKeyguardViewManager.interceptMediaKey(event);
+    }
+
     public boolean onMenuPressed() {
-        return mOnKeyguard && mStatusBarKeyguardViewManager.onMenuPressed();
+        return mState == StatusBarState.KEYGUARD && mStatusBarKeyguardViewManager.onMenuPressed();
     }
 
     public boolean onBackPressed() {
-        if (mOnKeyguard) {
+        if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
             return mStatusBarKeyguardViewManager.onBackPressed();
         } else {
             animateCollapsePanels();
@@ -3002,7 +2787,7 @@
     }
 
     private void showBouncer() {
-        if (mOnKeyguard) {
+        if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
             mStatusBarKeyguardViewManager.dismiss();
         }
     }
@@ -3035,23 +2820,33 @@
     public void onActivated(View view) {
         userActivity();
         mKeyguardIndicationTextView.switchIndication(R.string.notification_tap_again);
-        super.onActivated(view);
+        mStackScroller.setActivatedChild(view);
+    }
+
+    /**
+     * @param state The {@link StatusBarState} to set.
+     */
+    public void setBarState(int state) {
+        mState = state;
+        mStatusBarWindowManager.setStatusBarState(state);
     }
 
     @Override
-    public void onReset(View view) {
-        super.onReset(view);
-        mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
+    public void onActivationReset(View view) {
+        if (view == mStackScroller.getActivatedChild()) {
+            mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
+            mStackScroller.setActivatedChild(null);
+        }
     }
 
     public void onTrackingStarted() {
-        if (mOnKeyguard) {
+        if (mState == StatusBarState.KEYGUARD) {
             mKeyguardIndicationTextView.switchIndication(R.string.keyguard_unlock);
         }
     }
 
     public void onTrackingStopped() {
-        if (mOnKeyguard) {
+        if (mState == StatusBarState.KEYGUARD) {
             mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
         }
     }
@@ -3065,135 +2860,59 @@
         return mNavigationBarView;
     }
 
+    // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
+
+    @Override
+    public void onDraggedDown(View startingChild) {
+        goToLockedShade(startingChild);
+    }
+
+    @Override
+    public void onDragDownReset() {
+        mStackScroller.setDimmed(true /* dimmed */, true /* animated */);
+    }
+
+    public void onThresholdReached() {
+        mStackScroller.setDimmed(false /* dimmed */, true /* animate */);
+    }
+
+    /**
+     * If secure with redaction: Show bouncer, go to unlocked shade.
+     *
+     * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p>
+     *
+     * @param expandView The view to expand after going to the shade.
+     */
+    public void goToLockedShade(View expandView) {
+        if (expandView instanceof ExpandableNotificationRow) {
+            ExpandableNotificationRow row = (ExpandableNotificationRow) expandView;
+            row.setUserExpanded(true);
+        }
+        if (isLockscreenPublicMode() && !userAllowsPrivateNotificationsInPublic(mCurrentUserId)) {
+            mLeaveOpenOnKeyguardHide = true;
+            showBouncer();
+        } else {
+            mNotificationPanel.animateNextTopPaddingChange();
+            setBarState(StatusBarState.SHADE_LOCKED);
+            updateKeyguardState();
+        }
+    }
+
     /**
      * @return a ViewGroup that spans the entire panel which contains the quick settings
      */
     public ViewGroup getQuickSettingsOverlayParent() {
-        if (mHasQuickSettings) {
-            return mNotificationPanel;
-        } else {
-            return null;
-        }
+        return mNotificationPanel;
     }
 
-    public static boolean inBounds(View view, MotionEvent event, boolean orAbove) {
-        final int[] location = new int[2];
-        view.getLocationInWindow(location);
-        final int rx = (int) event.getRawX();
-        final int ry = (int) event.getRawY();
-        return rx >= location[0] && rx <= location[0] + view.getMeasuredWidth()
-                && (orAbove || ry >= location[1]) && ry <= location[1] + view.getMeasuredHeight();
+    public LinearLayout getSystemIcons() {
+        return mSystemIcons;
     }
 
-    private final class FlipperButton {
-        private final View mHolder;
-
-        private ImageView mSettingsButton, mNotificationButton;
-        private Animator mSettingsButtonAnim, mNotificationButtonAnim;
-
-        public FlipperButton(View holder) {
-            mHolder = holder;
-            mSettingsButton = (ImageView) holder.findViewById(R.id.settings_button);
-            if (mSettingsButton != null) {
-                mSettingsButton.setOnClickListener(mSettingsButtonListener);
-                if (mHasQuickSettings) {
-                    // the settings panel is hiding behind this button
-                    mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings);
-                    mSettingsButton.setVisibility(View.VISIBLE);
-                } else {
-                    // no settings panel, go straight to settings
-                    mSettingsButton.setVisibility(View.VISIBLE);
-                    mSettingsButton.setImageResource(R.drawable.ic_notify_settings);
-                }
-            }
-            mNotificationButton = (ImageView) holder.findViewById(R.id.notification_button);
-            if (mNotificationButton != null) {
-                mNotificationButton.setOnClickListener(mNotificationButtonListener);
-            }
-        }
-
-        public boolean inHolderBounds(MotionEvent event) {
-            return inBounds(mHolder, event, false);
-        }
-
-        public void provisionCheck(boolean provisioned) {
-            if (mSettingsButton != null) {
-                mSettingsButton.setEnabled(provisioned);
-            }
-        }
-
-        public void userSetup(boolean userSetup) {
-            if (mSettingsButton != null) {
-                mSettingsButton.setVisibility(userSetup ? View.VISIBLE : View.INVISIBLE);
-            }
-        }
-
-        public void reset() {
-            cancel();
-            mSettingsButton.setVisibility(View.VISIBLE);
-            mNotificationButton.setVisibility(View.GONE);
-        }
-
-        public void refreshLayout() {
-            if (mSettingsButton != null) {
-                // Force asset reloading
-                mSettingsButton.setImageDrawable(null);
-                mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings);
-            }
-
-            if (mNotificationButton != null) {
-                // Force asset reloading
-                mNotificationButton.setImageDrawable(null);
-                mNotificationButton.setImageResource(R.drawable.ic_notifications);
-            }
-        }
-
-        public void flipToSettings(boolean animate) {
-            mNotificationButton.setVisibility(View.VISIBLE);
-            if (animate) {
-                mSettingsButtonAnim = start(
-                    setVisibilityWhenDone(
-                        ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f)
-                            .setDuration(FLIP_DURATION_OUT),
-                        mStackScroller, View.INVISIBLE));
-                mNotificationButtonAnim = start(
-                    startDelay(FLIP_DURATION_OUT,
-                        ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f)
-                            .setDuration(FLIP_DURATION_IN)));
-            } else {
-                mSettingsButton.setAlpha(0f);
-                mSettingsButton.setVisibility(View.INVISIBLE);
-                mNotificationButton.setAlpha(1f);
-            }
-        }
-
-        public void flipToNotifications(boolean animate) {
-            mSettingsButton.setVisibility(View.VISIBLE);
-            if (animate) {
-                mNotificationButtonAnim = start(
-                    setVisibilityWhenDone(
-                        ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 0f)
-                            .setDuration(FLIP_DURATION_OUT),
-                        mNotificationButton, View.INVISIBLE));
-
-                mSettingsButtonAnim = start(
-                    startDelay(FLIP_DURATION_OUT,
-                        ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f)
-                            .setDuration(FLIP_DURATION_IN)));
-            } else {
-                mNotificationButton.setVisibility(View.INVISIBLE);
-                mNotificationButton.setAlpha(0f);
-                mSettingsButton.setAlpha(1f);
-            }
-        }
-
-        public void cancel() {
-            cancelAnim(mSettingsButtonAnim);
-            cancelAnim(mNotificationButtonAnim);
-        }
-
-        public void setVisibility(int vis) {
-            mHolder.setVisibility(vis);
-        }
+    /**
+     * Reattaches the system icons to its normal parent in collapsed status bar.
+     */
+    public void reattachSystemIcons() {
+        mSystemIconArea.addView(mSystemIcons, 0);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 79c63f7..084bfcf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -19,7 +19,6 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.Resources;
-import android.content.res.Resources.NotFoundException;
 import android.util.AttributeSet;
 import android.util.EventLog;
 import android.util.Log;
@@ -29,6 +28,7 @@
 
 import com.android.systemui.EventLogTags;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.StatusBarState;
 
 public class PhoneStatusBarView extends PanelBar {
     private static final String TAG = "PhoneStatusBarView";
@@ -63,7 +63,7 @@
     }
 
     @Override
-    public void onAttachedToWindow() {
+    public void onFinishInflate() {
         mBarTransitions.init();
     }
 
@@ -187,7 +187,10 @@
         if (panel == mFadingPanel && mScrimColor != 0 && ActivityManager.isHighEndGfx()
                 && mBar.mStatusBarWindow != null) {
             if (mShouldFade) {
-                int scrimColor = mBar.isOnKeyguard() ? mScrimColorKeyguard : mScrimColor;
+                int scrimColor = (mBar.getBarState() == StatusBarState.KEYGUARD
+                        || mBar.getBarState() == StatusBarState.SHADE_LOCKED)
+                        ? mScrimColorKeyguard
+                        : mScrimColor;
                 frac = mPanelExpandedFractionSum; // don't judge me
                 // let's start this 20% of the way down the screen
                 frac = frac * 1.2f - 0.2f;
@@ -217,8 +220,6 @@
             panel.setAlpha(alpha);
         }
 
-        mBar.animateHeadsUp(mNotificationPanel == panel, mPanelExpandedFractionSum);
-
         mBar.updateCarrierLabelVisibility(false);
         mBar.userActivity();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
new file mode 100644
index 0000000..1fe3be5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.Intent;
+import android.graphics.drawable.VectorDrawable;
+import android.os.HandlerThread;
+import android.os.Looper;
+
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.tiles.AirplaneModeTile;
+import com.android.systemui.qs.tiles.BluetoothTile;
+import com.android.systemui.qs.tiles.BugreportTile;
+import com.android.systemui.qs.tiles.CastTile;
+import com.android.systemui.qs.tiles.CellularTile;
+import com.android.systemui.qs.tiles.ColorInversionTile;
+import com.android.systemui.qs.tiles.LocationTile;
+import com.android.systemui.qs.tiles.RingerModeTile;
+import com.android.systemui.qs.tiles.RotationLockTile;
+import com.android.systemui.qs.tiles.HotspotTile;
+import com.android.systemui.qs.tiles.WifiTile;
+import com.android.systemui.qs.tiles.ZenModeTile;
+import com.android.systemui.settings.CurrentUserTracker;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.TetheringController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Platform implementation of the quick settings tile host **/
+public class QSTileHost implements QSTile.Host {
+
+    private final Context mContext;
+    private final PhoneStatusBar mStatusBar;
+    private final BluetoothController mBluetooth;
+    private final LocationController mLocation;
+    private final RotationLockController mRotation;
+    private final NetworkController mNetwork;
+    private final ZenModeController mZen;
+    private final TetheringController mTethering;
+    private final CastController mCast;
+    private final Looper mLooper;
+    private final CurrentUserTracker mUserTracker;
+    private final ArrayList<QSTile<?>> mTiles = new ArrayList<QSTile<?>>();
+
+    public QSTileHost(Context context, PhoneStatusBar statusBar,
+            BluetoothController bluetooth, LocationController location,
+            RotationLockController rotation, NetworkController network,
+            ZenModeController zen, TetheringController tethering,
+            CastController cast) {
+        mContext = context;
+        mStatusBar = statusBar;
+        mBluetooth = bluetooth;
+        mLocation = location;
+        mRotation = rotation;
+        mNetwork = network;
+        mZen = zen;
+        mTethering = tethering;
+        mCast = cast;
+
+        final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName());
+        ht.start();
+        mLooper = ht.getLooper();
+
+        mTiles.add(new WifiTile(this));
+        mTiles.add(new BluetoothTile(this));
+        mTiles.add(new ColorInversionTile(this));
+        mTiles.add(new CellularTile(this));
+        mTiles.add(new AirplaneModeTile(this));
+        mTiles.add(new ZenModeTile(this));
+        mTiles.add(new RingerModeTile(this));
+        mTiles.add(new RotationLockTile(this));
+        mTiles.add(new LocationTile(this));
+        mTiles.add(new CastTile(this));
+        mTiles.add(new HotspotTile(this));
+        mTiles.add(new BugreportTile(this));
+
+        mUserTracker = new CurrentUserTracker(mContext) {
+            @Override
+            public void onUserSwitched(int newUserId) {
+                for (QSTile<?> tile : mTiles) {
+                    tile.userSwitch(newUserId);
+                }
+            }
+        };
+        mUserTracker.startTracking();
+    }
+
+    @Override
+    public List<QSTile<?>> getTiles() {
+        return mTiles;
+    }
+
+    @Override
+    public void startSettingsActivity(final Intent intent) {
+        mStatusBar.postStartSettingsActivity(intent);
+    }
+
+    @Override
+    public void warn(String message, Throwable t) {
+        // already logged
+    }
+
+    @Override
+    public void collapsePanels() {
+        mStatusBar.postAnimateCollapsePanels();
+    }
+
+    @Override
+    public Looper getLooper() {
+        return mLooper;
+    }
+
+    @Override
+    public Context getContext() {
+        return mContext;
+    }
+
+    @Override
+    public VectorDrawable getVectorDrawable(int resId) {
+        return (VectorDrawable) mContext.getDrawable(resId);
+    }
+
+    @Override
+    public BluetoothController getBluetoothController() {
+        return mBluetooth;
+    }
+
+    @Override
+    public LocationController getLocationController() {
+        return mLocation;
+    }
+
+    @Override
+    public RotationLockController getRotationLockController() {
+        return mRotation;
+    }
+
+    @Override
+    public NetworkController getNetworkController() {
+        return mNetwork;
+    }
+
+    @Override
+    public ZenModeController getZenModeController() {
+        return mZen;
+    }
+
+    @Override
+    public TetheringController getTetheringController() {
+        return mTethering;
+    }
+
+    @Override
+    public CastController getCastController() {
+        return mCast;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
deleted file mode 100644
index f3ebf1b..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ /dev/null
@@ -1,1127 +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.statusbar.phone;
-
-import android.animation.ValueAnimator;
-import android.app.ActivityManagerNative;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.PendingIntent;
-import android.app.admin.DevicePolicyManager;
-import android.bluetooth.BluetoothAdapter;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.UserInfo;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.hardware.display.DisplayManager;
-import android.media.MediaRouter;
-import android.net.wifi.WifiManager;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.AlarmClock;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.Profile;
-import android.provider.Settings;
-import android.security.KeyChain;
-import android.text.TextUtils.TruncateAt;
-import android.util.Log;
-import android.util.Pair;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
-import android.view.WindowManager.LayoutParams;
-import android.widget.Button;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.internal.app.MediaRouteDialogPresenter;
-import com.android.systemui.R;
-import com.android.systemui.settings.UserSwitcherHostView;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.ActivityState;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.BluetoothState;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.RSSIState;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.State;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.UserState;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.WifiState;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.RotationLockController;
-
-import java.util.ArrayList;
-
-/**
- *
- */
-class QuickSettings {
-    static final boolean DEBUG_GONE_TILES = false;
-    private static final String TAG = "QuickSettings";
-    public static final boolean SHOW_IME_TILE = false;
-    public static final boolean SHOW_ACCESSIBILITY_TILES = true;
-
-    public static final boolean LONG_PRESS_TOGGLES = true;
-
-    private Context mContext;
-    private PanelBar mBar;
-    private QuickSettingsModel mModel;
-    private ViewGroup mContainerView;
-
-    private DevicePolicyManager mDevicePolicyManager;
-    private PhoneStatusBar mStatusBarService;
-    private BluetoothState mBluetoothState;
-    private BluetoothAdapter mBluetoothAdapter;
-    private WifiManager mWifiManager;
-
-    private BluetoothController mBluetoothController;
-    private RotationLockController mRotationLockController;
-    private LocationController mLocationController;
-
-    private AsyncTask<Void, Void, Pair<String, Drawable>> mUserInfoTask;
-    private AsyncTask<Void, Void, Pair<Boolean, Boolean>> mQueryCertTask;
-
-    boolean mTilesSetUp = false;
-    boolean mUseDefaultAvatar = false;
-
-    private Handler mHandler;
-
-    // The set of QuickSettingsTiles that have dynamic spans (and need to be updated on
-    // configuration change)
-    private final ArrayList<QuickSettingsTileView> mDynamicSpannedTiles =
-            new ArrayList<QuickSettingsTileView>();
-
-    public QuickSettings(Context context, QuickSettingsContainerView container) {
-        mDevicePolicyManager
-            = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        mContext = context;
-        mContainerView = container;
-        mModel = new QuickSettingsModel(context);
-        mBluetoothState = new QuickSettingsModel.BluetoothState();
-        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
-        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
-
-        mHandler = new Handler();
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
-        filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
-        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
-        filter.addAction(Intent.ACTION_USER_SWITCHED);
-        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
-        filter.addAction(KeyChain.ACTION_STORAGE_CHANGED);
-        mContext.registerReceiver(mReceiver, filter);
-
-        IntentFilter profileFilter = new IntentFilter();
-        profileFilter.addAction(ContactsContract.Intents.ACTION_PROFILE_CHANGED);
-        profileFilter.addAction(Intent.ACTION_USER_INFO_CHANGED);
-        mContext.registerReceiverAsUser(mProfileReceiver, UserHandle.ALL, profileFilter,
-                null, null);
-    }
-
-    void setBar(PanelBar bar) {
-        mBar = bar;
-    }
-
-    public void setService(PhoneStatusBar phoneStatusBar) {
-        mStatusBarService = phoneStatusBar;
-    }
-
-    public PhoneStatusBar getService() {
-        return mStatusBarService;
-    }
-
-    public void setImeWindowStatus(boolean visible) {
-        mModel.onImeWindowStatusChanged(visible);
-    }
-
-    void setup(NetworkController networkController, BluetoothController bluetoothController,
-            BatteryController batteryController, LocationController locationController,
-            RotationLockController rotationLockController) {
-        mBluetoothController = bluetoothController;
-        mRotationLockController = rotationLockController;
-        mLocationController = locationController;
-
-        setupQuickSettings();
-        updateResources();
-        applyLocationEnabledStatus();
-
-        networkController.addNetworkSignalChangedCallback(mModel);
-        bluetoothController.addStateChangedCallback(mModel);
-        batteryController.addStateChangedCallback(mModel);
-        locationController.addSettingsChangedCallback(mModel);
-        if (rotationLockController != null) {
-            rotationLockController.addRotationLockControllerCallback(mModel);
-        }
-    }
-
-    private void queryForSslCaCerts() {
-        mQueryCertTask = new AsyncTask<Void, Void, Pair<Boolean, Boolean>>() {
-            @Override
-            protected Pair<Boolean, Boolean> doInBackground(Void... params) {
-                boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
-                boolean isManaged = mDevicePolicyManager.getDeviceOwner() != null;
-
-                return Pair.create(hasCert, isManaged);
-            }
-            @Override
-            protected void onPostExecute(Pair<Boolean, Boolean> result) {
-                super.onPostExecute(result);
-                boolean hasCert = result.first;
-                boolean isManaged = result.second;
-                mModel.setSslCaCertWarningTileInfo(hasCert, isManaged);
-            }
-        };
-        mQueryCertTask.execute();
-    }
-
-    private void queryForUserInformation() {
-        Context currentUserContext = null;
-        UserInfo userInfo = null;
-        try {
-            userInfo = ActivityManagerNative.getDefault().getCurrentUser();
-            currentUserContext = mContext.createPackageContextAsUser("android", 0,
-                    new UserHandle(userInfo.id));
-        } catch (NameNotFoundException e) {
-            Log.e(TAG, "Couldn't create user context", e);
-            throw new RuntimeException(e);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Couldn't get user info", e);
-        }
-        final int userId = userInfo.id;
-        final String userName = userInfo.name;
-
-        final Context context = currentUserContext;
-        mUserInfoTask = new AsyncTask<Void, Void, Pair<String, Drawable>>() {
-            @Override
-            protected Pair<String, Drawable> doInBackground(Void... params) {
-                final UserManager um = UserManager.get(mContext);
-
-                // Fall back to the UserManager nickname if we can't read the name from the local
-                // profile below.
-                String name = userName;
-                Drawable avatar = null;
-                Bitmap rawAvatar = um.getUserIcon(userId);
-                if (rawAvatar != null) {
-                    avatar = new BitmapDrawable(mContext.getResources(), rawAvatar);
-                } else {
-                    avatar = mContext.getResources().getDrawable(R.drawable.ic_qs_default_user);
-                    mUseDefaultAvatar = true;
-                }
-
-                // If it's a single-user device, get the profile name, since the nickname is not
-                // usually valid
-                if (um.getUsers().size() <= 1) {
-                    // Try and read the display name from the local profile
-                    final Cursor cursor = context.getContentResolver().query(
-                            Profile.CONTENT_URI, new String[] {Phone._ID, Phone.DISPLAY_NAME},
-                            null, null, null);
-                    if (cursor != null) {
-                        try {
-                            if (cursor.moveToFirst()) {
-                                name = cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME));
-                            }
-                        } finally {
-                            cursor.close();
-                        }
-                    }
-                }
-                return new Pair<String, Drawable>(name, avatar);
-            }
-
-            @Override
-            protected void onPostExecute(Pair<String, Drawable> result) {
-                super.onPostExecute(result);
-                mModel.setUserTileInfo(result.first, result.second);
-                mUserInfoTask = null;
-            }
-        };
-        mUserInfoTask.execute();
-    }
-
-    private void setupQuickSettings() {
-        // Setup the tiles that we are going to be showing (including the temporary ones)
-        LayoutInflater inflater = LayoutInflater.from(mContext);
-
-        addUserTiles(mContainerView, inflater);
-        addSystemTiles(mContainerView, inflater);
-        addTemporaryTiles(mContainerView, inflater);
-        addAccessibilityTiles(mContainerView);
-
-        queryForUserInformation();
-        queryForSslCaCerts();
-        mTilesSetUp = true;
-    }
-
-    public void startSettingsActivity(String action) {
-        Intent intent = new Intent(action);
-        startSettingsActivity(intent);
-    }
-
-    private void startSettingsActivity(Intent intent) {
-        startSettingsActivity(intent, true);
-    }
-
-    private void collapsePanels() {
-        getService().animateCollapsePanels();
-    }
-
-    private void startSettingsActivity(Intent intent, boolean onlyProvisioned) {
-        if (onlyProvisioned && !getService().isDeviceProvisioned()) return;
-        try {
-            // Dismiss the lock screen when Settings starts.
-            ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
-        } catch (RemoteException e) {
-        }
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-        mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
-        collapsePanels();
-    }
-
-    private void addAccessibilityTiles(ViewGroup parent) {
-        if (!DEBUG_GONE_TILES && !SHOW_ACCESSIBILITY_TILES) return;
-
-        // Color inversion tile
-        final SystemSettingTile inversionTile = new SystemSettingTile(mContext);
-        inversionTile.setUri(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
-                SystemSettingTile.TYPE_SECURE);
-        inversionTile.setFragment("Settings$AccessibilityInversionSettingsActivity");
-        mModel.addInversionTile(inversionTile, inversionTile.getRefreshCallback());
-        parent.addView(inversionTile);
-
-        // Contrast enhancement tile
-        final SystemSettingTile contrastTile = new SystemSettingTile(mContext);
-        contrastTile.setUri(Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED,
-                SystemSettingTile.TYPE_SECURE);
-        contrastTile.setFragment("Settings$AccessibilityContrastSettingsActivity");
-        mModel.addContrastTile(contrastTile, contrastTile.getRefreshCallback());
-        parent.addView(contrastTile);
-
-        // Color space adjustment tile
-        final SystemSettingTile colorSpaceTile = new SystemSettingTile(mContext);
-        colorSpaceTile.setUri(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
-                SystemSettingTile.TYPE_SECURE);
-        colorSpaceTile.setFragment("Settings$AccessibilityDaltonizerSettingsActivity");
-        mModel.addColorSpaceTile(colorSpaceTile, colorSpaceTile.getRefreshCallback());
-        parent.addView(colorSpaceTile);
-    }
-
-    private void addUserTiles(final ViewGroup parent, final LayoutInflater inflater) {
-        QuickSettingsTileView userTile = (QuickSettingsTileView)
-                inflater.inflate(R.layout.quick_settings_tile, parent, false);
-        userTile.setContent(R.layout.quick_settings_tile_user, inflater);
-        userTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                final UserManager um = UserManager.get(mContext);
-                if (um.isUserSwitcherEnabled()) {
-                    final ViewGroup switcherParent = getService().getQuickSettingsOverlayParent();
-                    final UserSwitcherHostView switcher = (UserSwitcherHostView) inflater.inflate(
-                            R.layout.user_switcher_host, switcherParent, false);
-                    switcher.setFinishRunnable(new Runnable() {
-                        @Override
-                        public void run() {
-                            switcherParent.removeView(switcher);
-                        }
-                    });
-                    switcher.refreshUsers();
-                    switcherParent.addView(switcher);
-                } else {
-                    collapsePanels();
-                    Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
-                            mContext, v, ContactsContract.Profile.CONTENT_URI,
-                            ContactsContract.QuickContact.MODE_LARGE, null);
-                    mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
-                }
-            }
-        });
-        mModel.addUserTile(userTile, new QuickSettingsModel.RefreshCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView view, State state) {
-                UserState us = (UserState) state;
-                ImageView iv = (ImageView) view.findViewById(R.id.user_imageview);
-                TextView tv = (TextView) view.findViewById(R.id.user_textview);
-                tv.setText(state.label);
-                iv.setImageDrawable(us.avatar);
-                view.setContentDescription(mContext.getString(
-                        R.string.accessibility_quick_settings_user, state.label));
-            }
-        });
-        parent.addView(userTile);
-        mDynamicSpannedTiles.add(userTile);
-
-        // Brightness
-        final QuickSettingsBasicTile brightnessTile
-                = new QuickSettingsBasicTile(mContext);
-        brightnessTile.setImageResource(R.drawable.ic_qs_brightness_auto_off);
-        brightnessTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                collapsePanels();
-                showBrightnessDialog();
-            }
-        });
-        mModel.addBrightnessTile(brightnessTile,
-                new QuickSettingsModel.BasicRefreshCallback(brightnessTile));
-        parent.addView(brightnessTile);
-        mDynamicSpannedTiles.add(brightnessTile);
-
-        // Settings tile
-        final QuickSettingsBasicTile settingsTile = new QuickSettingsBasicTile(mContext);
-        settingsTile.setImageResource(R.drawable.ic_qs_settings);
-        settingsTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                startSettingsActivity(android.provider.Settings.ACTION_SETTINGS);
-            }
-        });
-        mModel.addSettingsTile(settingsTile,
-                new QuickSettingsModel.BasicRefreshCallback(settingsTile));
-        parent.addView(settingsTile);
-        mDynamicSpannedTiles.add(settingsTile);
-    }
-
-    private void addSystemTiles(ViewGroup parent, LayoutInflater inflater) {
-        // Wi-fi
-        final QuickSettingsTileView wifiTile = (QuickSettingsTileView)
-                inflater.inflate(R.layout.quick_settings_tile, parent, false);
-        wifiTile.setContent(R.layout.quick_settings_tile_wifi, inflater);
-        wifiTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                startSettingsActivity(android.provider.Settings.ACTION_WIFI_SETTINGS);
-            }
-        });
-        if (LONG_PRESS_TOGGLES) {
-            wifiTile.setOnLongClickListener(new View.OnLongClickListener() {
-                @Override
-                public boolean onLongClick(View v) {
-                    final boolean enable =
-                            (mWifiManager.getWifiState() != WifiManager.WIFI_STATE_ENABLED);
-                    new AsyncTask<Void, Void, Void>() {
-                        @Override
-                        protected Void doInBackground(Void... args) {
-                            // Disable tethering if enabling Wifi
-                            final int wifiApState = mWifiManager.getWifiApState();
-                            if (enable && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
-                                           (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
-                                mWifiManager.setWifiApEnabled(null, false);
-                            }
-
-                            mWifiManager.setWifiEnabled(enable);
-                            return null;
-                        }
-                    }.execute();
-                    wifiTile.setPressed(false);
-                    return true;
-                }} );
-        }
-        mModel.addWifiTile(wifiTile, new NetworkActivityCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView view, State state) {
-                WifiState wifiState = (WifiState) state;
-                ImageView iv = (ImageView) view.findViewById(R.id.image);
-                iv.setImageResource(wifiState.iconId);
-                setActivity(view, wifiState);
-                TextView tv = (TextView) view.findViewById(R.id.text);
-                tv.setText(wifiState.label);
-                wifiTile.setContentDescription(mContext.getString(
-                        R.string.accessibility_quick_settings_wifi,
-                        wifiState.signalContentDescription,
-                        (wifiState.connected) ? wifiState.label : ""));
-            }
-        });
-        parent.addView(wifiTile);
-
-        if (mModel.deviceHasMobileData()) {
-            // RSSI
-            QuickSettingsTileView rssiTile = (QuickSettingsTileView)
-                    inflater.inflate(R.layout.quick_settings_tile, parent, false);
-            rssiTile.setContent(R.layout.quick_settings_tile_rssi, inflater);
-            rssiTile.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    Intent intent = new Intent();
-                    intent.setComponent(new ComponentName(
-                            "com.android.settings",
-                            "com.android.settings.Settings$DataUsageSummaryActivity"));
-                    startSettingsActivity(intent);
-                }
-            });
-            mModel.addRSSITile(rssiTile, new NetworkActivityCallback() {
-                @Override
-                public void refreshView(QuickSettingsTileView view, State state) {
-                    RSSIState rssiState = (RSSIState) state;
-                    ImageView iv = (ImageView) view.findViewById(R.id.rssi_image);
-                    ImageView iov = (ImageView) view.findViewById(R.id.rssi_overlay_image);
-                    TextView tv = (TextView) view.findViewById(R.id.rssi_textview);
-                    // Force refresh
-                    iv.setImageDrawable(null);
-                    iv.setImageResource(rssiState.signalIconId);
-
-                    if (rssiState.dataTypeIconId > 0) {
-                        iov.setImageResource(rssiState.dataTypeIconId);
-                    } else {
-                        iov.setImageDrawable(null);
-                    }
-                    setActivity(view, rssiState);
-
-                    tv.setText(state.label);
-                    view.setContentDescription(mContext.getResources().getString(
-                            R.string.accessibility_quick_settings_mobile,
-                            rssiState.signalContentDescription, rssiState.dataContentDescription,
-                            state.label));
-                }
-            });
-            parent.addView(rssiTile);
-        }
-
-        // Rotation Lock
-        if (mRotationLockController != null) {
-            final QuickSettingsBasicTile rotationLockTile
-                    = new QuickSettingsBasicTile(mContext);
-            rotationLockTile.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View view) {
-                    final boolean locked = mRotationLockController.isRotationLocked();
-                    mRotationLockController.setRotationLocked(!locked);
-                }
-            });
-            mModel.addRotationLockTile(rotationLockTile, mRotationLockController,
-                    new QuickSettingsModel.RefreshCallback() {
-                        @Override
-                        public void refreshView(QuickSettingsTileView view, State state) {
-                            QuickSettingsModel.RotationLockState rotationLockState =
-                                    (QuickSettingsModel.RotationLockState) state;
-                            view.setVisibility(rotationLockState.visible
-                                    ? View.VISIBLE : View.GONE);
-                            if (state.iconId != 0) {
-                                // needed to flush any cached IDs
-                                rotationLockTile.setImageDrawable(null);
-                                rotationLockTile.setImageResource(state.iconId);
-                            }
-                            if (state.label != null) {
-                                rotationLockTile.setText(state.label);
-                            }
-                        }
-                    });
-            parent.addView(rotationLockTile);
-        }
-
-        // Battery
-        final QuickSettingsTileView batteryTile = (QuickSettingsTileView)
-                inflater.inflate(R.layout.quick_settings_tile, parent, false);
-        batteryTile.setContent(R.layout.quick_settings_tile_battery, inflater);
-        batteryTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                startSettingsActivity(Intent.ACTION_POWER_USAGE_SUMMARY);
-            }
-        });
-        mModel.addBatteryTile(batteryTile, new QuickSettingsModel.RefreshCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView unused, State state) {
-                QuickSettingsModel.BatteryState batteryState =
-                        (QuickSettingsModel.BatteryState) state;
-                String t;
-                if (batteryState.batteryLevel == 100) {
-                    t = mContext.getString(R.string.quick_settings_battery_charged_label);
-                } else {
-                    t = batteryState.pluggedIn
-                        ? mContext.getString(R.string.quick_settings_battery_charging_label,
-                                batteryState.batteryLevel)
-                        : mContext.getString(R.string.status_bar_settings_battery_meter_format,
-                                batteryState.batteryLevel);
-                }
-                ((TextView)batteryTile.findViewById(R.id.text)).setText(t);
-                batteryTile.setContentDescription(
-                        mContext.getString(R.string.accessibility_quick_settings_battery, t));
-            }
-        });
-        parent.addView(batteryTile);
-
-        // Bluetooth
-        if (mModel.deviceSupportsBluetooth()
-                || DEBUG_GONE_TILES) {
-            final QuickSettingsBasicTile bluetoothTile
-                    = new QuickSettingsBasicTile(mContext);
-            bluetoothTile.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    startSettingsActivity(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS);
-                }
-            });
-            if (LONG_PRESS_TOGGLES) {
-                bluetoothTile.setOnLongClickListener(new View.OnLongClickListener() {
-                    @Override
-                    public boolean onLongClick(View v) {
-                        if (mBluetoothAdapter.isEnabled()) {
-                            mBluetoothAdapter.disable();
-                        } else {
-                            mBluetoothAdapter.enable();
-                        }
-                        bluetoothTile.setPressed(false);
-                        return true;
-                    }});
-            }
-            mModel.addBluetoothTile(bluetoothTile, new QuickSettingsModel.RefreshCallback() {
-                @Override
-                public void refreshView(QuickSettingsTileView unused, State state) {
-                    BluetoothState bluetoothState = (BluetoothState) state;
-                    bluetoothTile.setImageResource(state.iconId);
-
-                    /*
-                    Resources r = mContext.getResources();
-                    //TODO: Show connected bluetooth device label
-                    Set<BluetoothDevice> btDevices =
-                            mBluetoothController.getBondedBluetoothDevices();
-                    if (btDevices.size() == 1) {
-                        // Show the name of the bluetooth device you are connected to
-                        label = btDevices.iterator().next().getName();
-                    } else if (btDevices.size() > 1) {
-                        // Show a generic label about the number of bluetooth devices
-                        label = r.getString(R.string.quick_settings_bluetooth_multiple_devices_label,
-                                btDevices.size());
-                    }
-                    */
-                    bluetoothTile.setContentDescription(mContext.getString(
-                            R.string.accessibility_quick_settings_bluetooth,
-                            bluetoothState.stateContentDescription));
-                    bluetoothTile.setText(state.label);
-                }
-            });
-            parent.addView(bluetoothTile);
-        }
-
-        // Location
-        final QuickSettingsBasicTile locationTile
-                = new QuickSettingsBasicTile(mContext);
-        locationTile.setImageResource(R.drawable.ic_qs_location_on);
-        locationTile.setTextResource(R.string.quick_settings_location_label);
-        locationTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                startSettingsActivity(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
-            }
-        });
-        if (LONG_PRESS_TOGGLES) {
-            locationTile.setOnLongClickListener(new View.OnLongClickListener() {
-                @Override
-                public boolean onLongClick(View v) {
-                    boolean newLocationEnabledState = !mLocationController.isLocationEnabled();
-                    if (mLocationController.setLocationEnabled(newLocationEnabledState)
-                            && newLocationEnabledState) {
-                        // If we've successfully switched from location off to on, close the
-                        // notifications tray to show the network location provider consent dialog.
-                        Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-                        mContext.sendBroadcast(closeDialog);
-                    }
-                    return true; // Consume click
-                }} );
-        }
-        mModel.addLocationTile(locationTile, new QuickSettingsModel.RefreshCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView unused, State state) {
-                locationTile.setImageResource(state.iconId);
-                String locationState = mContext.getString(
-                        (state.enabled) ? R.string.accessibility_desc_on
-                                : R.string.accessibility_desc_off);
-                locationTile.setContentDescription(mContext.getString(
-                        R.string.accessibility_quick_settings_location,
-                        locationState));
-                locationTile.setText(state.label);
-            }
-        });
-        parent.addView(locationTile);
-
-        // Airplane Mode
-        final QuickSettingsBasicTile airplaneTile
-                = new QuickSettingsBasicTile(mContext);
-        mModel.addAirplaneModeTile(airplaneTile, new QuickSettingsModel.RefreshCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView unused, State state) {
-                airplaneTile.setImageResource(state.iconId);
-
-                String airplaneState = mContext.getString(
-                        (state.enabled) ? R.string.accessibility_desc_on
-                                : R.string.accessibility_desc_off);
-                airplaneTile.setContentDescription(
-                        mContext.getString(R.string.accessibility_quick_settings_airplane,
-                                airplaneState));
-                airplaneTile.setText(state.label);
-            }
-        });
-        parent.addView(airplaneTile);
-
-        // Zen Mode
-        final QuickSettingsBasicTile zenModeTile = new QuickSettingsBasicTile(mContext);
-        zenModeTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                showZenModeDialog();
-            }
-        });
-        mModel.addZenModeTile(zenModeTile, new QuickSettingsModel.RefreshCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView unused, State state) {
-                zenModeTile.setImageResource(state.iconId);
-                // TODO cut new assets
-                zenModeTile.getImageView().setAlpha(state.enabled ? 1 : .2f);
-                zenModeTile.getImageView().setScaleX(1.5f);
-                zenModeTile.getImageView().setScaleY(1.5f);
-                // for landscape version
-                zenModeTile.getTextView().setMaxLines(2);
-                zenModeTile.getTextView().setEllipsize(TruncateAt.END);
-                // TODO content description
-                zenModeTile.setText(state.label);
-            }
-        });
-        parent.addView(zenModeTile);
-    }
-
-    private void addTemporaryTiles(final ViewGroup parent, final LayoutInflater inflater) {
-        // Alarm tile
-        final QuickSettingsBasicTile alarmTile
-                = new QuickSettingsBasicTile(mContext);
-        alarmTile.setImageResource(R.drawable.ic_qs_alarm_on);
-        alarmTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                startSettingsActivity(AlarmClock.ACTION_SHOW_ALARMS);
-            }
-        });
-        mModel.addAlarmTile(alarmTile, new QuickSettingsModel.RefreshCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView unused, State alarmState) {
-                alarmTile.setText(alarmState.label);
-                alarmTile.setVisibility(alarmState.enabled ? View.VISIBLE : View.GONE);
-                alarmTile.setContentDescription(mContext.getString(
-                        R.string.accessibility_quick_settings_alarm, alarmState.label));
-            }
-        });
-        parent.addView(alarmTile);
-
-        // Remote Display
-        QuickSettingsBasicTile remoteDisplayTile
-                = new QuickSettingsBasicTile(mContext);
-        remoteDisplayTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                collapsePanels();
-
-                final Dialog[] dialog = new Dialog[1];
-                dialog[0] = MediaRouteDialogPresenter.createDialog(mContext,
-                        MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
-                        new View.OnClickListener() {
-                    @Override
-                    public void onClick(View v) {
-                        dialog[0].dismiss();
-                        startSettingsActivity(
-                                android.provider.Settings.ACTION_WIFI_DISPLAY_SETTINGS);
-                    }
-                });
-                dialog[0].getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
-                dialog[0].show();
-            }
-        });
-        mModel.addRemoteDisplayTile(remoteDisplayTile,
-                new QuickSettingsModel.BasicRefreshCallback(remoteDisplayTile)
-                        .setShowWhenEnabled(true));
-        parent.addView(remoteDisplayTile);
-
-        if (SHOW_IME_TILE || DEBUG_GONE_TILES) {
-            // IME
-            final QuickSettingsBasicTile imeTile
-                    = new QuickSettingsBasicTile(mContext);
-            imeTile.setImageResource(R.drawable.ic_qs_ime);
-            imeTile.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    try {
-                        collapsePanels();
-                        Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER);
-                        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
-                        pendingIntent.send();
-                    } catch (Exception e) {}
-                }
-            });
-            mModel.addImeTile(imeTile,
-                    new QuickSettingsModel.BasicRefreshCallback(imeTile)
-                            .setShowWhenEnabled(true));
-            parent.addView(imeTile);
-        }
-
-        // Bug reports
-        final QuickSettingsBasicTile bugreportTile
-                = new QuickSettingsBasicTile(mContext);
-        bugreportTile.setImageResource(com.android.internal.R.drawable.stat_sys_adb);
-        bugreportTile.setTextResource(com.android.internal.R.string.bugreport_title);
-        bugreportTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                collapsePanels();
-                showBugreportDialog();
-            }
-        });
-        mModel.addBugreportTile(bugreportTile, new QuickSettingsModel.RefreshCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView view, State state) {
-                view.setVisibility(state.enabled ? View.VISIBLE : View.GONE);
-            }
-        });
-        parent.addView(bugreportTile);
-        /*
-        QuickSettingsTileView mediaTile = (QuickSettingsTileView)
-                inflater.inflate(R.layout.quick_settings_tile, parent, false);
-        mediaTile.setContent(R.layout.quick_settings_tile_media, inflater);
-        parent.addView(mediaTile);
-        QuickSettingsTileView imeTile = (QuickSettingsTileView)
-                inflater.inflate(R.layout.quick_settings_tile, parent, false);
-        imeTile.setContent(R.layout.quick_settings_tile_ime, inflater);
-        imeTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                parent.removeViewAt(0);
-            }
-        });
-        parent.addView(imeTile);
-        */
-
-        // SSL CA Cert Warning.
-        final QuickSettingsBasicTile sslCaCertWarningTile =
-                new QuickSettingsBasicTile(mContext, null, R.layout.quick_settings_tile_monitoring);
-        sslCaCertWarningTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                collapsePanels();
-                startSettingsActivity(Settings.ACTION_MONITORING_CERT_INFO);
-            }
-        });
-
-        sslCaCertWarningTile.setImageResource(
-                com.android.internal.R.drawable.indicator_input_error);
-        sslCaCertWarningTile.setTextResource(R.string.ssl_ca_cert_warning);
-
-        mModel.addSslCaCertWarningTile(sslCaCertWarningTile,
-                new QuickSettingsModel.BasicRefreshCallback(sslCaCertWarningTile)
-                        .setShowWhenEnabled(true));
-        parent.addView(sslCaCertWarningTile);
-    }
-
-    void updateResources() {
-        Resources r = mContext.getResources();
-
-        // Update the model
-        mModel.updateResources();
-
-        // Update the User, Time, and Settings tiles spans, and reset everything else
-        int span = r.getInteger(R.integer.quick_settings_user_time_settings_tile_span);
-        for (QuickSettingsTileView v : mDynamicSpannedTiles) {
-            v.setColumnSpan(span);
-        }
-        ((QuickSettingsContainerView)mContainerView).updateResources();
-        mContainerView.requestLayout();
-    }
-
-
-    private void showBrightnessDialog() {
-        Intent intent = new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG);
-        mContext.sendBroadcast(intent);
-    }
-
-    private void showBugreportDialog() {
-        final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
-        builder.setPositiveButton(com.android.internal.R.string.report, new OnClickListener() {
-            @Override
-            public void onClick(DialogInterface dialog, int which) {
-                if (which == DialogInterface.BUTTON_POSITIVE) {
-                    // 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);
-                }
-            }
-        });
-        builder.setMessage(com.android.internal.R.string.bugreport_message);
-        builder.setTitle(com.android.internal.R.string.bugreport_title);
-        builder.setCancelable(true);
-        final Dialog dialog = builder.create();
-        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-        try {
-            WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
-        } catch (RemoteException e) {
-        }
-        dialog.show();
-    }
-
-    private void showZenModeDialog() {
-        final Dialog d = new Dialog(mContext);
-        d.requestWindowFeature(Window.FEATURE_NO_TITLE);
-        d.setCancelable(true);
-        d.setCanceledOnTouchOutside(true);
-        final ZenModeView v = new ZenModeView(mContext) {
-            @Override
-            protected void onConfigurationChanged(Configuration newConfig) {
-                super.onConfigurationChanged(newConfig);
-                WindowManager.LayoutParams lp = d.getWindow().getAttributes();
-                lp.width = mContext.getResources()
-                        .getDimensionPixelSize(R.dimen.zen_mode_dialog_width);
-                d.getWindow().setAttributes(lp);
-            }
-        };
-        v.setAutoActivate(true);
-        v.setAdapter(new ZenModeViewAdapter(mContext) {
-            @Override
-            public void configure() {
-                if (mStatusBarService != null) {
-                    mStatusBarService.startSettingsActivity(Settings.ACTION_ZEN_MODE_SETTINGS);
-                }
-                d.dismiss();
-            }
-            @Override
-            public void close() {
-                d.dismiss();
-            }
-        });
-        d.setContentView(v);
-        d.create();
-        d.getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
-        WindowManager.LayoutParams lp = d.getWindow().getAttributes();
-        lp.width = mContext.getResources().getDimensionPixelSize(R.dimen.zen_mode_dialog_width);
-        d.getWindow().setAttributes(lp);
-        d.show();
-    }
-
-    private void applyBluetoothStatus() {
-        mModel.onBluetoothStateChange(mBluetoothState);
-    }
-
-    private void applyLocationEnabledStatus() {
-        mModel.onLocationSettingsChanged(mLocationController.isLocationEnabled());
-    }
-
-    void reloadUserInfo() {
-        if (mUserInfoTask != null) {
-            mUserInfoTask.cancel(false);
-            mUserInfoTask = null;
-        }
-        if (mTilesSetUp) {
-            queryForUserInformation();
-            queryForSslCaCerts();
-        }
-    }
-
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            final String action = intent.getAction();
-            if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
-                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
-                        BluetoothAdapter.ERROR);
-                mBluetoothState.enabled = (state == BluetoothAdapter.STATE_ON);
-                applyBluetoothStatus();
-            } else if (BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-                int status = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
-                        BluetoothAdapter.STATE_DISCONNECTED);
-                mBluetoothState.connected = (status == BluetoothAdapter.STATE_CONNECTED);
-                applyBluetoothStatus();
-            } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                reloadUserInfo();
-            } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
-                if (mUseDefaultAvatar) {
-                    queryForUserInformation();
-                }
-            } else if (KeyChain.ACTION_STORAGE_CHANGED.equals(action)) {
-                queryForSslCaCerts();
-            }
-        }
-    };
-
-    private final BroadcastReceiver mProfileReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            final String action = intent.getAction();
-            if (ContactsContract.Intents.ACTION_PROFILE_CHANGED.equals(action) ||
-                    Intent.ACTION_USER_INFO_CHANGED.equals(action)) {
-                try {
-                    final int currentUser = ActivityManagerNative.getDefault().getCurrentUser().id;
-                    final int changedUser =
-                            intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId());
-                    if (changedUser == currentUser) {
-                        reloadUserInfo();
-                    }
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Couldn't get current user id for profile change", e);
-                }
-            }
-
-        }
-    };
-
-    private abstract static class NetworkActivityCallback
-            implements QuickSettingsModel.RefreshCallback {
-        private final long mDefaultDuration = new ValueAnimator().getDuration();
-        private final long mShortDuration = mDefaultDuration / 3;
-
-        public void setActivity(View view, ActivityState state) {
-            setVisibility(view.findViewById(R.id.activity_in), state.activityIn);
-            setVisibility(view.findViewById(R.id.activity_out), state.activityOut);
-        }
-
-        private void setVisibility(View view, boolean visible) {
-            final float newAlpha = visible ? 1 : 0;
-            if (view.getAlpha() != newAlpha) {
-                view.animate()
-                    .setDuration(visible ? mShortDuration : mDefaultDuration)
-                    .alpha(newAlpha)
-                    .start();
-            }
-        }
-    }
-
-    /**
-     * Quick Setting tile that represents a secure setting. This type of tile
-     * can toggle a URI within Settings.Secure on click and launch a Settings
-     * fragment on long-click.
-     */
-    public class SystemSettingTile extends QuickSettingsBasicTile {
-        private static final int TYPE_GLOBAL = 0;
-        private static final int TYPE_SECURE = 1;
-        private static final int TYPE_SYSTEM = 2;
-
-        private final QuickSettingsModel.BasicRefreshCallback mRefreshCallback;
-
-        private String mFragment;
-        private String mName;
-        private int mType;
-
-        public SystemSettingTile(Context context) {
-            super(context);
-
-            mRefreshCallback = new QuickSettingsModel.BasicRefreshCallback(this);
-            mRefreshCallback.setShowWhenEnabled(true);
-        }
-
-        @Override
-        public boolean performLongClick() {
-            if (mFragment != null) {
-                collapsePanels();
-
-                final Intent intent = new Intent();
-                intent.setComponent(new ComponentName(
-                        "com.android.settings", "com.android.settings." + mFragment));
-                startSettingsActivity(intent);
-                return true;
-            }
-            return false;
-        }
-
-        @Override
-        public boolean performClick() {
-            if (mName != null) {
-                collapsePanels();
-
-                final ContentResolver cr = mContext.getContentResolver();
-                switch (mType) {
-                    case TYPE_GLOBAL: {
-                        final boolean enable = Settings.Global.getInt(cr, mName, 0) == 0;
-                        Settings.Global.putInt(cr, mName, enable ? 1 : 0);
-                    } break;
-                    case TYPE_SECURE: {
-                        final boolean enable = Settings.Secure.getIntForUser(
-                                cr, mName, 0, UserHandle.USER_CURRENT) == 0;
-                        Settings.Secure.putIntForUser(
-                                cr, mName, enable ? 1 : 0, UserHandle.USER_CURRENT);
-                    } break;
-                    case TYPE_SYSTEM: {
-                        final boolean enable = Settings.System.getIntForUser(
-                                cr, mName, 0, UserHandle.USER_CURRENT) == 0;
-                        Settings.System.putIntForUser(
-                                cr, mName, enable ? 1 : 0, UserHandle.USER_CURRENT);
-                    } break;
-                }
-                return true;
-            }
-            return false;
-        }
-
-        /**
-         * Specifies the fragment within the com.android.settings package to
-         * launch when this tile is long-clicked.
-         *
-         * @param fragment a fragment name within the com.android.settings
-         *            package
-         */
-        public void setFragment(String fragment) {
-            mFragment = fragment;
-            setLongClickable(fragment != null);
-        }
-
-        /**
-         * Specifies the setting name and type to toggle when this tile is
-         * clicked.
-         *
-         * @param name a setting name
-         * @param type the type of setting, one of:
-         *            <ul>
-         *            <li>{@link #TYPE_GLOBAL}
-         *            <li>{@link #TYPE_SECURE}
-         *            <li>{@link #TYPE_SYSTEM}
-         *            </ul>
-         */
-        public void setUri(String name, int type) {
-            mName = name;
-            mType = type;
-            setClickable(mName != null);
-        }
-
-        /**
-         * @return the refresh callback for this tile
-         */
-        public QuickSettingsModel.BasicRefreshCallback getRefreshCallback() {
-            return mRefreshCallback;
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsBasicTile.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsBasicTile.java
deleted file mode 100644
index 099780c..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsBasicTile.java
+++ /dev/null
@@ -1,85 +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.statusbar.phone;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-
-class QuickSettingsBasicTile extends QuickSettingsTileView {
-    private final TextView mTextView;
-    private final ImageView mImageView;
-
-    public QuickSettingsBasicTile(Context context) {
-        this(context, null);
-    }
-
-    public QuickSettingsBasicTile(Context context, AttributeSet attrs) {
-        this(context, attrs, R.layout.quick_settings_tile_basic);
-    }
-
-    public QuickSettingsBasicTile(Context context, AttributeSet attrs, int layoutId) {
-        super(context, attrs);
-
-        setLayoutParams(new FrameLayout.LayoutParams(
-            FrameLayout.LayoutParams.MATCH_PARENT,
-            context.getResources().getDimensionPixelSize(R.dimen.quick_settings_cell_height)
-        ));
-        setBackgroundResource(R.drawable.qs_tile_background);
-        addView(LayoutInflater.from(context).inflate(layoutId, null),
-                new FrameLayout.LayoutParams(
-                        FrameLayout.LayoutParams.MATCH_PARENT,
-                        FrameLayout.LayoutParams.MATCH_PARENT));
-        mTextView = (TextView) findViewById(R.id.text);
-        mImageView = (ImageView) findViewById(R.id.image);
-    }
-
-    @Override
-    void setContent(int layoutId, LayoutInflater inflater) {
-        throw new RuntimeException("why?");
-    }
-
-    public ImageView getImageView() {
-        return mImageView;
-    }
-
-    public TextView getTextView() {
-        return mTextView;
-    }
-
-    public void setImageDrawable(Drawable drawable) {
-        mImageView.setImageDrawable(drawable);
-    }
-
-    public void setImageResource(int resId) {
-        mImageView.setImageResource(resId);
-    }
-
-    public void setText(CharSequence text) {
-        mTextView.setText(text);
-    }
-
-    public void setTextResource(int resId) {
-        mTextView.setText(resId);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java
deleted file mode 100644
index c44cb0c..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java
+++ /dev/null
@@ -1,295 +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.statusbar.phone;
-
-import android.animation.LayoutTransition;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Rect;
-import android.graphics.Typeface;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import com.android.systemui.R;
-
-/**
- *
- */
-class QuickSettingsContainerView extends FrameLayout {
-
-    private static boolean sShowScrim = true;
-
-    private final Context mContext;
-
-    // The number of columns in the QuickSettings grid
-    private int mNumColumns;
-
-    private boolean mKeyguardShowing;
-    private int mMaxRows;
-    private int mMaxRowsOnKeyguard;
-
-    // The gap between tiles in the QuickSettings grid
-    private float mCellGap;
-
-    private ScrimView mScrim;
-
-    public QuickSettingsContainerView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mContext = context;
-        updateResources();
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        if (sShowScrim) {
-            mScrim = new ScrimView(mContext);
-            addView(mScrim);
-        }
-        // TODO: Setup the layout transitions
-        LayoutTransition transitions = getLayoutTransition();
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        if (mScrim != null) {
-            sShowScrim = false;
-            removeView(mScrim);
-        }
-        return super.onTouchEvent(event);
-    }
-
-    void updateResources() {
-        Resources r = getContext().getResources();
-        mCellGap = r.getDimension(R.dimen.quick_settings_cell_gap);
-        mNumColumns = r.getInteger(R.integer.quick_settings_num_columns);
-        mMaxRows = r.getInteger(R.integer.quick_settings_max_rows);
-        mMaxRowsOnKeyguard = r.getInteger(R.integer.quick_settings_max_rows_keyguard);
-        requestLayout();
-    }
-
-    void setKeyguardShowing(boolean showing) {
-        mKeyguardShowing = showing;
-        requestLayout();
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        // Calculate the cell width dynamically
-        int width = MeasureSpec.getSize(widthMeasureSpec);
-        int height = MeasureSpec.getSize(heightMeasureSpec);
-        int availableWidth = (int) (width - getPaddingLeft() - getPaddingRight() -
-                (mNumColumns - 1) * mCellGap);
-        float cellWidth = (float) Math.ceil(((float) availableWidth) / mNumColumns);
-
-        // Update each of the children's widths accordingly to the cell width
-        final int N = getChildCount();
-        int cellHeight = 0;
-        int cursor = 0;
-        int maxRows = mKeyguardShowing ? mMaxRowsOnKeyguard : mMaxRows;
-
-        for (int i = 0; i < N; ++i) {
-            if (getChildAt(i).equals(mScrim)) {
-                continue;
-            }
-            // Update the child's width
-            QuickSettingsTileView v = (QuickSettingsTileView) getChildAt(i);
-            if (v.getVisibility() != View.GONE) {
-                int row = (int) (cursor / mNumColumns);
-                if (row >= maxRows) continue;
-
-                ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
-                int colSpan = v.getColumnSpan();
-                lp.width = (int) ((colSpan * cellWidth) + (colSpan - 1) * mCellGap);
-
-                // Measure the child
-                int newWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
-                int newHeightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
-                v.measure(newWidthSpec, newHeightSpec);
-
-                // Save the cell height
-                if (cellHeight <= 0) {
-                    cellHeight = v.getMeasuredHeight();
-                }
-                cursor += colSpan;
-            }
-        }
-
-        // Set the measured dimensions.  We always fill the tray width, but wrap to the height of
-        // all the tiles.
-        int numRows = (int) Math.ceil((float) cursor / mNumColumns);
-        int newHeight = (int) ((numRows * cellHeight) + ((numRows - 1) * mCellGap)) +
-                getPaddingTop() + getPaddingBottom();
-        setMeasuredDimension(width, newHeight);
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        if (mScrim != null) {
-            mScrim.bringToFront();
-        }
-        final int N = getChildCount();
-        final boolean isLayoutRtl = isLayoutRtl();
-        final int width = getWidth();
-
-        int x = getPaddingStart();
-        int y = getPaddingTop();
-        int cursor = 0;
-        int maxRows = mKeyguardShowing ? mMaxRowsOnKeyguard : mMaxRows;
-
-        for (int i = 0; i < N; ++i) {
-            if (getChildAt(i).equals(mScrim)) {
-                int w = right - left - getPaddingLeft() - getPaddingRight();
-                int h = bottom - top - getPaddingTop() - getPaddingBottom();
-                mScrim.measure(
-                        MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY),
-                        MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY));
-                mScrim.layout(getPaddingLeft(), getPaddingTop(), right, bottom);
-                continue;
-            }
-            QuickSettingsTileView child = (QuickSettingsTileView) getChildAt(i);
-            ViewGroup.LayoutParams lp = child.getLayoutParams();
-            if (child.getVisibility() != GONE) {
-                final int col = cursor % mNumColumns;
-                final int colSpan = child.getColumnSpan();
-
-                final int childWidth = lp.width;
-                final int childHeight = lp.height;
-
-                int row = (int) (cursor / mNumColumns);
-                if (row >= maxRows) continue;
-
-                // Push the item to the next row if it can't fit on this one
-                if ((col + colSpan) > mNumColumns) {
-                    x = getPaddingStart();
-                    y += childHeight + mCellGap;
-                    row++;
-                }
-
-                final int childLeft = (isLayoutRtl) ? width - x - childWidth : x;
-                final int childRight = childLeft + childWidth;
-
-                final int childTop = y;
-                final int childBottom = childTop + childHeight;
-
-                // Layout the container
-                child.layout(childLeft, childTop, childRight, childBottom);
-
-                // Offset the position by the cell gap or reset the position and cursor when we
-                // reach the end of the row
-                cursor += child.getColumnSpan();
-                if (cursor < (((row + 1) * mNumColumns))) {
-                    x += childWidth + mCellGap;
-                } else {
-                    x = getPaddingStart();
-                    y += childHeight + mCellGap;
-                }
-            }
-        }
-    }
-
-    private static final class ScrimView extends View {
-        private static final int SCRIM = 0x4f000000;
-        private static final int COLOR = 0xaf4285f4;
-
-        private final Paint mLinePaint;
-        private final int mStrokeWidth;
-        private final Rect mTmp = new Rect();
-        private final Paint mTextPaint;
-        private final int mTextSize;
-
-        public ScrimView(Context context) {
-            super(context);
-            setFocusable(false);
-            final Resources res = context.getResources();
-            mStrokeWidth = res.getDimensionPixelSize(R.dimen.quick_settings_tmp_scrim_stroke_width);
-            mTextSize = res.getDimensionPixelSize(R.dimen.quick_settings_tmp_scrim_text_size);
-
-            mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-            mLinePaint.setColor(COLOR);
-            mLinePaint.setStrokeWidth(mStrokeWidth);
-            mLinePaint.setStrokeJoin(Paint.Join.ROUND);
-            mLinePaint.setStrokeCap(Paint.Cap.ROUND);
-            mLinePaint.setStyle(Paint.Style.STROKE);
-
-            mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-            mTextPaint.setColor(COLOR);
-            mTextPaint.setTextSize(mTextSize);
-            mTextPaint.setTypeface(Typeface.create("sans-serif-condensed", Typeface.BOLD));
-        }
-
-        @Override
-        protected void onDraw(Canvas canvas) {
-            final int w = getMeasuredWidth();
-            final int h = getMeasuredHeight();
-            final int f = mStrokeWidth * 3 / 4;
-
-            canvas.drawColor(SCRIM);
-            canvas.drawPath(line(f, h / 2, w - f, h / 2), mLinePaint);
-            canvas.drawPath(line(w / 2, f, w / 2, h - f), mLinePaint);
-
-            final int s = mStrokeWidth;
-            mTextPaint.setTextAlign(Paint.Align.RIGHT);
-            canvas.drawText("FUTURE", w / 2 - s, h / 2 - s, mTextPaint);
-            mTextPaint.setTextAlign(Paint.Align.LEFT);
-            canvas.drawText("SITE OF", w / 2 + s, h / 2 - s , mTextPaint);
-            mTextPaint.setTextAlign(Paint.Align.RIGHT);
-            drawUnder(canvas, "QUANTUM", w / 2 - s, h / 2 + s);
-            mTextPaint.setTextAlign(Paint.Align.LEFT);
-            drawUnder(canvas, "SETTINGS", w / 2 + s, h / 2 + s);
-        }
-
-        private void drawUnder(Canvas c, String text, float x, float y) {
-            if (mTmp.isEmpty()) {
-                mTextPaint.getTextBounds(text, 0, text.length(), mTmp);
-            }
-            c.drawText(text, x, y + mTmp.height() * .85f, mTextPaint);
-        }
-
-        private Path line(float x1, float y1, float x2, float y2) {
-            final int a = mStrokeWidth * 2;
-            final Path p = new Path();
-            p.moveTo(x1, y1);
-            p.lineTo(x2, y2);
-            if (y1 == y2) {
-                p.moveTo(x1 + a, y1 + a);
-                p.lineTo(x1, y1);
-                p.lineTo(x1 + a, y1 - a);
-
-                p.moveTo(x2 - a, y2 - a);
-                p.lineTo(x2, y2);
-                p.lineTo(x2 - a, y2 + a);
-            }
-            if (x1 == x2) {
-                p.moveTo(x1 - a, y1 + a);
-                p.lineTo(x1, y1);
-                p.lineTo(x1 + a, y1 + a);
-
-                p.moveTo(x2 - a, y2 - a);
-                p.lineTo(x2, y2);
-                p.lineTo(x2 + a, y2 - a);
-            }
-            return p;
-        }
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
deleted file mode 100644
index e1ef83a..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ /dev/null
@@ -1,1126 +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.statusbar.phone;
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
-import android.content.BroadcastReceiver;
-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.database.ContentObserver;
-import android.graphics.drawable.Drawable;
-import android.media.MediaRouter;
-import android.media.MediaRouter.RouteInfo;
-import android.net.ConnectivityManager;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.view.inputmethod.InputMethodSubtype;
-
-import com.android.systemui.R;
-import com.android.systemui.settings.BrightnessController.BrightnessStateChangeCallback;
-import com.android.systemui.settings.CurrentUserTracker;
-import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
-import com.android.systemui.statusbar.policy.LocationController.LocationSettingsChangeCallback;
-import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
-import com.android.systemui.statusbar.policy.RotationLockController;
-import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
-
-import java.util.List;
-
-class QuickSettingsModel implements BluetoothStateChangeCallback,
-        NetworkSignalChangedCallback,
-        BatteryStateChangeCallback,
-        BrightnessStateChangeCallback,
-        RotationLockControllerCallback,
-        LocationSettingsChangeCallback {
-    // Sett InputMethoManagerService
-    private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
-
-    /** Represents the state of a given attribute. */
-    static class State {
-        int iconId;
-        String label;
-        boolean enabled = false;
-    }
-    static class BatteryState extends State {
-        int batteryLevel;
-        boolean pluggedIn;
-    }
-    static class ActivityState extends State {
-        boolean activityIn;
-        boolean activityOut;
-    }
-    static class RSSIState extends ActivityState {
-        int signalIconId;
-        String signalContentDescription;
-        int dataTypeIconId;
-        String dataContentDescription;
-    }
-    static class WifiState extends ActivityState {
-        String signalContentDescription;
-        boolean connected;
-    }
-    static class UserState extends State {
-        Drawable avatar;
-    }
-    static class BrightnessState extends State {
-        boolean autoBrightness;
-    }
-    static class InversionState extends State {
-        boolean toggled;
-        int type;
-    }
-    static class ContrastState extends State {
-        boolean toggled;
-        float contrast;
-        float brightness;
-    }
-    static class ColorSpaceState extends State {
-        boolean toggled;
-        int type;
-    }
-    public static class BluetoothState extends State {
-        boolean connected = false;
-        String stateContentDescription;
-    }
-    public static class RotationLockState extends State {
-        boolean visible = false;
-    }
-    public static class ZenModeState extends State {
-        int zenMode = Settings.Global.ZEN_MODE_OFF;
-    }
-
-    /** The callback to update a given tile. */
-    interface RefreshCallback {
-        public void refreshView(QuickSettingsTileView view, State state);
-    }
-
-    public static class BasicRefreshCallback implements RefreshCallback {
-        private final QuickSettingsBasicTile mView;
-        private boolean mShowWhenEnabled;
-
-        public BasicRefreshCallback(QuickSettingsBasicTile v) {
-            mView = v;
-        }
-        public void refreshView(QuickSettingsTileView ignored, State state) {
-            if (mShowWhenEnabled) {
-                mView.setVisibility(state.enabled ? View.VISIBLE : View.GONE);
-            }
-            if (state.iconId != 0) {
-                mView.setImageDrawable(null); // needed to flush any cached IDs
-                mView.setImageResource(state.iconId);
-            }
-            if (state.label != null) {
-                mView.setText(state.label);
-            }
-        }
-        public BasicRefreshCallback setShowWhenEnabled(boolean swe) {
-            mShowWhenEnabled = swe;
-            return this;
-        }
-    }
-
-    /** Broadcast receive to determine if there is an alarm set. */
-    private BroadcastReceiver mAlarmIntentReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(Intent.ACTION_ALARM_CHANGED)) {
-                onAlarmChanged(intent);
-                onNextAlarmChanged();
-            }
-        }
-    };
-
-    /** ContentObserver to determine the next alarm */
-    private class NextAlarmObserver extends ContentObserver {
-        public NextAlarmObserver(Handler handler) {
-            super(handler);
-        }
-
-        @Override public void onChange(boolean selfChange) {
-            onNextAlarmChanged();
-        }
-
-        public void startObserving() {
-            final ContentResolver cr = mContext.getContentResolver();
-            cr.registerContentObserver(
-                    Settings.System.getUriFor(Settings.System.NEXT_ALARM_FORMATTED), false, this,
-                    UserHandle.USER_ALL);
-        }
-    }
-
-    /** ContentObserver to watch adb */
-    private class BugreportObserver extends ContentObserver {
-        public BugreportObserver(Handler handler) {
-            super(handler);
-        }
-
-        @Override public void onChange(boolean selfChange) {
-            onBugreportChanged();
-        }
-
-        public void startObserving() {
-            final ContentResolver cr = mContext.getContentResolver();
-            cr.registerContentObserver(
-                    Settings.Global.getUriFor(Settings.Global.BUGREPORT_IN_POWER_MENU), false, this);
-        }
-    }
-
-    /** ContentObserver to watch brightness **/
-    private class BrightnessObserver extends ContentObserver {
-        public BrightnessObserver(Handler handler) {
-            super(handler);
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            onBrightnessLevelChanged();
-        }
-
-        public void startObserving() {
-            final ContentResolver cr = mContext.getContentResolver();
-            cr.unregisterContentObserver(this);
-            cr.registerContentObserver(
-                    Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE),
-                    false, this, mUserTracker.getCurrentUserId());
-            cr.registerContentObserver(
-                    Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS),
-                    false, this, mUserTracker.getCurrentUserId());
-        }
-    }
-
-    /** ContentObserver to watch display inversion */
-    private class DisplayInversionObserver extends ContentObserver {
-        public DisplayInversionObserver(Handler handler) {
-            super(handler);
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            onInversionChanged();
-        }
-
-        public void startObserving() {
-            final ContentResolver cr = mContext.getContentResolver();
-            cr.unregisterContentObserver(this);
-            cr.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED),
-                    false, this, mUserTracker.getCurrentUserId());
-            cr.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_QUICK_SETTING_ENABLED),
-                    false, this, mUserTracker.getCurrentUserId());
-            cr.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION),
-                    false, this, mUserTracker.getCurrentUserId());
-        }
-    }
-
-    /** ContentObserver to watch display contrast */
-    private class DisplayContrastObserver extends ContentObserver {
-        public DisplayContrastObserver(Handler handler) {
-            super(handler);
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            onContrastChanged();
-        }
-
-        public void startObserving() {
-            final ContentResolver cr = mContext.getContentResolver();
-            cr.unregisterContentObserver(this);
-            cr.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED),
-                    false, this, mUserTracker.getCurrentUserId());
-            cr.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_QUICK_SETTING_ENABLED),
-                    false, this, mUserTracker.getCurrentUserId());
-            cr.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST),
-                    false, this, mUserTracker.getCurrentUserId());
-            cr.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_BRIGHTNESS),
-                    false, this, mUserTracker.getCurrentUserId());
-        }
-    }
-
-    /** ContentObserver to watch display color space adjustment */
-    private class DisplayColorSpaceObserver extends ContentObserver {
-        public DisplayColorSpaceObserver(Handler handler) {
-            super(handler);
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            onColorSpaceChanged();
-        }
-
-        public void startObserving() {
-            final ContentResolver cr = mContext.getContentResolver();
-            cr.unregisterContentObserver(this);
-            cr.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
-                    false, this, mUserTracker.getCurrentUserId());
-            cr.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_QUICK_SETTING_ENABLED),
-                    false, this, mUserTracker.getCurrentUserId());
-            cr.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER),
-                    false, this, mUserTracker.getCurrentUserId());
-        }
-    }
-
-    /** ContentObserver to watch display color space adjustment */
-    private class ZenModeObserver extends ContentObserver {
-        public ZenModeObserver(Handler handler) {
-            super(handler);
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            onZenModeChanged();
-        }
-
-        public void startObserving() {
-            final ContentResolver cr = mContext.getContentResolver();
-            cr.unregisterContentObserver(this);
-            cr.registerContentObserver(
-                    Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false, this);
-        }
-    }
-
-    /** Callback for changes to remote display routes. */
-    private class RemoteDisplayRouteCallback extends MediaRouter.SimpleCallback {
-        @Override
-        public void onRouteAdded(MediaRouter router, RouteInfo route) {
-            updateRemoteDisplays();
-        }
-        @Override
-        public void onRouteChanged(MediaRouter router, RouteInfo route) {
-            updateRemoteDisplays();
-        }
-        @Override
-        public void onRouteRemoved(MediaRouter router, RouteInfo route) {
-            updateRemoteDisplays();
-        }
-        @Override
-        public void onRouteSelected(MediaRouter router, int type, RouteInfo route) {
-            updateRemoteDisplays();
-        }
-        @Override
-        public void onRouteUnselected(MediaRouter router, int type, RouteInfo route) {
-            updateRemoteDisplays();
-        }
-    }
-
-    private final Context mContext;
-    private final Handler mHandler;
-    private final CurrentUserTracker mUserTracker;
-    private final NextAlarmObserver mNextAlarmObserver;
-    private final BugreportObserver mBugreportObserver;
-    private final BrightnessObserver mBrightnessObserver;
-    private final DisplayInversionObserver mInversionObserver;
-    private final DisplayContrastObserver mContrastObserver;
-    private final DisplayColorSpaceObserver mColorSpaceObserver;
-    private final ZenModeObserver mZenModeObserver;
-
-    private final MediaRouter mMediaRouter;
-    private final RemoteDisplayRouteCallback mRemoteDisplayRouteCallback;
-
-    private final boolean mHasMobileData;
-
-    private QuickSettingsTileView mUserTile;
-    private RefreshCallback mUserCallback;
-    private UserState mUserState = new UserState();
-
-    private QuickSettingsTileView mTimeTile;
-    private RefreshCallback mTimeCallback;
-    private State mTimeState = new State();
-
-    private QuickSettingsTileView mAlarmTile;
-    private RefreshCallback mAlarmCallback;
-    private State mAlarmState = new State();
-
-    private QuickSettingsTileView mAirplaneModeTile;
-    private RefreshCallback mAirplaneModeCallback;
-    private State mAirplaneModeState = new State();
-
-    private QuickSettingsTileView mZenModeTile;
-    private RefreshCallback mZenModeCallback;
-    private ZenModeState mZenModeState = new ZenModeState();
-
-    private QuickSettingsTileView mWifiTile;
-    private RefreshCallback mWifiCallback;
-    private WifiState mWifiState = new WifiState();
-
-    private QuickSettingsTileView mRemoteDisplayTile;
-    private RefreshCallback mRemoteDisplayCallback;
-    private State mRemoteDisplayState = new State();
-
-    private QuickSettingsTileView mRSSITile;
-    private RefreshCallback mRSSICallback;
-    private RSSIState mRSSIState = new RSSIState();
-
-    private QuickSettingsTileView mBluetoothTile;
-    private RefreshCallback mBluetoothCallback;
-    private BluetoothState mBluetoothState = new BluetoothState();
-
-    private QuickSettingsTileView mBatteryTile;
-    private RefreshCallback mBatteryCallback;
-    private BatteryState mBatteryState = new BatteryState();
-
-    private QuickSettingsTileView mLocationTile;
-    private RefreshCallback mLocationCallback;
-    private State mLocationState = new State();
-
-    private QuickSettingsTileView mImeTile;
-    private RefreshCallback mImeCallback = null;
-    private State mImeState = new State();
-
-    private QuickSettingsTileView mRotationLockTile;
-    private RefreshCallback mRotationLockCallback;
-    private RotationLockState mRotationLockState = new RotationLockState();
-
-    private QuickSettingsTileView mBrightnessTile;
-    private RefreshCallback mBrightnessCallback;
-    private BrightnessState mBrightnessState = new BrightnessState();
-
-    private QuickSettingsTileView mInversionTile;
-    private RefreshCallback mInversionCallback;
-    private InversionState mInversionState = new InversionState();
-
-    private QuickSettingsTileView mContrastTile;
-    private RefreshCallback mContrastCallback;
-    private ContrastState mContrastState = new ContrastState();
-
-    private QuickSettingsTileView mColorSpaceTile;
-    private RefreshCallback mColorSpaceCallback;
-    private ColorSpaceState mColorSpaceState = new ColorSpaceState();
-
-    private QuickSettingsTileView mBugreportTile;
-    private RefreshCallback mBugreportCallback;
-    private State mBugreportState = new State();
-
-    private QuickSettingsTileView mSettingsTile;
-    private RefreshCallback mSettingsCallback;
-    private State mSettingsState = new State();
-
-    private QuickSettingsTileView mSslCaCertWarningTile;
-    private RefreshCallback mSslCaCertWarningCallback;
-    private State mSslCaCertWarningState = new State();
-
-    private RotationLockController mRotationLockController;
-    private int mRotationLockedLabel;
-
-    public QuickSettingsModel(Context context) {
-        mContext = context;
-        mHandler = new Handler();
-        mUserTracker = new CurrentUserTracker(mContext) {
-            @Override
-            public void onUserSwitched(int newUserId) {
-                mBrightnessObserver.startObserving();
-                mInversionObserver.startObserving();
-                mContrastObserver.startObserving();
-                mColorSpaceObserver.startObserving();
-                refreshRotationLockTile();
-                onBrightnessLevelChanged();
-                onInversionChanged();
-                onContrastChanged();
-                onColorSpaceChanged();
-                onNextAlarmChanged();
-                onBugreportChanged();
-                rebindMediaRouterAsCurrentUser();
-            }
-        };
-
-        mNextAlarmObserver = new NextAlarmObserver(mHandler);
-        mNextAlarmObserver.startObserving();
-        mBugreportObserver = new BugreportObserver(mHandler);
-        mBugreportObserver.startObserving();
-        mBrightnessObserver = new BrightnessObserver(mHandler);
-        mBrightnessObserver.startObserving();
-        mInversionObserver = new DisplayInversionObserver(mHandler);
-        mInversionObserver.startObserving();
-        mContrastObserver = new DisplayContrastObserver(mHandler);
-        mContrastObserver.startObserving();
-        mColorSpaceObserver = new DisplayColorSpaceObserver(mHandler);
-        mColorSpaceObserver.startObserving();
-        mZenModeObserver = new ZenModeObserver(mHandler);
-        mZenModeObserver.startObserving();
-
-        mMediaRouter = (MediaRouter)context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
-        rebindMediaRouterAsCurrentUser();
-
-        mRemoteDisplayRouteCallback = new RemoteDisplayRouteCallback();
-
-        ConnectivityManager cm = (ConnectivityManager)
-                context.getSystemService(Context.CONNECTIVITY_SERVICE);
-        mHasMobileData = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
-
-        IntentFilter alarmIntentFilter = new IntentFilter();
-        alarmIntentFilter.addAction(Intent.ACTION_ALARM_CHANGED);
-        context.registerReceiver(mAlarmIntentReceiver, alarmIntentFilter);
-    }
-
-    void updateResources() {
-        refreshSettingsTile();
-        refreshBatteryTile();
-        refreshBluetoothTile();
-        refreshBrightnessTile();
-        refreshRotationLockTile();
-        refreshRssiTile();
-        refreshLocationTile();
-    }
-
-    // Settings
-    void addSettingsTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mSettingsTile = view;
-        mSettingsCallback = cb;
-        refreshSettingsTile();
-    }
-    void refreshSettingsTile() {
-        Resources r = mContext.getResources();
-        mSettingsState.label = r.getString(R.string.quick_settings_settings_label);
-        mSettingsCallback.refreshView(mSettingsTile, mSettingsState);
-    }
-
-    // User
-    void addUserTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mUserTile = view;
-        mUserCallback = cb;
-        mUserCallback.refreshView(mUserTile, mUserState);
-    }
-    void setUserTileInfo(String name, Drawable avatar) {
-        mUserState.label = name;
-        mUserState.avatar = avatar;
-        mUserCallback.refreshView(mUserTile, mUserState);
-    }
-
-    // Time
-    void addTimeTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mTimeTile = view;
-        mTimeCallback = cb;
-        mTimeCallback.refreshView(view, mTimeState);
-    }
-
-    // Alarm
-    void addAlarmTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mAlarmTile = view;
-        mAlarmCallback = cb;
-        mAlarmCallback.refreshView(view, mAlarmState);
-    }
-    void onAlarmChanged(Intent intent) {
-        mAlarmState.enabled = intent.getBooleanExtra("alarmSet", false);
-        mAlarmCallback.refreshView(mAlarmTile, mAlarmState);
-    }
-    void onNextAlarmChanged() {
-        final String alarmText = Settings.System.getStringForUser(mContext.getContentResolver(),
-                Settings.System.NEXT_ALARM_FORMATTED,
-                UserHandle.USER_CURRENT);
-        mAlarmState.label = alarmText;
-
-        // When switching users, this is the only clue we're going to get about whether the
-        // alarm is actually set, since we won't get the ACTION_ALARM_CHANGED broadcast
-        mAlarmState.enabled = ! TextUtils.isEmpty(alarmText);
-
-        mAlarmCallback.refreshView(mAlarmTile, mAlarmState);
-    }
-
-    // Airplane Mode
-    void addAirplaneModeTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mAirplaneModeTile = view;
-        mAirplaneModeTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                if (mAirplaneModeState.enabled) {
-                    setAirplaneModeState(false);
-                } else {
-                    setAirplaneModeState(true);
-                }
-            }
-        });
-        mAirplaneModeCallback = cb;
-        int airplaneMode = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_ON, 0);
-        onAirplaneModeChanged(airplaneMode != 0);
-    }
-    private void setAirplaneModeState(boolean enabled) {
-        // TODO: Sets the view to be "awaiting" if not already awaiting
-
-        // Change the system setting
-        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON,
-                                enabled ? 1 : 0);
-
-        // Post the intent
-        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        intent.putExtra("state", enabled);
-        mContext.sendBroadcast(intent);
-    }
-    // NetworkSignalChanged callback
-    @Override
-    public void onAirplaneModeChanged(boolean enabled) {
-        // TODO: If view is in awaiting state, disable
-        Resources r = mContext.getResources();
-        mAirplaneModeState.enabled = enabled;
-        mAirplaneModeState.iconId = (enabled ?
-                R.drawable.ic_qs_airplane_on :
-                R.drawable.ic_qs_airplane_off);
-        mAirplaneModeState.label = r.getString(R.string.quick_settings_airplane_mode_label);
-        mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState);
-    }
-
-    // Zen Mode
-    void addZenModeTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mZenModeTile = view;
-        mZenModeCallback = cb;
-        onZenModeChanged();
-    }
-    private void onZenModeChanged() {
-        final int mode = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
-        mZenModeState.enabled = mode != Settings.Global.ZEN_MODE_OFF;
-        mZenModeState.zenMode = mode;
-        mZenModeState.label = mContext.getString(R.string.zen_mode_title);
-        mZenModeState.iconId = R.drawable.stat_sys_zen_limited;
-        mZenModeCallback.refreshView(mZenModeTile, mZenModeState);
-    }
-
-    // Wifi
-    void addWifiTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mWifiTile = view;
-        mWifiCallback = cb;
-        mWifiCallback.refreshView(mWifiTile, mWifiState);
-    }
-    // Remove the double quotes that the SSID may contain
-    public static String removeDoubleQuotes(String string) {
-        if (string == null) return null;
-        final int length = string.length();
-        if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
-            return string.substring(1, length - 1);
-        }
-        return string;
-    }
-    // Remove the period from the network name
-    public static String removeTrailingPeriod(String string) {
-        if (string == null) return null;
-        final int length = string.length();
-        if (string.endsWith(".")) {
-            return string.substring(0, length - 1);
-        }
-        return string;
-    }
-    // NetworkSignalChanged callback
-    @Override
-    public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
-            boolean activityIn, boolean activityOut,
-            String wifiSignalContentDescription, String enabledDesc) {
-        // TODO: If view is in awaiting state, disable
-        Resources r = mContext.getResources();
-
-        boolean wifiConnected = enabled && (wifiSignalIconId > 0) && (enabledDesc != null);
-        boolean wifiNotConnected = (wifiSignalIconId > 0) && (enabledDesc == null);
-        mWifiState.enabled = enabled;
-        mWifiState.connected = wifiConnected;
-        mWifiState.activityIn = enabled && activityIn;
-        mWifiState.activityOut = enabled && activityOut;
-        if (wifiConnected) {
-            mWifiState.iconId = wifiSignalIconId;
-            mWifiState.label = removeDoubleQuotes(enabledDesc);
-            mWifiState.signalContentDescription = wifiSignalContentDescription;
-        } else if (wifiNotConnected) {
-            mWifiState.iconId = R.drawable.ic_qs_wifi_0;
-            mWifiState.label = r.getString(R.string.quick_settings_wifi_label);
-            mWifiState.signalContentDescription = r.getString(R.string.accessibility_no_wifi);
-        } else {
-            mWifiState.iconId = R.drawable.ic_qs_wifi_no_network;
-            mWifiState.label = r.getString(R.string.quick_settings_wifi_off_label);
-            mWifiState.signalContentDescription = r.getString(R.string.accessibility_wifi_off);
-        }
-        mWifiCallback.refreshView(mWifiTile, mWifiState);
-    }
-
-    boolean deviceHasMobileData() {
-        return mHasMobileData;
-    }
-
-    // RSSI
-    void addRSSITile(QuickSettingsTileView view, RefreshCallback cb) {
-        mRSSITile = view;
-        mRSSICallback = cb;
-        mRSSICallback.refreshView(mRSSITile, mRSSIState);
-    }
-    // NetworkSignalChanged callback
-    @Override
-    public void onMobileDataSignalChanged(
-            boolean enabled, int mobileSignalIconId, String signalContentDescription,
-            int dataTypeIconId, boolean activityIn, boolean activityOut,
-            String dataContentDescription,String enabledDesc) {
-        if (deviceHasMobileData()) {
-            // TODO: If view is in awaiting state, disable
-            Resources r = mContext.getResources();
-            mRSSIState.signalIconId = enabled && (mobileSignalIconId > 0)
-                    ? mobileSignalIconId
-                    : R.drawable.ic_qs_signal_no_signal;
-            mRSSIState.signalContentDescription = enabled && (mobileSignalIconId > 0)
-                    ? signalContentDescription
-                    : r.getString(R.string.accessibility_no_signal);
-            mRSSIState.dataTypeIconId = enabled && (dataTypeIconId > 0) && !mWifiState.enabled
-                    ? dataTypeIconId
-                    : 0;
-            mRSSIState.activityIn = enabled && activityIn;
-            mRSSIState.activityOut = enabled && activityOut;
-            mRSSIState.dataContentDescription = enabled && (dataTypeIconId > 0) && !mWifiState.enabled
-                    ? dataContentDescription
-                    : r.getString(R.string.accessibility_no_data);
-            mRSSIState.label = enabled
-                    ? removeTrailingPeriod(enabledDesc)
-                    : r.getString(R.string.quick_settings_rssi_emergency_only);
-            mRSSICallback.refreshView(mRSSITile, mRSSIState);
-        }
-    }
-
-    void refreshRssiTile() {
-        if (mRSSITile != null) {
-            // We reinflate the original view due to potential styling changes that may have
-            // taken place due to a configuration change.
-            mRSSITile.reinflateContent(LayoutInflater.from(mContext));
-        }
-    }
-
-    // Bluetooth
-    void addBluetoothTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mBluetoothTile = view;
-        mBluetoothCallback = cb;
-
-        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        mBluetoothState.enabled = adapter.isEnabled();
-        mBluetoothState.connected =
-                (adapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED);
-        onBluetoothStateChange(mBluetoothState);
-    }
-    boolean deviceSupportsBluetooth() {
-        return (BluetoothAdapter.getDefaultAdapter() != null);
-    }
-    // BluetoothController callback
-    @Override
-    public void onBluetoothStateChange(boolean on) {
-        mBluetoothState.enabled = on;
-        onBluetoothStateChange(mBluetoothState);
-    }
-    public void onBluetoothStateChange(BluetoothState bluetoothStateIn) {
-        // TODO: If view is in awaiting state, disable
-        Resources r = mContext.getResources();
-        mBluetoothState.enabled = bluetoothStateIn.enabled;
-        mBluetoothState.connected = bluetoothStateIn.connected;
-        if (mBluetoothState.enabled) {
-            if (mBluetoothState.connected) {
-                mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_on;
-                mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_connected);
-            } else {
-                mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_not_connected;
-                mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_on);
-            }
-            mBluetoothState.label = r.getString(R.string.quick_settings_bluetooth_label);
-        } else {
-            mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_off;
-            mBluetoothState.label = r.getString(R.string.quick_settings_bluetooth_off_label);
-            mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_off);
-        }
-        mBluetoothCallback.refreshView(mBluetoothTile, mBluetoothState);
-    }
-    void refreshBluetoothTile() {
-        if (mBluetoothTile != null) {
-            onBluetoothStateChange(mBluetoothState.enabled);
-        }
-    }
-
-    // Battery
-    void addBatteryTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mBatteryTile = view;
-        mBatteryCallback = cb;
-        mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
-    }
-    // BatteryController callback
-    @Override
-    public void onBatteryLevelChanged(int level, boolean pluggedIn) {
-        mBatteryState.batteryLevel = level;
-        mBatteryState.pluggedIn = pluggedIn;
-        mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
-    }
-    void refreshBatteryTile() {
-        mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
-    }
-
-    // Location
-    void addLocationTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mLocationTile = view;
-        mLocationCallback = cb;
-        mLocationCallback.refreshView(mLocationTile, mLocationState);
-    }
-
-    void refreshLocationTile() {
-        if (mLocationTile != null) {
-            onLocationSettingsChanged(mLocationState.enabled);
-        }
-    }
-
-    @Override
-    public void onLocationSettingsChanged(boolean locationEnabled) {
-        int textResId = locationEnabled ? R.string.quick_settings_location_label
-                : R.string.quick_settings_location_off_label;
-        String label = mContext.getText(textResId).toString();
-        int locationIconId = locationEnabled
-                ? R.drawable.ic_qs_location_on : R.drawable.ic_qs_location_off;
-        mLocationState.enabled = locationEnabled;
-        mLocationState.label = label;
-        mLocationState.iconId = locationIconId;
-        mLocationCallback.refreshView(mLocationTile, mLocationState);
-    }
-
-    // Bug report
-    void addBugreportTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mBugreportTile = view;
-        mBugreportCallback = cb;
-        onBugreportChanged();
-    }
-    // SettingsObserver callback
-    public void onBugreportChanged() {
-        final ContentResolver cr = mContext.getContentResolver();
-        boolean enabled = false;
-        try {
-            enabled = (Settings.Global.getInt(cr, Settings.Global.BUGREPORT_IN_POWER_MENU) != 0);
-        } catch (SettingNotFoundException e) {
-        }
-
-        mBugreportState.enabled = enabled && mUserTracker.isCurrentUserOwner();
-        mBugreportCallback.refreshView(mBugreportTile, mBugreportState);
-    }
-
-    // Remote Display
-    void addRemoteDisplayTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mRemoteDisplayTile = view;
-        mRemoteDisplayCallback = cb;
-        mRemoteDisplayTile.setOnPrepareListener(new QuickSettingsTileView.OnPrepareListener() {
-            @Override
-            public void onPrepare() {
-                mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
-                        mRemoteDisplayRouteCallback,
-                        MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
-                updateRemoteDisplays();
-            }
-            @Override
-            public void onUnprepare() {
-                mMediaRouter.removeCallback(mRemoteDisplayRouteCallback);
-            }
-        });
-
-        updateRemoteDisplays();
-    }
-
-    private void rebindMediaRouterAsCurrentUser() {
-        mMediaRouter.rebindAsUser(mUserTracker.getCurrentUserId());
-    }
-
-    private void updateRemoteDisplays() {
-        MediaRouter.RouteInfo connectedRoute = mMediaRouter.getSelectedRoute(
-                MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
-        boolean enabled = connectedRoute != null
-                && connectedRoute.matchesTypes(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
-        boolean connecting;
-        if (enabled) {
-            connecting = connectedRoute.isConnecting();
-        } else {
-            connectedRoute = null;
-            connecting = false;
-            enabled = mMediaRouter.isRouteAvailable(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
-                    MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE);
-        }
-
-        mRemoteDisplayState.enabled = enabled;
-        if (connectedRoute != null) {
-            mRemoteDisplayState.label = connectedRoute.getName().toString();
-            mRemoteDisplayState.iconId = connecting ?
-                    R.drawable.ic_qs_cast_connecting : R.drawable.ic_qs_cast_connected;
-        } else {
-            mRemoteDisplayState.label = mContext.getString(
-                    R.string.quick_settings_remote_display_no_connection_label);
-            mRemoteDisplayState.iconId = R.drawable.ic_qs_cast_available;
-        }
-        mRemoteDisplayCallback.refreshView(mRemoteDisplayTile, mRemoteDisplayState);
-    }
-
-    // IME
-    void addImeTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mImeTile = view;
-        mImeCallback = cb;
-        mImeCallback.refreshView(mImeTile, mImeState);
-    }
-    /* This implementation is taken from
-       InputMethodManagerService.needsToShowImeSwitchOngoingNotification(). */
-    private boolean needsToShowImeSwitchOngoingNotification(InputMethodManager imm) {
-        List<InputMethodInfo> imis = imm.getEnabledInputMethodList();
-        final int N = imis.size();
-        if (N > 2) return true;
-        if (N < 1) return false;
-        int nonAuxCount = 0;
-        int auxCount = 0;
-        InputMethodSubtype nonAuxSubtype = null;
-        InputMethodSubtype auxSubtype = null;
-        for(int i = 0; i < N; ++i) {
-            final InputMethodInfo imi = imis.get(i);
-            final List<InputMethodSubtype> subtypes = imm.getEnabledInputMethodSubtypeList(imi,
-                    true);
-            final int subtypeCount = subtypes.size();
-            if (subtypeCount == 0) {
-                ++nonAuxCount;
-            } else {
-                for (int j = 0; j < subtypeCount; ++j) {
-                    final InputMethodSubtype subtype = subtypes.get(j);
-                    if (!subtype.isAuxiliary()) {
-                        ++nonAuxCount;
-                        nonAuxSubtype = subtype;
-                    } else {
-                        ++auxCount;
-                        auxSubtype = subtype;
-                    }
-                }
-            }
-        }
-        if (nonAuxCount > 1 || auxCount > 1) {
-            return true;
-        } else if (nonAuxCount == 1 && auxCount == 1) {
-            if (nonAuxSubtype != null && auxSubtype != null
-                    && (nonAuxSubtype.getLocale().equals(auxSubtype.getLocale())
-                            || auxSubtype.overridesImplicitlyEnabledSubtype()
-                            || nonAuxSubtype.overridesImplicitlyEnabledSubtype())
-                    && nonAuxSubtype.containsExtraValueKey(TAG_TRY_SUPPRESSING_IME_SWITCHER)) {
-                return false;
-            }
-            return true;
-        }
-        return false;
-    }
-    void onImeWindowStatusChanged(boolean visible) {
-        InputMethodManager imm =
-                (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
-        List<InputMethodInfo> imis = imm.getInputMethodList();
-
-        mImeState.enabled = (visible && needsToShowImeSwitchOngoingNotification(imm));
-        mImeState.label = getCurrentInputMethodName(mContext, mContext.getContentResolver(),
-                imm, imis, mContext.getPackageManager());
-        if (mImeCallback != null) {
-            mImeCallback.refreshView(mImeTile, mImeState);
-        }
-    }
-    private static String getCurrentInputMethodName(Context context, ContentResolver resolver,
-            InputMethodManager imm, List<InputMethodInfo> imis, PackageManager pm) {
-        if (resolver == null || imis == null) return null;
-        final String currentInputMethodId = Settings.Secure.getString(resolver,
-                Settings.Secure.DEFAULT_INPUT_METHOD);
-        if (TextUtils.isEmpty(currentInputMethodId)) return null;
-        for (InputMethodInfo imi : imis) {
-            if (currentInputMethodId.equals(imi.getId())) {
-                final InputMethodSubtype subtype = imm.getCurrentInputMethodSubtype();
-                final CharSequence summary = subtype != null
-                        ? subtype.getDisplayName(context, imi.getPackageName(),
-                                imi.getServiceInfo().applicationInfo)
-                        : context.getString(R.string.quick_settings_ime_label);
-                return summary.toString();
-            }
-        }
-        return null;
-    }
-
-    // Rotation lock
-    void addRotationLockTile(QuickSettingsTileView view,
-            RotationLockController rotationLockController,
-            RefreshCallback cb) {
-        mRotationLockTile = view;
-        mRotationLockCallback = cb;
-        mRotationLockController = rotationLockController;
-        final int lockOrientation = mRotationLockController.getRotationLockOrientation();
-        mRotationLockedLabel = lockOrientation == Configuration.ORIENTATION_PORTRAIT
-                    ? R.string.quick_settings_rotation_locked_portrait_label
-                    : lockOrientation == Configuration.ORIENTATION_LANDSCAPE
-                    ? R.string.quick_settings_rotation_locked_landscape_label
-                    : R.string.quick_settings_rotation_locked_label;
-        onRotationLockChanged();
-    }
-    void onRotationLockChanged() {
-        onRotationLockStateChanged(mRotationLockController.isRotationLocked(),
-                mRotationLockController.isRotationLockAffordanceVisible());
-    }
-    @Override
-    public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
-        mRotationLockState.visible = affordanceVisible;
-        mRotationLockState.enabled = rotationLocked;
-        mRotationLockState.iconId = rotationLocked
-                ? R.drawable.ic_qs_rotation_locked
-                : R.drawable.ic_qs_auto_rotate;
-        mRotationLockState.label = rotationLocked
-                ? mContext.getString(mRotationLockedLabel)
-                : mContext.getString(R.string.quick_settings_rotation_unlocked_label);
-        mRotationLockCallback.refreshView(mRotationLockTile, mRotationLockState);
-    }
-    void refreshRotationLockTile() {
-        if (mRotationLockTile != null) {
-            onRotationLockChanged();
-        }
-    }
-
-    // Brightness
-    void addBrightnessTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mBrightnessTile = view;
-        mBrightnessCallback = cb;
-        onBrightnessLevelChanged();
-    }
-    @Override
-    public void onBrightnessLevelChanged() {
-        Resources r = mContext.getResources();
-        int mode = Settings.System.getIntForUser(mContext.getContentResolver(),
-                Settings.System.SCREEN_BRIGHTNESS_MODE,
-                Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
-                mUserTracker.getCurrentUserId());
-        mBrightnessState.autoBrightness =
-                (mode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
-        mBrightnessState.iconId = mBrightnessState.autoBrightness
-                ? R.drawable.ic_qs_brightness_auto_on
-                : R.drawable.ic_qs_brightness_auto_off;
-        mBrightnessState.label = r.getString(R.string.quick_settings_brightness_label);
-        mBrightnessCallback.refreshView(mBrightnessTile, mBrightnessState);
-    }
-    void refreshBrightnessTile() {
-        onBrightnessLevelChanged();
-    }
-
-    // Color inversion
-    void addInversionTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mInversionTile = view;
-        mInversionCallback = cb;
-        onInversionChanged();
-    }
-    public void onInversionChanged() {
-        final Resources res = mContext.getResources();
-        final ContentResolver cr = mContext.getContentResolver();
-        final int currentUserId = mUserTracker.getCurrentUserId();
-        final boolean quickSettingEnabled = Settings.Secure.getIntForUser(
-                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_QUICK_SETTING_ENABLED, 0,
-                currentUserId) == 1;
-        final boolean enabled = Settings.Secure.getIntForUser(
-                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, currentUserId) == 1;
-        final int type = Settings.Secure.getIntForUser(
-                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION, 0, currentUserId);
-        mInversionState.enabled = quickSettingEnabled;
-        mInversionState.toggled = enabled;
-        mInversionState.type = type;
-        // TODO: Add real icon assets.
-        mInversionState.iconId = enabled ? R.drawable.ic_qs_inversion_on
-                : R.drawable.ic_qs_inversion_off;
-        mInversionState.label = res.getString(R.string.quick_settings_inversion_label);
-        mInversionCallback.refreshView(mInversionTile, mInversionState);
-    }
-
-    // Contrast enhancement
-    void addContrastTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mContrastTile = view;
-        mContrastCallback = cb;
-        onContrastChanged();
-    }
-    public void onContrastChanged() {
-        final Resources res = mContext.getResources();
-        final ContentResolver cr = mContext.getContentResolver();
-        final int currentUserId = mUserTracker.getCurrentUserId();
-        final boolean quickSettingEnabled = Settings.Secure.getIntForUser(
-                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_QUICK_SETTING_ENABLED, 0,
-                currentUserId) == 1;
-        final boolean enabled = Settings.Secure.getIntForUser(
-                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED, 0, currentUserId) == 1;
-        final float contrast = Settings.Secure.getFloatForUser(
-                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST, 1, currentUserId);
-        final float brightness = Settings.Secure.getFloatForUser(
-                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_BRIGHTNESS, 0, currentUserId);
-        mContrastState.enabled = quickSettingEnabled;
-        mContrastState.toggled = enabled;
-        mContrastState.contrast = contrast;
-        mContrastState.brightness = brightness;
-        // TODO: Add real icon assets.
-        mContrastState.iconId = enabled ? R.drawable.ic_qs_contrast_on
-                : R.drawable.ic_qs_contrast_off;
-        mContrastState.label = res.getString(R.string.quick_settings_contrast_label);
-        mContrastCallback.refreshView(mContrastTile, mContrastState);
-    }
-
-    // Color space adjustment
-    void addColorSpaceTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mColorSpaceTile = view;
-        mColorSpaceCallback = cb;
-        onColorSpaceChanged();
-    }
-    public void onColorSpaceChanged() {
-        final Resources res = mContext.getResources();
-        final ContentResolver cr = mContext.getContentResolver();
-        final int currentUserId = mUserTracker.getCurrentUserId();
-        final boolean quickSettingEnabled = Settings.Secure.getIntForUser(
-                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_QUICK_SETTING_ENABLED, 0,
-                currentUserId) == 1;
-        final boolean enabled = Settings.Secure.getIntForUser(cr,
-                Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, currentUserId) == 1;
-        final int type = Settings.Secure.getIntForUser(
-                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, 0, currentUserId);
-        mColorSpaceState.enabled = quickSettingEnabled;
-        mColorSpaceState.toggled = enabled;
-        mColorSpaceState.type = type;
-        // TODO: Add real icon assets.
-        mColorSpaceState.iconId = enabled ? R.drawable.ic_qs_color_space_on
-                : R.drawable.ic_qs_color_space_off;
-        mColorSpaceState.label = res.getString(R.string.quick_settings_color_space_label);
-        mColorSpaceCallback.refreshView(mColorSpaceTile, mColorSpaceState);
-    }
-
-    // SSL CA Cert warning.
-    public void addSslCaCertWarningTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mSslCaCertWarningTile = view;
-        mSslCaCertWarningCallback = cb;
-        // Set a sane default while we wait for the AsyncTask to finish (no cert).
-        setSslCaCertWarningTileInfo(false, true);
-    }
-    public void setSslCaCertWarningTileInfo(boolean hasCert, boolean isManaged) {
-        Resources r = mContext.getResources();
-        mSslCaCertWarningState.enabled = hasCert;
-        if (isManaged) {
-            mSslCaCertWarningState.iconId = R.drawable.ic_qs_certificate_info;
-        } else {
-            mSslCaCertWarningState.iconId = android.R.drawable.stat_notify_error;
-        }
-        mSslCaCertWarningState.label = r.getString(R.string.ssl_ca_cert_warning);
-        mSslCaCertWarningCallback.refreshView(mSslCaCertWarningTile, mSslCaCertWarningState);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsScrollView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsScrollView.java
deleted file mode 100644
index 175805a..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsScrollView.java
+++ /dev/null
@@ -1,59 +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.statusbar.phone;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.ScrollView;
-
-public class QuickSettingsScrollView extends ScrollView {
-
-    public QuickSettingsScrollView(Context context) {
-        super(context);
-    }
-
-    public QuickSettingsScrollView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public QuickSettingsScrollView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    // Y U NO PROTECTED
-    private int getScrollRange() {
-        int scrollRange = 0;
-        if (getChildCount() > 0) {
-            View child = getChildAt(0);
-            scrollRange = Math.max(0,
-                    child.getHeight() - (getHeight() - getPaddingBottom() - getPaddingTop()));
-        }
-        return scrollRange;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        final int range = getScrollRange();
-        if (range == 0) {
-            return false;
-        }
-
-        return super.onTouchEvent(ev);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
deleted file mode 100644
index ad18294..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
+++ /dev/null
@@ -1,149 +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.statusbar.phone;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewParent;
-import android.widget.FrameLayout;
-
-/**
- *
- */
-class QuickSettingsTileView extends FrameLayout {
-    private static final String TAG = "QuickSettingsTileView";
-
-    private int mContentLayoutId;
-    private int mColSpan;
-    private boolean mPrepared;
-    private OnPrepareListener mOnPrepareListener;
-
-    public QuickSettingsTileView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-
-        mContentLayoutId = -1;
-        mColSpan = 1;
-    }
-
-    void setColumnSpan(int span) {
-        mColSpan = span;
-    }
-
-    int getColumnSpan() {
-        return mColSpan;
-    }
-
-    void setContent(int layoutId, LayoutInflater inflater) {
-        mContentLayoutId = layoutId;
-        inflater.inflate(layoutId, this);
-    }
-
-    void reinflateContent(LayoutInflater inflater) {
-        if (mContentLayoutId != -1) {
-            removeAllViews();
-            setContent(mContentLayoutId, inflater);
-        } else {
-            Log.e(TAG, "Not reinflating content: No layoutId set");
-        }
-    }
-
-    @Override
-    public void setVisibility(int vis) {
-        if (QuickSettings.DEBUG_GONE_TILES) {
-            if (vis == View.GONE) {
-                vis = View.VISIBLE;
-                setAlpha(0.25f);
-                setEnabled(false);
-            } else {
-                setAlpha(1f);
-                setEnabled(true);
-            }
-        }
-        super.setVisibility(vis);
-    }
-
-    public void setOnPrepareListener(OnPrepareListener listener) {
-        if (mOnPrepareListener != listener) {
-            mOnPrepareListener = listener;
-            mPrepared = false;
-            post(new Runnable() {
-                @Override
-                public void run() {
-                    updatePreparedState();
-                }
-            });
-        }
-    }
-
-    @Override
-    protected void onVisibilityChanged(View changedView, int visibility) {
-        super.onVisibilityChanged(changedView, visibility);
-        updatePreparedState();
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        updatePreparedState();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        updatePreparedState();
-    }
-
-    private void updatePreparedState() {
-        if (mOnPrepareListener != null) {
-            if (isParentVisible()) {
-                if (!mPrepared) {
-                    mPrepared = true;
-                    mOnPrepareListener.onPrepare();
-                }
-            } else if (mPrepared) {
-                mPrepared = false;
-                mOnPrepareListener.onUnprepare();
-            }
-        }
-    }
-
-    private boolean isParentVisible() {
-        if (!isAttachedToWindow()) {
-            return false;
-        }
-        for (ViewParent current = getParent(); current instanceof View;
-                current = current.getParent()) {
-            View view = (View)current;
-            if (view.getVisibility() != VISIBLE) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Called when the view's parent becomes visible or invisible to provide
-     * an opportunity for the client to provide new content.
-     */
-    public interface OnPrepareListener {
-        void onPrepare();
-        void onUnprepare();
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
new file mode 100644
index 0000000..2305445
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.Intent;
+import android.graphics.Outline;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSPanel;
+import com.android.systemui.settings.BrightnessController;
+import com.android.systemui.settings.ToggleSlider;
+import com.android.systemui.statusbar.policy.UserInfoController;
+
+/**
+ * The view to manage the header area in the expanded status bar.
+ */
+public class StatusBarHeaderView extends RelativeLayout implements View.OnClickListener {
+
+    private boolean mExpanded;
+    private boolean mKeyguardShowing;
+
+    private View mBackground;
+    private ViewGroup mSystemIconsContainer;
+    private View mDateTime;
+    private View mKeyguardCarrierText;
+    private MultiUserSwitch mMultiUserSwitch;
+    private View mDate;
+    private View mStatusIcons;
+    private View mSignalCluster;
+    private View mSettingsButton;
+    private View mBrightnessContainer;
+
+    private int mCollapsedHeight;
+    private int mExpandedHeight;
+    private int mKeyguardHeight;
+
+    private int mKeyguardWidth = ViewGroup.LayoutParams.MATCH_PARENT;
+    private int mNormalWidth;
+
+    private ActivityStarter mActivityStarter;
+    private BrightnessController mBrightnessController;
+    private QSPanel mQSPanel;
+
+    private final Rect mClipBounds = new Rect();
+    private final Outline mOutline = new Outline();
+
+    public StatusBarHeaderView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mBackground = findViewById(R.id.background);
+        mSystemIconsContainer = (ViewGroup) findViewById(R.id.system_icons_container);
+        mDateTime = findViewById(R.id.datetime);
+        mKeyguardCarrierText = findViewById(R.id.keyguard_carrier_text);
+        mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch);
+        mDate = findViewById(R.id.date);
+        mSettingsButton = findViewById(R.id.settings_button);
+        mSettingsButton.setOnClickListener(this);
+        mBrightnessContainer = findViewById(R.id.brightness_container);
+        mBrightnessController = new BrightnessController(getContext(),
+                (ImageView) findViewById(R.id.brightness_icon),
+                (ToggleSlider) findViewById(R.id.brightness_slider));
+        loadDimens();
+    }
+
+    private void loadDimens() {
+        mCollapsedHeight = getResources().getDimensionPixelSize(R.dimen.status_bar_header_height);
+        mExpandedHeight = getResources().getDimensionPixelSize(
+                R.dimen.status_bar_header_height_expanded);
+        mKeyguardHeight = getResources().getDimensionPixelSize(
+                R.dimen.status_bar_header_height_keyguard);
+        mNormalWidth = getLayoutParams().width;
+    }
+
+    public void setActivityStarter(ActivityStarter activityStarter) {
+        mActivityStarter = activityStarter;
+    }
+
+    public int getCollapsedHeight() {
+        return mKeyguardShowing ? mKeyguardHeight : mCollapsedHeight;
+    }
+
+    public int getExpandedHeight() {
+        return mExpandedHeight;
+    }
+
+    public void setExpanded(boolean expanded) {
+        boolean changed = expanded != mExpanded;
+        mExpanded = expanded;
+        if (changed) {
+            updateHeights();
+            updateVisibilities();
+            updateSystemIconsLayoutParams();
+            updateBrightnessControllerState();
+            if (mQSPanel != null) {
+                mQSPanel.setExpanded(expanded);
+            }
+        }
+    }
+
+    private void updateHeights() {
+        boolean onKeyguardAndCollapsed = mKeyguardShowing && !mExpanded;
+        int height;
+        if (mExpanded) {
+            height = mExpandedHeight;
+        } else if (onKeyguardAndCollapsed) {
+            height = mKeyguardHeight;
+        } else {
+            height = mCollapsedHeight;
+        }
+        ViewGroup.LayoutParams lp = getLayoutParams();
+        if (lp.height != height) {
+            lp.height = height;
+            setLayoutParams(lp);
+        }
+        int systemIconsContainerHeight = onKeyguardAndCollapsed ? mKeyguardHeight : mCollapsedHeight;
+        lp = mSystemIconsContainer.getLayoutParams();
+        if (lp.height != systemIconsContainerHeight) {
+            lp.height = systemIconsContainerHeight;
+            mSystemIconsContainer.setLayoutParams(lp);
+        }
+        lp = mMultiUserSwitch.getLayoutParams();
+        if (lp.height != systemIconsContainerHeight) {
+            lp.height = systemIconsContainerHeight;
+            mMultiUserSwitch.setLayoutParams(lp);
+        }
+    }
+
+    private void updateWidth() {
+        int width = mKeyguardShowing ? mKeyguardWidth : mNormalWidth;
+        ViewGroup.LayoutParams lp = getLayoutParams();
+        if (width != lp.width) {
+            lp.width = width;
+            setLayoutParams(lp);
+        }
+    }
+
+    private void updateVisibilities() {
+        boolean onKeyguardAndCollapsed = mKeyguardShowing && !mExpanded;
+        mBackground.setVisibility(onKeyguardAndCollapsed ? View.INVISIBLE : View.VISIBLE);
+        mDateTime.setVisibility(onKeyguardAndCollapsed ? View.INVISIBLE : View.VISIBLE);
+        mKeyguardCarrierText.setVisibility(onKeyguardAndCollapsed ? View.VISIBLE : View.GONE);
+        mDate.setVisibility(mExpanded ? View.VISIBLE : View.GONE);
+        mSettingsButton.setVisibility(mExpanded ? View.VISIBLE : View.GONE);
+        mBrightnessContainer.setVisibility(mExpanded ? View.VISIBLE : View.GONE);
+        if (mStatusIcons != null) {
+            mStatusIcons.setVisibility(!mExpanded ? View.VISIBLE : View.GONE);
+        }
+        if (mSignalCluster != null) {
+            mSignalCluster.setVisibility(!mExpanded ? View.VISIBLE : View.GONE);
+        }
+    }
+
+    private void updateSystemIconsLayoutParams() {
+        RelativeLayout.LayoutParams lp = (LayoutParams) mSystemIconsContainer.getLayoutParams();
+        lp.addRule(RelativeLayout.START_OF, mExpanded
+                ? mSettingsButton.getId()
+                : mMultiUserSwitch.getId());
+    }
+
+    private void updateBrightnessControllerState() {
+        if (mExpanded) {
+            mBrightnessController.registerCallbacks();
+        } else {
+            mBrightnessController.unregisterCallbacks();
+        }
+    }
+
+    public void setExpansion(float height) {
+        if (height < mCollapsedHeight) {
+            height = mCollapsedHeight;
+        }
+        if (height > mExpandedHeight) {
+            height = mExpandedHeight;
+        }
+        if (mExpanded) {
+            mBackground.setTranslationY(-(mExpandedHeight - height));
+        } else {
+            mBackground.setTranslationY(0);
+        }
+        setClipping(height);
+    }
+
+    private void setClipping(float height) {
+        mClipBounds.set(getPaddingLeft(), 0, getWidth() - getPaddingRight(), (int) height);
+        setClipBounds(mClipBounds);
+        mOutline.setRect(mClipBounds);
+        setOutline(mOutline);
+    }
+
+    public View getBackgroundView() {
+        return mBackground;
+    }
+
+    public void attachSystemIcons(LinearLayout systemIcons) {
+        mSystemIconsContainer.addView(systemIcons);
+        mStatusIcons = systemIcons.findViewById(R.id.statusIcons);
+        mSignalCluster = systemIcons.findViewById(R.id.signal_cluster);
+    }
+
+    public void onSystemIconsDetached() {
+        if (mStatusIcons != null) {
+            mStatusIcons.setVisibility(View.VISIBLE);
+        }
+        if (mSignalCluster != null) {
+            mSignalCluster.setVisibility(View.VISIBLE);
+        }
+        mStatusIcons = null;
+        mSignalCluster = null;
+    }
+
+    public void setKeyguardShowing(boolean keyguardShowing) {
+        mKeyguardShowing = keyguardShowing;
+        if (keyguardShowing) {
+            setZ(0);
+        } else {
+            setTranslationZ(0);
+        }
+        updateHeights();
+        updateWidth();
+        updateVisibilities();
+    }
+
+    public void setUserInfoController(UserInfoController userInfoController) {
+        mMultiUserSwitch.setUserInfoController(userInfoController);
+    }
+
+    public void setOverlayParent(ViewGroup parent) {
+        mMultiUserSwitch.setOverlayParent(parent);
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v == mSettingsButton) {
+            startSettingsActivity();
+        }
+    }
+
+    private void startSettingsActivity() {
+        mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS));
+    }
+
+    public void setQSPanel(QSPanel qsp) {
+        mQSPanel = qsp;
+    }
+}
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 c2595cf..77b760e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -18,22 +18,16 @@
 
 import android.content.Context;
 import android.os.Bundle;
-import android.os.IBinder;
 import android.os.RemoteException;
-import android.util.Log;
 import android.util.Slog;
-import android.view.LayoutInflater;
+import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
 
 import com.android.internal.policy.IKeyguardShowCallback;
 import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardHostView;
-import com.android.keyguard.KeyguardSimpleHostView;
-import com.android.keyguard.R;
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.keyguard.KeyguardViewMediator;
 
 /**
  * Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back
@@ -58,6 +52,12 @@
     private boolean mShowing;
     private boolean mOccluded;
 
+    private boolean mFirstUpdate = true;
+    private boolean mLastShowing;
+    private boolean mLastOccluded;
+    private boolean mLastBouncerShowing;
+    private boolean mLastBouncerDismissible;
+
     public StatusBarKeyguardViewManager(Context context, ViewMediatorCallback callback,
             LockPatternUtils lockPatternUtils) {
         mContext = context;
@@ -81,8 +81,7 @@
     public void show(Bundle options) {
         mShowing = true;
         mStatusBarWindowManager.setKeyguardShowing(true);
-        showBouncerOrKeyguard();
-        updateBackButtonState();
+        reset();
     }
 
     /**
@@ -102,17 +101,26 @@
         }
     }
 
-    public void showBouncer() {
-        mBouncer.show();
-        updateBackButtonState();
+    private void showBouncer() {
+        if (!mOccluded) {
+            mBouncer.show();
+        }
+        updateStates();
     }
 
     /**
      * Reset the state of the view.
      */
     public void reset() {
-        showBouncerOrKeyguard();
-        updateBackButtonState();
+        if (mShowing) {
+            if (mOccluded) {
+                mPhoneStatusBar.hideKeyguard();
+                mBouncer.hide();
+            } else {
+                showBouncerOrKeyguard();
+            }
+            updateStates();
+        }
     }
 
     public void onScreenTurnedOff() {
@@ -155,7 +163,7 @@
     public void setOccluded(boolean occluded) {
         mOccluded = occluded;
         mStatusBarWindowManager.setKeyguardOccluded(occluded);
-        updateBackButtonState();
+        reset();
     }
 
     /**
@@ -167,7 +175,7 @@
         mStatusBarWindowManager.setKeyguardShowing(false);
         mBouncer.hide();
         mViewMediatorCallback.keyguardGone();
-        updateBackButtonState();
+        updateStates();
     }
 
     /**
@@ -199,28 +207,63 @@
         if (mBouncer.isShowing()) {
             mBouncer.hide();
             mPhoneStatusBar.showKeyguard();
-            updateBackButtonState();
+            updateStates();
             return true;
         }
         return false;
     }
 
-    private void updateBackButtonState() {
+    private void updateStates() {
         int vis = mContainer.getSystemUiVisibility();
-        boolean bouncerDismissable = mBouncer.isShowing() && !mBouncer.needsFullscreenBouncer();
-        if (bouncerDismissable || !mShowing) {
-            mContainer.setSystemUiVisibility(vis & ~View.STATUS_BAR_DISABLE_BACK);
-        } else {
-            mContainer.setSystemUiVisibility(vis | View.STATUS_BAR_DISABLE_BACK);
+        boolean showing = mShowing;
+        boolean occluded = mOccluded;
+        boolean bouncerShowing = mBouncer.isShowing();
+        boolean bouncerDismissible = bouncerShowing && !mBouncer.needsFullscreenBouncer();
+
+        if ((bouncerDismissible || !showing) != (mLastBouncerDismissible || !mLastShowing)
+                || mFirstUpdate) {
+            if (bouncerDismissible || !showing) {
+                mContainer.setSystemUiVisibility(vis & ~View.STATUS_BAR_DISABLE_BACK);
+            } else {
+                mContainer.setSystemUiVisibility(vis | View.STATUS_BAR_DISABLE_BACK);
+            }
         }
-        if (!(mShowing && !mOccluded) || mBouncer.isShowing()) {
-            mPhoneStatusBar.getNavigationBarView().setVisibility(View.VISIBLE);
-        } else {
-            mPhoneStatusBar.getNavigationBarView().setVisibility(View.GONE);
+        if ((!(showing && !occluded) || bouncerShowing)
+                != (!(mLastShowing && !mLastOccluded) || mLastBouncerShowing) || mFirstUpdate) {
+            if (mPhoneStatusBar.getNavigationBarView() != null) {
+                if (!(showing && !occluded) || bouncerShowing) {
+                    mPhoneStatusBar.getNavigationBarView().setVisibility(View.VISIBLE);
+                } else {
+                    mPhoneStatusBar.getNavigationBarView().setVisibility(View.GONE);
+                }
+            }
         }
+
+        if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
+            mStatusBarWindowManager.setBouncerShowing(bouncerShowing);
+            mPhoneStatusBar.setBouncerShowing(bouncerShowing);
+        }
+
+        KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
+        if ((showing && !occluded) != (mLastShowing && !mLastOccluded) || mFirstUpdate) {
+            updateMonitor.sendKeyguardVisibilityChanged(showing && !occluded);
+        }
+        if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
+            updateMonitor.sendKeyguardBouncerChanged(bouncerShowing);
+        }
+
+        mFirstUpdate = false;
+        mLastShowing = showing;
+        mLastOccluded = occluded;
+        mLastBouncerShowing = bouncerShowing;
+        mLastBouncerDismissible = bouncerDismissible;
     }
 
     public boolean onMenuPressed() {
         return mBouncer.onMenuPressed();
     }
+
+    public boolean interceptMediaKey(KeyEvent event) {
+        return mBouncer.interceptMediaKey(event);
+    }
 }
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 d175d7a..46a637b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.app.ActionBar;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.res.Resources;
@@ -28,6 +27,8 @@
 import android.view.WindowManager;
 
 import com.android.keyguard.R;
+import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.StatusBarState;
 
 /**
  * Encapsulates all logic for the status bar window state management.
@@ -77,9 +78,8 @@
                         | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
                         | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
                 PixelFormat.TRANSLUCENT);
-
         mLp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-        mLp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+        mLp.gravity = Gravity.TOP;
         mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
         mLp.setTitle("StatusBar");
         mLp.packageName = mContext.getPackageName();
@@ -111,7 +111,8 @@
     }
 
     private void applyFocusableFlag(State state) {
-        if (state.isKeyguardShowingAndNotOccluded() && state.keyguardNeedsInput) {
+        if (state.isKeyguardShowingAndNotOccluded() && state.keyguardNeedsInput
+                && state.bouncerShowing) {
             mLp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
             mLp.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
         } else if (state.isKeyguardShowingAndNotOccluded() || state.statusBarFocusable) {
@@ -137,7 +138,8 @@
     }
 
     private void applyUserActivityTimeout(State state) {
-        if (state.isKeyguardShowingAndNotOccluded()) {
+        if (state.isKeyguardShowingAndNotOccluded()
+                && state.statusBarState == StatusBarState.KEYGUARD) {
             mLp.userActivityTimeout = state.keyguardUserActivityTimeout;
         } else {
             mLp.userActivityTimeout = -1;
@@ -145,7 +147,8 @@
     }
 
     private void applyInputFeatures(State state) {
-        if (state.isKeyguardShowingAndNotOccluded()) {
+        if (state.isKeyguardShowingAndNotOccluded()
+                && state.statusBarState == StatusBarState.KEYGUARD) {
             mLp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
         } else {
             mLp.inputFeatures &= ~WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
@@ -194,6 +197,19 @@
         apply(mCurrentState);
     }
 
+    public void setBouncerShowing(boolean showing) {
+        mCurrentState.bouncerShowing = showing;
+        apply(mCurrentState);
+    }
+
+    /**
+     * @param state The {@link StatusBarState} of the status bar.
+     */
+    public void setStatusBarState(int state) {
+        mCurrentState.statusBarState = state;
+        apply(mCurrentState);
+    }
+
     private static class State {
         boolean keyguardShowing;
         boolean keyguardOccluded;
@@ -201,6 +217,12 @@
         boolean statusBarExpanded;
         boolean statusBarFocusable;
         long keyguardUserActivityTimeout;
+        boolean bouncerShowing;
+
+        /**
+         * The {@link BaseStatusBar} state from the status bar.
+         */
+        int statusBarState;
 
         private boolean isKeyguardShowingAndNotOccluded() {
             return keyguardShowing && !keyguardOccluded;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 6b5ef5a..b51626d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -31,16 +31,17 @@
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.BaseStatusBar;
-import com.android.systemui.statusbar.policy.ScrollAdapter;
+import com.android.systemui.statusbar.DragDownHelper;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 
-public class StatusBarWindowView extends FrameLayout
-{
+public class StatusBarWindowView extends FrameLayout {
     public static final String TAG = "StatusBarWindowView";
     public static final boolean DEBUG = BaseStatusBar.DEBUG;
 
     private ExpandHelper mExpandHelper;
+    private DragDownHelper mDragDownHelper;
     private NotificationStackScrollLayout mStackScrollLayout;
     private NotificationPanelView mNotificationPanel;
 
@@ -55,11 +56,14 @@
     @Override
     protected boolean fitSystemWindows(Rect insets) {
         if (getFitsSystemWindows()) {
-            setPadding(insets.left, insets.top, insets.right, insets.bottom);
+            setPadding(insets.left, insets.top, insets.right, 0);
+            insets.left = 0;
+            insets.top = 0;
+            insets.right = 0;
         } else {
             setPadding(0, 0, 0, 0);
         }
-        return true;
+        return false;
     }
 
     @Override
@@ -75,6 +79,7 @@
                 minHeight, maxHeight);
         mExpandHelper.setEventSource(this);
         mExpandHelper.setScrollAdapter(mStackScrollLayout);
+        mDragDownHelper = new DragDownHelper(getContext(), this, mStackScrollLayout, mService);
 
         // We really need to be able to animate while window animations are going on
         // so that activities may be started asynchronously from panel animations
@@ -98,6 +103,9 @@
                     return mService.onMenuPressed();
                 }
         }
+        if (mService.interceptMediaKey(event)) {
+            return true;
+        }
         return super.dispatchKeyEvent(event);
     }
 
@@ -106,8 +114,15 @@
         boolean intercept = false;
         if (mNotificationPanel.isFullyExpanded()
                 && mStackScrollLayout.getVisibility() == View.VISIBLE
-                && !mService.isOnKeyguard()) {
+                && (mService.getBarState() == StatusBarState.SHADE
+                        || (mService.getBarState() == StatusBarState.SHADE_LOCKED
+                                && !mService.isBouncerShowing()))) {
             intercept = mExpandHelper.onInterceptTouchEvent(ev);
+        } else if (mNotificationPanel.isFullyExpanded()
+                && mStackScrollLayout.getVisibility() == View.VISIBLE
+                && mService.getBarState() == StatusBarState.KEYGUARD
+                && !mService.isBouncerShowing()) {
+            intercept = mDragDownHelper.onInterceptTouchEvent(ev);
         }
         if (!intercept) {
             super.onInterceptTouchEvent(ev);
@@ -124,8 +139,11 @@
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         boolean handled = false;
-        if (mNotificationPanel.isFullyExpanded()) {
+        if (mNotificationPanel.isFullyExpanded()
+                && mService.getBarState() != StatusBarState.KEYGUARD) {
             handled = mExpandHelper.onTouchEvent(ev);
+        } else if (mService.getBarState() == StatusBarState.KEYGUARD) {
+            handled = mDragDownHelper.onTouchEvent(ev);
         }
         if (!handled) {
             handled = super.onTouchEvent(ev);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SwipeAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SwipeAffordanceView.java
new file mode 100644
index 0000000..049c5fc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SwipeAffordanceView.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.TypedArray;
+import android.os.SystemClock;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.Button;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.KeyButtonView;
+
+/**
+ * A swipeable button for affordances on the lockscreen. This is used for the camera and phone
+ * affordance.
+ */
+public class SwipeAffordanceView extends KeyButtonView {
+
+    private static final int SWIPE_DIRECTION_START = 0;
+    private static final int SWIPE_DIRECTION_END = 1;
+
+    private static final int SWIPE_DIRECTION_LEFT = 0;
+    private static final int SWIPE_DIRECTION_RIGHT = 1;
+
+    private AffordanceListener mListener;
+    private int mScaledTouchSlop;
+    private float mDragDistance;
+    private int mResolvedSwipeDirection;
+    private int mSwipeDirection;
+
+    public SwipeAffordanceView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public SwipeAffordanceView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        TypedArray a = context.getTheme().obtainStyledAttributes(
+                attrs,
+                R.styleable.SwipeAffordanceView,
+                0, 0);
+        try {
+            mSwipeDirection = a.getInt(R.styleable.SwipeAffordanceView_swipeDirection, 0);
+        } finally {
+            a.recycle();
+        }
+    }
+
+    @Override
+    public void onRtlPropertiesChanged(int layoutDirection) {
+        super.onRtlPropertiesChanged(layoutDirection);
+        if (!isLayoutRtl()) {
+            mResolvedSwipeDirection = mSwipeDirection;
+        } else {
+            mResolvedSwipeDirection = mSwipeDirection == SWIPE_DIRECTION_START
+                    ? SWIPE_DIRECTION_RIGHT
+                    : SWIPE_DIRECTION_LEFT;
+        }
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mDragDistance = getResources().getDimension(R.dimen.affordance_drag_distance);
+        mScaledTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
+    }
+
+    public void enableAccessibility(boolean touchExplorationEnabled) {
+
+        // Add a touch handler or accessibility click listener for camera button.
+        if (touchExplorationEnabled) {
+            setOnTouchListener(null);
+            setOnClickListener(mClickListener);
+        } else {
+            setOnTouchListener(mTouchListener);
+            setOnClickListener(null);
+        }
+    }
+
+    public void setAffordanceListener(AffordanceListener listener) {
+        mListener = listener;
+    }
+
+    private void onActionPerformed() {
+        if (mListener != null) {
+            mListener.onActionPerformed(this);
+        }
+    }
+
+    private void onUserActivity(long when) {
+        if (mListener != null) {
+            mListener.onUserActivity(when);
+        }
+    }
+
+    private final OnClickListener mClickListener = new OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            onActionPerformed();
+        }
+    };
+
+    private final OnTouchListener mTouchListener = new OnTouchListener() {
+        private float mStartX;
+        private boolean mTouchSlopReached;
+        private boolean mSkipCancelAnimation;
+
+        @Override
+        public boolean onTouch(final View view, MotionEvent event) {
+            float realX = event.getRawX();
+            switch (event.getAction()) {
+                case MotionEvent.ACTION_DOWN:
+                    mStartX = realX;
+                    mTouchSlopReached = false;
+                    mSkipCancelAnimation = false;
+                    break;
+                case MotionEvent.ACTION_MOVE:
+                    if (mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
+                            ? realX > mStartX
+                            : realX < mStartX) {
+                        realX = mStartX;
+                    }
+                    if (mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
+                            ? realX < mStartX - mDragDistance
+                            : realX > mStartX + mDragDistance) {
+                        view.setPressed(true);
+                        onUserActivity(event.getEventTime());
+                    } else {
+                        view.setPressed(false);
+                    }
+                    if (mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
+                            ? realX < mStartX - mScaledTouchSlop
+                            : realX > mStartX + mScaledTouchSlop) {
+                        mTouchSlopReached = true;
+                    }
+                    view.setTranslationX(mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
+                                    ? Math.max(realX - mStartX, -mDragDistance)
+                                    : Math.min(realX - mStartX, mDragDistance));
+                    break;
+                case MotionEvent.ACTION_UP:
+                    if (mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
+                            ? realX < mStartX - mDragDistance
+                            : realX > mStartX + mDragDistance) {
+                        onActionPerformed();
+                        view.animate().x(mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
+                                ? -view.getWidth()
+                                : ((View) view.getParent()).getWidth() + view.getWidth())
+                                .setInterpolator(new AccelerateInterpolator(2f)).withEndAction(
+                                new Runnable() {
+                                    @Override
+                                    public void run() {
+                                        view.setTranslationX(0);
+                                    }
+                                });
+                        mSkipCancelAnimation = true;
+                    }
+                    if (mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
+                            ? realX < mStartX - mScaledTouchSlop
+                            : realX > mStartX + mScaledTouchSlop) {
+                        mTouchSlopReached = true;
+                    }
+                    if (!mTouchSlopReached) {
+                        mSkipCancelAnimation = true;
+                        view.animate().translationX(mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
+                                ? -mDragDistance / 2
+                                : mDragDistance / 2).
+                                setInterpolator(new DecelerateInterpolator()).withEndAction(
+                                new Runnable() {
+                                    @Override
+                                    public void run() {
+                                        view.animate().translationX(0).
+                                                setInterpolator(new AccelerateInterpolator());
+                                    }
+                                });
+                    }
+                case MotionEvent.ACTION_CANCEL:
+                    view.setPressed(false);
+                    if (!mSkipCancelAnimation) {
+                        view.animate().translationX(0)
+                                .setInterpolator(new AccelerateInterpolator(2f));
+                    }
+                    break;
+            }
+            return true;
+        }
+    };
+
+    public interface AffordanceListener {
+
+        /**
+         * Called when the view would like to report user activity.
+         *
+         * @param when The timestamp of the user activity in {@link SystemClock#uptimeMillis} time
+         *             base.
+         */
+        void onUserActivity(long when);
+
+        /**
+         * Called when the action of the affordance has been performed.
+         */
+        void onActionPerformed(SwipeAffordanceView view);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
deleted file mode 100644
index 20011ff..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
+++ /dev/null
@@ -1,424 +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.phone;
-
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.Typeface;
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.OvalShape;
-import android.text.Spannable;
-import android.text.SpannableStringBuilder;
-import android.text.TextPaint;
-import android.text.method.LinkMovementMethod;
-import android.text.style.URLSpan;
-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.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
-import android.widget.Switch;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.ZenModeView.Adapter.ExitCondition;
-
-public class ZenModeView extends RelativeLayout {
-    private static final String TAG = ZenModeView.class.getSimpleName();
-    private static final boolean DEBUG = false;
-
-    public static final int BACKGROUND = 0xff282828;
-
-    private static final Typeface CONDENSED =
-            Typeface.create("sans-serif-condensed", Typeface.NORMAL);
-    private static final int GRAY = 0xff999999; //TextAppearance.StatusBar.Expanded.Network
-    private static final int DARK_GRAY = 0xff333333;
-
-    private static final long DURATION = new ValueAnimator().getDuration();
-    private static final long PAGER_DURATION = DURATION / 2;
-    private static final long CLOSE_DELAY = 600;
-    private static final long AUTO_ACTIVATE_DELAY = 100;
-
-    private final Context mContext;
-    private final TextView mModeText;
-    private final Switch mModeSwitch;
-    private final View mDivider;
-    private final UntilPager mUntilPager;
-    private final ProgressDots mProgressDots;
-    private final View mDivider2;
-    private final TextView mSettingsButton;
-
-    private Adapter mAdapter;
-    private boolean mInit;
-    private boolean mAutoActivate;
-
-    public ZenModeView(Context context) {
-        this(context, null);
-    }
-
-    public ZenModeView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        if (DEBUG) log("new %s()", getClass().getSimpleName());
-        mContext = context;
-
-        final int iconSize = mContext.getResources()
-                .getDimensionPixelSize(com.android.internal.R.dimen.notification_large_icon_width);
-        final int topRowSize = iconSize * 2 / 3;
-        final int p = topRowSize / 3;
-
-        LayoutParams lp = null;
-
-        mModeText = new TextView(mContext);
-        mModeText.setText(R.string.zen_mode_title);
-        mModeText.setId(android.R.id.title);
-        mModeText.setTextColor(GRAY);
-        mModeText.setTypeface(CONDENSED);
-        mModeText.setAllCaps(true);
-        mModeText.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
-        mModeText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mModeText.getTextSize() * 1.5f);
-        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize);
-        lp.leftMargin = p;
-        addView(mModeText, lp);
-
-        mModeSwitch = new Switch(mContext);
-        mModeSwitch.setSwitchPadding(0);
-        mModeSwitch.setSwitchTypeface(CONDENSED);
-        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize);
-        lp.topMargin = p;
-        lp.rightMargin = p;
-        lp.addRule(ALIGN_PARENT_RIGHT);
-        lp.addRule(ALIGN_BASELINE, mModeText.getId());
-        addView(mModeSwitch, lp);
-        mModeSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
-            @Override
-            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-                mAdapter.setMode(isChecked);
-                if (!mInit) return;
-                postDelayed(new Runnable(){
-                    @Override
-                    public void run() {
-                        mAdapter.close();
-                    }
-                }, CLOSE_DELAY);
-            }
-        });
-
-        mDivider = new View(mContext);
-        mDivider.setId(android.R.id.empty);
-        mDivider.setBackgroundColor(GRAY);
-        lp = new LayoutParams(LayoutParams.MATCH_PARENT, 2);
-        lp.addRule(BELOW, mModeText.getId());
-        lp.bottomMargin = p;
-        addView(mDivider, lp);
-
-        mUntilPager = new UntilPager(mContext, iconSize * 3 / 4);
-        mUntilPager.setId(android.R.id.tabhost);
-        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
-        lp.leftMargin = lp.rightMargin = iconSize / 2;
-        lp.addRule(CENTER_HORIZONTAL);
-        lp.addRule(BELOW, mDivider.getId());
-        addView(mUntilPager, lp);
-
-        mProgressDots = new ProgressDots(mContext, iconSize / 5);
-        mProgressDots.setId(android.R.id.progress);
-        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
-        lp.addRule(CENTER_HORIZONTAL);
-        lp.addRule(BELOW, mUntilPager.getId());
-        addView(mProgressDots, lp);
-
-        mDivider2 = new View(mContext);
-        mDivider2.setId(android.R.id.widget_frame);
-        mDivider2.setBackgroundColor(GRAY);
-        lp = new LayoutParams(LayoutParams.MATCH_PARENT, 2);
-        lp.addRule(BELOW, mProgressDots.getId());
-        addView(mDivider2, lp);
-
-        mSettingsButton = new TextView(mContext);
-        mSettingsButton.setTypeface(CONDENSED);
-        mSettingsButton.setTextSize(TypedValue.COMPLEX_UNIT_PX, mSettingsButton.getTextSize() * 1.3f);
-        mSettingsButton.setPadding(p, p, p, p);
-        mSettingsButton.setText("More settings...");
-        lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
-        lp.addRule(BELOW, mDivider2.getId());
-        addView(mSettingsButton, lp);
-        mSettingsButton.setOnTouchListener(new OnTouchListener() {
-            @Override
-            public boolean onTouch(View v, MotionEvent event) {
-                if (event.getAction() == MotionEvent.ACTION_DOWN) {
-                    mSettingsButton.setBackgroundColor(DARK_GRAY);
-                } else if (event.getAction() == MotionEvent.ACTION_UP) {
-                    mSettingsButton.setBackground(null);
-                    if (mAdapter != null) {
-                        mAdapter.configure();
-                    }
-                }
-                return true;
-            }
-        });
-    }
-
-    public void setAdapter(Adapter adapter) {
-        mAdapter = adapter;
-        mAdapter.setCallbacks(new Adapter.Callbacks() {
-            @Override
-            public void onChanged() {
-                post(new Runnable() {
-                    @Override
-                    public void run() {
-                        updateState(true);
-                    }
-                });
-            }
-        });
-        updateState(false);
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        if (mAutoActivate) {
-            mAutoActivate = false;
-            postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    if (!mModeSwitch.isChecked()) {
-                        mInit = false;
-                        mModeSwitch.setChecked(true);
-                    }
-                }
-            }, AUTO_ACTIVATE_DELAY);
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        if (mAdapter != null) {
-            mAdapter.dispose();
-        }
-    }
-
-    public void setAutoActivate(boolean value) {
-        mAutoActivate = value;
-    }
-
-    private void updateState(boolean animate) {
-        mUntilPager.updateState();
-        mModeSwitch.setChecked(mAdapter.getMode());
-        mInit = true;
-    }
-
-    private static void log(String msg, Object... args) {
-        Log.d(TAG, args == null || args.length == 0 ? msg : String.format(msg, args));
-    }
-
-    private final class UntilView extends FrameLayout {
-        private static final boolean SUPPORT_LINKS = false;
-
-        private final TextView mText;
-        public UntilView(Context context) {
-            super(context);
-            mText = new TextView(mContext);
-            mText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mText.getTextSize() * 1.3f);
-            mText.setTypeface(CONDENSED);
-            mText.setTextColor(GRAY);
-            mText.setGravity(Gravity.CENTER);
-            addView(mText);
-        }
-
-        public void setExitCondition(final ExitCondition ec) {
-            SpannableStringBuilder ss = new SpannableStringBuilder(ec.summary);
-            if (SUPPORT_LINKS && ec.action != null) {
-                ss.setSpan(new CustomLinkSpan() {
-                    @Override
-                    public void onClick() {
-                        // TODO wire up links
-                        Toast.makeText(mContext, ec.action, Toast.LENGTH_SHORT).show();
-                    }
-                }, 0, ss.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
-                mText.setMovementMethod(LinkMovementMethod.getInstance());
-            } else {
-                mText.setMovementMethod(null);
-            }
-            mText.setText(ss);
-        }
-    }
-
-    private final class ProgressDots extends LinearLayout {
-        private final int mDotSize;
-        public ProgressDots(Context context, int dotSize) {
-            super(context);
-            setOrientation(HORIZONTAL);
-            mDotSize = dotSize;
-        }
-
-        private void updateState(int current, int count) {
-            while (getChildCount() < count) {
-                View dot = new View(mContext);
-                OvalShape s = new OvalShape();
-                ShapeDrawable sd = new ShapeDrawable(s);
-
-                dot.setBackground(sd);
-                LayoutParams lp = new LayoutParams(mDotSize, mDotSize);
-                lp.leftMargin = lp.rightMargin = mDotSize / 2;
-                lp.topMargin = lp.bottomMargin = mDotSize * 2 / 3;
-                addView(dot, lp);
-            }
-            while (getChildCount() > count) {
-                removeViewAt(getChildCount() - 1);
-            }
-            final int N = getChildCount();
-            for (int i = 0; i < N; i++) {
-                final int color = current == i ? GRAY : DARK_GRAY;
-                ((ShapeDrawable)getChildAt(i).getBackground()).setColorFilter(color, Mode.ADD);
-            }
-        }
-    }
-
-    private final class UntilPager extends RelativeLayout {
-        private final UntilView[] mViews;
-        private int mCurrent;
-        private float mDownX;
-
-        public UntilPager(Context context, int iconSize) {
-            super(context);
-            mViews = new UntilView[3];
-            for (int i = 0; i < mViews.length; i++) {
-                UntilView v = new UntilView(mContext);
-                LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, iconSize);
-                addView(v, lp);
-                mViews[i] = v;
-            }
-            updateState();
-            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) {
-                    if (left != oldLeft || right != oldRight) {
-                        updateState();
-                    }
-                }
-            });
-            setBackgroundColor(DARK_GRAY);
-        }
-
-        private void updateState() {
-            if (mAdapter == null) {
-                return;
-            }
-            UntilView current = mViews[mCurrent];
-            current.setExitCondition(mAdapter.getExitCondition(0));
-            UntilView next = mViews[mCurrent + 1 % 3];
-            next.setExitCondition(mAdapter.getExitCondition(1));
-            UntilView prev = mViews[mCurrent + 2 % 3];
-            prev.setExitCondition(mAdapter.getExitCondition(-1));
-            position(0, false);
-            mProgressDots.updateState(mAdapter.getExitConditionIndex(),
-                    mAdapter.getExitConditionCount());
-        }
-
-        private void position(float dx, boolean animate) {
-            int w = getWidth();
-            UntilView current = mViews[mCurrent];
-            UntilView next = mViews[mCurrent + 1 % 3];
-            UntilView prev = mViews[mCurrent + 2 % 3];
-            if (animate) {
-                current.animate().setDuration(PAGER_DURATION).translationX(dx).start();
-                next.animate().setDuration(PAGER_DURATION).translationX(w + dx).start();
-                prev.animate().setDuration(PAGER_DURATION).translationX(-w + dx).start();
-            } else {
-                current.setTranslationX(dx);
-                next.setTranslationX(w + dx);
-                prev.setTranslationX(-w + dx);
-            }
-        }
-
-        @Override
-        public boolean onTouchEvent(MotionEvent event) {
-            log("onTouchEvent " + MotionEvent.actionToString(event.getAction()));
-            if (event.getAction() == MotionEvent.ACTION_DOWN) {
-                mDownX = event.getX();
-            } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
-                float dx = event.getX() - mDownX;
-                position(dx, false);
-            } else if (event.getAction() == MotionEvent.ACTION_UP
-                    || event.getAction() == MotionEvent.ACTION_CANCEL) {
-                float dx = event.getX() - mDownX;
-                int d = Math.abs(dx) < getWidth() / 3 ? 0 : Math.signum(dx) > 0 ? -1 : 1;
-                if (d != 0 && mAdapter.getExitConditionCount() > 1) {
-                    mAdapter.select(mAdapter.getExitCondition(d));
-                } else {
-                    position(0, true);
-                }
-            }
-            return true;
-        }
-    }
-
-    private abstract static class CustomLinkSpan extends URLSpan {
-        abstract public void onClick();
-
-        public CustomLinkSpan() {
-            super("#");
-        }
-
-        @Override
-        public void updateDrawState(TextPaint ds) {
-            super.updateDrawState(ds);
-            ds.setUnderlineText(false);
-            ds.bgColor = BACKGROUND;
-        }
-
-        @Override
-        public void onClick(View widget) {
-            onClick();
-        }
-    }
-
-    public interface Adapter {
-        void configure();
-        void close();
-        boolean getMode();
-        void setMode(boolean mode);
-        void select(ExitCondition ec);
-        void init();
-        void dispose();
-        void setCallbacks(Callbacks callbacks);
-        ExitCondition getExitCondition(int d);
-        int getExitConditionCount();
-        int getExitConditionIndex();
-
-        public static class ExitCondition {
-            public String summary;
-            public String line1;
-            public String line2;
-            public String action;
-            public Object tag;
-        }
-
-        public interface Callbacks {
-            void onChanged();
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
deleted file mode 100644
index 1bc97a0..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
+++ /dev/null
@@ -1,230 +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.phone;
-
-import android.app.INotificationManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.provider.Settings;
-import android.service.notification.Condition;
-import android.service.notification.IConditionListener;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public abstract class ZenModeViewAdapter implements ZenModeView.Adapter {
-    private static final String TAG = "ZenModeViewAdapter";
-
-    private final Context mContext;
-    private final ContentResolver mResolver;
-    private final Handler mHandler = new Handler();
-    private final SettingsObserver mObserver;
-    private final List<ExitCondition> mExits = new ArrayList<ExitCondition>(Arrays.asList(
-            newExit("Until you turn this off", "Until", "You turn this off", null)));
-    private final INotificationManager mNoMan;
-    private final ArrayMap<Uri, Condition> mConditions = new ArrayMap<Uri, Condition>();
-
-    private Callbacks mCallbacks;
-    private int mExitIndex;
-    private boolean mMode;
-
-    public ZenModeViewAdapter(Context context) {
-        mContext = context;
-        mResolver = mContext.getContentResolver();
-        mObserver = new SettingsObserver(mHandler);
-        mNoMan = INotificationManager.Stub.asInterface(
-                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
-        try {
-            mNoMan.requestZenModeConditions(mListener, true /*requested*/);
-        } catch (RemoteException e) {
-            // noop
-        }
-        mObserver.init();
-        init();
-    }
-
-    @Override
-    public boolean getMode() {
-        return mMode;
-    }
-
-    @Override
-    public void setMode(boolean mode) {
-        if (mode == mMode) return;
-        mMode = mode;
-        final int v = mMode ? Settings.Global.ZEN_MODE_ON : Settings.Global.ZEN_MODE_OFF;
-        AsyncTask.execute(new Runnable() {
-            @Override
-            public void run() {
-                Settings.Global.putInt(mContext.getContentResolver(),
-                        Settings.Global.ZEN_MODE, v);
-            }
-        });
-        dispatchChanged();
-    }
-
-    @Override
-    public void init() {
-        if (mExitIndex != 0) {
-            mExitIndex = 0;
-            dispatchChanged();
-        }
-        setZenModeCondition();
-    }
-
-    @Override
-    public void dispose() {
-        try {
-            mNoMan.requestZenModeConditions(mListener, false /*requested*/);
-        } catch (RemoteException e) {
-            // noop
-        }
-    }
-
-    private void dispatchChanged() {
-        mHandler.removeCallbacks(mChanged);
-        mHandler.post(mChanged);
-    }
-
-    @Override
-    public void setCallbacks(final Callbacks callbacks) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                mCallbacks = callbacks;
-            }
-        });
-    }
-
-    @Override
-    public ExitCondition getExitCondition(int d) {
-        final int n = mExits.size();
-        final int i = (n + (mExitIndex + (int)Math.signum(d))) % n;
-        return mExits.get(i);
-    }
-
-    @Override
-    public int getExitConditionCount() {
-        return mExits.size();
-    }
-
-    @Override
-    public int getExitConditionIndex() {
-        return mExitIndex;
-    }
-
-    @Override
-    public void select(ExitCondition ec) {
-        final int i = mExits.indexOf(ec);
-        if (i == -1 || i == mExitIndex) {
-            return;
-        }
-        mExitIndex = i;
-        dispatchChanged();
-        setZenModeCondition();
-    }
-
-    private void setZenModeCondition() {
-        if (mExitIndex < 0 || mExitIndex >= mExits.size()) {
-            Log.w(TAG, "setZenModeCondition to bad index " + mExitIndex + " of " + mExits.size());
-            return;
-        }
-        final Uri conditionUri = (Uri) mExits.get(mExitIndex).tag;
-        try {
-            mNoMan.setZenModeCondition(conditionUri);
-        } catch (RemoteException e) {
-            // noop
-        }
-    }
-
-    private static ExitCondition newExit(String summary, String line1, String line2, Object tag) {
-        final ExitCondition rt = new ExitCondition();
-        rt.summary = summary;
-        rt.line1 = line1;
-        rt.line2 = line2;
-        rt.tag = tag;
-        return rt;
-    }
-
-    private final Runnable mChanged = new Runnable() {
-        public void run() {
-            if (mCallbacks == null) {
-                return;
-            }
-            try {
-                mCallbacks.onChanged();
-            } catch (Throwable t) {
-                Log.w(TAG, "Error dispatching onChanged to " + mCallbacks, t);
-            }
-        }
-    };
-
-    private final class SettingsObserver extends ContentObserver {
-        public SettingsObserver(Handler handler) {
-            super(handler);
-        }
-
-        public void init() {
-            loadSettings();
-            mResolver.registerContentObserver(
-                    Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
-                    false, this);
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            loadSettings();
-            mChanged.run();  // already on handler
-        }
-
-        private void loadSettings() {
-            mMode = getModeFromSetting();
-        }
-
-        private boolean getModeFromSetting() {
-            final int v = Settings.Global.getInt(mResolver,
-                    Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
-            return v != Settings.Global.ZEN_MODE_OFF;
-        }
-    }
-
-    private final IConditionListener mListener = new IConditionListener.Stub() {
-        @Override
-        public void onConditionsReceived(Condition[] conditions) {
-            if (conditions == null || conditions.length == 0) return;
-            for (Condition c : conditions) {
-                mConditions.put(c.id, c);
-            }
-            for (int i = mExits.size() - 1; i > 0; i--) {
-                mExits.remove(i);
-            }
-            for (Condition c : mConditions.values()) {
-                mExits.add(newExit(c.caption, "", "", c.id));
-            }
-            dispatchChanged();
-        }
-    };
-}
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 0e53f0d..f4145cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 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.
@@ -16,87 +16,14 @@
 
 package com.android.systemui.statusbar.policy;
 
-import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
-import android.bluetooth.BluetoothDevice;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Set;
+public interface BluetoothController {
+    void addStateChangedCallback(BluetoothStateChangeCallback callback);
+    void removeStateChangedCallback(BluetoothStateChangeCallback callback);
 
-public class BluetoothController extends BroadcastReceiver {
-    private static final String TAG = "StatusBar.BluetoothController";
-
-    private boolean mEnabled = false;
-
-    private Set<BluetoothDevice> mBondedDevices = new HashSet<BluetoothDevice>();
-
-    private ArrayList<BluetoothStateChangeCallback> mChangeCallbacks =
-            new ArrayList<BluetoothStateChangeCallback>();
-
-    public BluetoothController(Context context) {
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
-        filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
-        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
-        context.registerReceiver(this, filter);
-
-        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        if (adapter != null) {
-            handleAdapterStateChange(adapter.getState());
-        }
-        fireCallbacks();
-        updateBondedBluetoothDevices();
-    }
-
-    public void addStateChangedCallback(BluetoothStateChangeCallback cb) {
-        mChangeCallbacks.add(cb);
-    }
-
-    public Set<BluetoothDevice> getBondedBluetoothDevices() {
-        return mBondedDevices;
-    }
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        final String action = intent.getAction();
-
-        if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
-            handleAdapterStateChange(
-                    intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR));
-        }
-        fireCallbacks();
-        updateBondedBluetoothDevices();
-    }
-
-    private void updateBondedBluetoothDevices() {
-        mBondedDevices.clear();
-
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        if (adapter != null) {
-            Set<BluetoothDevice> devices = adapter.getBondedDevices();
-            if (devices != null) {
-                for (BluetoothDevice device : devices) {
-                    if (device.getBondState() != BluetoothDevice.BOND_NONE) {
-                        mBondedDevices.add(device);
-                    }
-                }
-            }
-        }
-    }
-
-    private void handleAdapterStateChange(int adapterState) {
-        mEnabled = (adapterState == BluetoothAdapter.STATE_ON);
-    }
-
-    private void fireCallbacks() {
-        for (BluetoothStateChangeCallback cb : mChangeCallbacks) {
-            cb.onBluetoothStateChange(mEnabled);
-        }
-    }
+    boolean isBluetoothSupported();
+    boolean isBluetoothEnabled();
+    boolean isBluetoothConnected();
+    void setBluetoothEnabled(boolean enabled);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
new file mode 100644
index 0000000..1c7119f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -0,0 +1,137 @@
+/*
+ * 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.policy;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+public class BluetoothControllerImpl extends BroadcastReceiver implements BluetoothController {
+    private static final String TAG = "StatusBar.BluetoothController";
+
+    private final BluetoothAdapter mAdapter;
+
+    private boolean mEnabled = false;
+
+    private Set<BluetoothDevice> mBondedDevices = new HashSet<BluetoothDevice>();
+
+    private ArrayList<BluetoothStateChangeCallback> mChangeCallbacks =
+            new ArrayList<BluetoothStateChangeCallback>();
+
+    public BluetoothControllerImpl(Context context) {
+        mAdapter = BluetoothAdapter.getDefaultAdapter();
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+        filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
+        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+        context.registerReceiver(this, filter);
+
+        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter != null) {
+            handleAdapterStateChange(adapter.getState());
+        }
+        fireCallbacks();
+        updateBondedBluetoothDevices();
+    }
+
+    public void addStateChangedCallback(BluetoothStateChangeCallback cb) {
+        mChangeCallbacks.add(cb);
+    }
+
+    @Override
+    public void removeStateChangedCallback(BluetoothStateChangeCallback cb) {
+        mChangeCallbacks.remove(cb);
+    }
+
+    @Override
+    public boolean isBluetoothEnabled() {
+        return mAdapter != null && mAdapter.isEnabled();
+    }
+
+    @Override
+    public boolean isBluetoothConnected() {
+        return mAdapter != null
+                && mAdapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED;
+    }
+
+    @Override
+    public void setBluetoothEnabled(boolean enabled) {
+        if (mAdapter != null) {
+            if (enabled) {
+                mAdapter.enable();
+            } else {
+                mAdapter.disable();
+            }
+        }
+    }
+
+    @Override
+    public boolean isBluetoothSupported() {
+        return mAdapter != null;
+    }
+
+    public Set<BluetoothDevice> getBondedBluetoothDevices() {
+        return mBondedDevices;
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        final String action = intent.getAction();
+
+        if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
+            handleAdapterStateChange(
+                    intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR));
+        }
+        fireCallbacks();
+        updateBondedBluetoothDevices();
+    }
+
+    private void updateBondedBluetoothDevices() {
+        mBondedDevices.clear();
+
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter != null) {
+            Set<BluetoothDevice> devices = adapter.getBondedDevices();
+            if (devices != null) {
+                for (BluetoothDevice device : devices) {
+                    if (device.getBondState() != BluetoothDevice.BOND_NONE) {
+                        mBondedDevices.add(device);
+                    }
+                }
+            }
+        }
+    }
+
+    private void handleAdapterStateChange(int adapterState) {
+        mEnabled = (adapterState == BluetoothAdapter.STATE_ON);
+    }
+
+    private void fireCallbacks() {
+        for (BluetoothStateChangeCallback cb : mChangeCallbacks) {
+            cb.onBluetoothStateChange(mEnabled);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
new file mode 100644
index 0000000..54041e1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
@@ -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 com.android.systemui.statusbar.policy;
+
+public interface CastController {
+    void addCallback(Callback callback);
+    void removeCallback(Callback callback);
+    void setDiscovering(boolean request);
+    void setCurrentUserId(int currentUserId);
+
+    public interface Callback {
+        void onStateChanged(boolean enabled, boolean connecting, String connectedRouteName);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
new file mode 100644
index 0000000..33a85b1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.media.MediaRouter;
+import android.media.MediaRouter.RouteInfo;
+
+import java.util.ArrayList;
+
+/** Platform implementation of the cast controller. **/
+public class CastControllerImpl implements CastController {
+
+    private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
+    private final MediaRouter mMediaRouter;
+
+    public CastControllerImpl(Context context) {
+        mMediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
+    }
+
+    @Override
+    public void addCallback(Callback callback) {
+        mCallbacks.add(callback);
+    }
+
+    @Override
+    public void removeCallback(Callback callback) {
+        mCallbacks.remove(callback);
+    }
+
+    @Override
+    public void setDiscovering(boolean request) {
+        if (request) {
+            mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
+                    mMediaCallback,
+                    MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
+        } else {
+            mMediaRouter.removeCallback(mMediaCallback);
+        }
+    }
+
+    @Override
+    public void setCurrentUserId(int currentUserId) {
+        mMediaRouter.rebindAsUser(currentUserId);
+    }
+
+    private void updateRemoteDisplays() {
+        final MediaRouter.RouteInfo connectedRoute = mMediaRouter.getSelectedRoute(
+                MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
+        boolean enabled = connectedRoute != null
+                && connectedRoute.matchesTypes(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
+        boolean connecting;
+        if (enabled) {
+            connecting = connectedRoute.isConnecting();
+        } else {
+            connecting = false;
+            enabled = mMediaRouter.isRouteAvailable(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
+                    MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE);
+        }
+
+        String connectedRouteName = null;
+        if (connectedRoute != null) {
+            connectedRouteName = connectedRoute.getName().toString();
+        }
+        fireStateChanged(enabled, connecting, connectedRouteName);
+    }
+
+    private void fireStateChanged(boolean enabled, boolean connecting, String connectedRouteName) {
+        for (Callback callback : mCallbacks) {
+            callback.onStateChanged(enabled, connecting, connectedRouteName);
+        }
+    }
+
+    private final MediaRouter.SimpleCallback mMediaCallback = new MediaRouter.SimpleCallback() {
+        @Override
+        public void onRouteAdded(MediaRouter router, RouteInfo route) {
+            updateRemoteDisplays();
+        }
+        @Override
+        public void onRouteChanged(MediaRouter router, RouteInfo route) {
+            updateRemoteDisplays();
+        }
+        @Override
+        public void onRouteRemoved(MediaRouter router, RouteInfo route) {
+            updateRemoteDisplays();
+        }
+        @Override
+        public void onRouteSelected(MediaRouter router, int type, RouteInfo route) {
+            updateRemoteDisplays();
+        }
+        @Override
+        public void onRouteUnselected(MediaRouter router, int type, RouteInfo route) {
+            updateRemoteDisplays();
+        }
+    };
+}
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 8ced1c9..55a0bba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.TypedArray;
 import android.os.Bundle;
 import android.text.Spannable;
 import android.text.SpannableStringBuilder;
@@ -30,6 +31,7 @@
 import android.widget.TextView;
 
 import com.android.systemui.DemoMode;
+import com.android.systemui.R;
 
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
@@ -52,7 +54,7 @@
     private static final int AM_PM_STYLE_SMALL   = 1;
     private static final int AM_PM_STYLE_GONE    = 2;
 
-    private static final int AM_PM_STYLE = AM_PM_STYLE_GONE;
+    private final int mAmPmStyle;
 
     public Clock(Context context) {
         this(context, null);
@@ -64,6 +66,15 @@
 
     public Clock(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+        TypedArray a = context.getTheme().obtainStyledAttributes(
+                attrs,
+                R.styleable.Clock,
+                0, 0);
+        try {
+            mAmPmStyle = a.getInt(R.styleable.Clock_amPmStyle, AM_PM_STYLE_GONE);
+        } finally {
+            a.recycle();
+        }
     }
 
     @Override
@@ -145,7 +156,7 @@
              * add dummy characters around it to let us find it again after
              * formatting and change its size.
              */
-            if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) {
+            if (mAmPmStyle != AM_PM_STYLE_NORMAL) {
                 int a = -1;
                 boolean quoted = false;
                 for (int i = 0; i < format.length(); i++) {
@@ -177,15 +188,15 @@
         }
         String result = sdf.format(mCalendar.getTime());
 
-        if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) {
+        if (mAmPmStyle != AM_PM_STYLE_NORMAL) {
             int magic1 = result.indexOf(MAGIC1);
             int magic2 = result.indexOf(MAGIC2);
             if (magic1 >= 0 && magic2 > magic1) {
                 SpannableStringBuilder formatted = new SpannableStringBuilder(result);
-                if (AM_PM_STYLE == AM_PM_STYLE_GONE) {
+                if (mAmPmStyle == AM_PM_STYLE_GONE) {
                     formatted.delete(magic1, magic2+1);
                 } else {
-                    if (AM_PM_STYLE == AM_PM_STYLE_SMALL) {
+                    if (mAmPmStyle == AM_PM_STYLE_SMALL) {
                         CharacterStyle style = new RelativeSizeSpan(0.7f);
                         formatted.setSpan(style, magic1, magic2,
                                           Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java
new file mode 100644
index 0000000..158e9c1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java
@@ -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 com.android.systemui.statusbar.policy;
+
+/** Common interface for items requiring manual cleanup. **/
+public interface Disposable {
+    void dispose();
+}
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 c94c65f..81e2cb3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -32,6 +32,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SwipeHelper;
 import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.NotificationData;
 
 public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper.Callback, ExpandHelper.Callback {
@@ -185,12 +186,12 @@
     // ExpandHelper.Callback methods
 
     @Override
-    public View getChildAtRawPosition(float x, float y) {
+    public ExpandableView getChildAtRawPosition(float x, float y) {
         return getChildAtPosition(x, y);
     }
 
     @Override
-    public View getChildAtPosition(float x, float y) {
+    public ExpandableView getChildAtPosition(float x, float y) {
         return mHeadsUp == null ? null : mHeadsUp.row;
     }
 
@@ -236,6 +237,10 @@
     }
 
     @Override
+    public void onChildSnappedBack(View animView) {
+    }
+
+    @Override
     public View getChildAtPosition(MotionEvent ev) {
         return mContentHolder;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
index f5ee95b..29a8981 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 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.
@@ -16,47 +16,11 @@
 
 package com.android.systemui.statusbar.policy;
 
-import android.app.ActivityManager;
-import android.app.AppOpsManager;
-import android.app.StatusBarManager;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.location.LocationManager;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-
-import com.android.systemui.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A controller to manage changes of location related states and update the views accordingly.
- */
-public class LocationController extends BroadcastReceiver {
-    // The name of the placeholder corresponding to the location request status icon.
-    // This string corresponds to config_statusBarIcons in core/res/res/values/config.xml.
-    public static final String LOCATION_STATUS_ICON_PLACEHOLDER = "location";
-    public static final int LOCATION_STATUS_ICON_ID
-        = R.drawable.stat_sys_device_access_location_found;
-
-    private static final int[] mHighPowerRequestAppOpArray
-        = new int[] {AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION};
-
-    private Context mContext;
-
-    private AppOpsManager mAppOpsManager;
-    private StatusBarManager mStatusBarManager;
-
-    private boolean mAreActiveLocationRequests;
-
-    private ArrayList<LocationSettingsChangeCallback> mSettingsChangeCallbacks =
-            new ArrayList<LocationSettingsChangeCallback>();
+public interface LocationController {
+    boolean isLocationEnabled();
+    boolean setLocationEnabled(boolean enabled);
+    void addSettingsChangedCallback(LocationSettingsChangeCallback cb);
+    void removeSettingsChangedCallback(LocationSettingsChangeCallback cb);
 
     /**
      * A callback for change in location settings (the user has enabled/disabled location).
@@ -68,156 +32,6 @@
          * @param locationEnabled A value of true indicates that at least one type of location
          *                        is enabled in settings.
          */
-        public void onLocationSettingsChanged(boolean locationEnabled);
-    }
-
-    public LocationController(Context context) {
-        mContext = context;
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
-        context.registerReceiver(this, filter);
-
-        mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
-        mStatusBarManager
-                = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
-
-        // Register to listen for changes in location settings.
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION);
-        context.registerReceiverAsUser(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                String action = intent.getAction();
-                if (LocationManager.MODE_CHANGED_ACTION.equals(action)) {
-                    locationSettingsChanged();
-                }
-            }
-        }, UserHandle.ALL, intentFilter, null, new Handler());
-
-        // Examine the current location state and initialize the status view.
-        updateActiveLocationRequests();
-        refreshViews();
-    }
-
-    /**
-     * Add a callback to listen for changes in location settings.
-     */
-    public void addSettingsChangedCallback(LocationSettingsChangeCallback cb) {
-        mSettingsChangeCallbacks.add(cb);
-    }
-
-    /**
-     * Enable or disable location in settings.
-     *
-     * <p>This will attempt to enable/disable every type of location setting
-     * (e.g. high and balanced power).
-     *
-     * <p>If enabling, a user consent dialog will pop up prompting the user to accept.
-     * If the user doesn't accept, network location won't be enabled.
-     *
-     * @return true if attempt to change setting was successful.
-     */
-    public boolean setLocationEnabled(boolean enabled) {
-        int currentUserId = ActivityManager.getCurrentUser();
-        if (isUserLocationRestricted(currentUserId)) {
-            return false;
-        }
-        final ContentResolver cr = mContext.getContentResolver();
-        // When enabling location, a user consent dialog will pop up, and the
-        // setting won't be fully enabled until the user accepts the agreement.
-        int mode = enabled
-                ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY : Settings.Secure.LOCATION_MODE_OFF;
-        // QuickSettings always runs as the owner, so specifically set the settings
-        // for the current foreground user.
-        return Settings.Secure
-                .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId);
-    }
-
-    /**
-     * Returns true if location isn't disabled in settings.
-     */
-    public boolean isLocationEnabled() {
-        ContentResolver resolver = mContext.getContentResolver();
-        // QuickSettings always runs as the owner, so specifically retrieve the settings
-        // for the current foreground user.
-        int mode = Settings.Secure.getIntForUser(resolver, Settings.Secure.LOCATION_MODE,
-                Settings.Secure.LOCATION_MODE_OFF, ActivityManager.getCurrentUser());
-        return mode != Settings.Secure.LOCATION_MODE_OFF;
-    }
-
-    /**
-     * Returns true if the current user is restricted from using location.
-     */
-    private boolean isUserLocationRestricted(int userId) {
-        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        return um.hasUserRestriction(
-                UserManager.DISALLOW_SHARE_LOCATION,
-                new UserHandle(userId));
-    }
-
-    /**
-     * Returns true if there currently exist active high power location requests.
-     */
-    private boolean areActiveHighPowerLocationRequests() {
-        List<AppOpsManager.PackageOps> packages
-            = mAppOpsManager.getPackagesForOps(mHighPowerRequestAppOpArray);
-        // AppOpsManager can return null when there is no requested data.
-        if (packages != null) {
-            final int numPackages = packages.size();
-            for (int packageInd = 0; packageInd < numPackages; packageInd++) {
-                AppOpsManager.PackageOps packageOp = packages.get(packageInd);
-                List<AppOpsManager.OpEntry> opEntries = packageOp.getOps();
-                if (opEntries != null) {
-                    final int numOps = opEntries.size();
-                    for (int opInd = 0; opInd < numOps; opInd++) {
-                        AppOpsManager.OpEntry opEntry = opEntries.get(opInd);
-                        // AppOpsManager should only return OP_MONITOR_HIGH_POWER_LOCATION because
-                        // of the mHighPowerRequestAppOpArray filter, but checking defensively.
-                        if (opEntry.getOp() == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION) {
-                            if (opEntry.isRunning()) {
-                                return true;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        return false;
-    }
-
-    // Updates the status view based on the current state of location requests.
-    private void refreshViews() {
-        if (mAreActiveLocationRequests) {
-            mStatusBarManager.setIcon(LOCATION_STATUS_ICON_PLACEHOLDER, LOCATION_STATUS_ICON_ID, 0,
-                    mContext.getString(R.string.accessibility_location_active));
-        } else {
-            mStatusBarManager.removeIcon(LOCATION_STATUS_ICON_PLACEHOLDER);
-        }
-    }
-
-    // Reads the active location requests and updates the status view if necessary.
-    private void updateActiveLocationRequests() {
-        boolean hadActiveLocationRequests = mAreActiveLocationRequests;
-        mAreActiveLocationRequests = areActiveHighPowerLocationRequests();
-        if (mAreActiveLocationRequests != hadActiveLocationRequests) {
-            refreshViews();
-        }
-    }
-
-    private void locationSettingsChanged() {
-        boolean isEnabled = isLocationEnabled();
-        for (LocationSettingsChangeCallback cb : mSettingsChangeCallbacks) {
-            cb.onLocationSettingsChanged(isEnabled);
-        }
-    }
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        final String action = intent.getAction();
-        if (LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) {
-            updateActiveLocationRequests();
-        }
+        void onLocationSettingsChanged(boolean locationEnabled);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
new file mode 100644
index 0000000..9e5ad18
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -0,0 +1,214 @@
+/*
+ * 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.policy;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.location.LocationManager;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+
+import com.android.systemui.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A controller to manage changes of location related states and update the views accordingly.
+ */
+public class LocationControllerImpl extends BroadcastReceiver implements LocationController {
+    // The name of the placeholder corresponding to the location request status icon.
+    // This string corresponds to config_statusBarIcons in core/res/res/values/config.xml.
+    public static final String LOCATION_STATUS_ICON_PLACEHOLDER = "location";
+    public static final int LOCATION_STATUS_ICON_ID
+        = R.drawable.stat_sys_device_access_location_found;
+
+    private static final int[] mHighPowerRequestAppOpArray
+        = new int[] {AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION};
+
+    private Context mContext;
+
+    private AppOpsManager mAppOpsManager;
+    private StatusBarManager mStatusBarManager;
+
+    private boolean mAreActiveLocationRequests;
+
+    private ArrayList<LocationSettingsChangeCallback> mSettingsChangeCallbacks =
+            new ArrayList<LocationSettingsChangeCallback>();
+
+    public LocationControllerImpl(Context context) {
+        mContext = context;
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
+        context.registerReceiver(this, filter);
+
+        mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+        mStatusBarManager
+                = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
+
+        // Register to listen for changes in location settings.
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION);
+        context.registerReceiverAsUser(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                String action = intent.getAction();
+                if (LocationManager.MODE_CHANGED_ACTION.equals(action)) {
+                    locationSettingsChanged();
+                }
+            }
+        }, UserHandle.ALL, intentFilter, null, new Handler());
+
+        // Examine the current location state and initialize the status view.
+        updateActiveLocationRequests();
+        refreshViews();
+    }
+
+    /**
+     * Add a callback to listen for changes in location settings.
+     */
+    public void addSettingsChangedCallback(LocationSettingsChangeCallback cb) {
+        mSettingsChangeCallbacks.add(cb);
+    }
+
+    public void removeSettingsChangedCallback(LocationSettingsChangeCallback cb) {
+        mSettingsChangeCallbacks.remove(cb);
+    }
+
+    /**
+     * Enable or disable location in settings.
+     *
+     * <p>This will attempt to enable/disable every type of location setting
+     * (e.g. high and balanced power).
+     *
+     * <p>If enabling, a user consent dialog will pop up prompting the user to accept.
+     * If the user doesn't accept, network location won't be enabled.
+     *
+     * @return true if attempt to change setting was successful.
+     */
+    public boolean setLocationEnabled(boolean enabled) {
+        int currentUserId = ActivityManager.getCurrentUser();
+        if (isUserLocationRestricted(currentUserId)) {
+            return false;
+        }
+        final ContentResolver cr = mContext.getContentResolver();
+        // When enabling location, a user consent dialog will pop up, and the
+        // setting won't be fully enabled until the user accepts the agreement.
+        int mode = enabled
+                ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY : Settings.Secure.LOCATION_MODE_OFF;
+        // QuickSettings always runs as the owner, so specifically set the settings
+        // for the current foreground user.
+        return Settings.Secure
+                .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId);
+    }
+
+    /**
+     * Returns true if location isn't disabled in settings.
+     */
+    public boolean isLocationEnabled() {
+        ContentResolver resolver = mContext.getContentResolver();
+        // QuickSettings always runs as the owner, so specifically retrieve the settings
+        // for the current foreground user.
+        int mode = Settings.Secure.getIntForUser(resolver, Settings.Secure.LOCATION_MODE,
+                Settings.Secure.LOCATION_MODE_OFF, ActivityManager.getCurrentUser());
+        return mode != Settings.Secure.LOCATION_MODE_OFF;
+    }
+
+    /**
+     * Returns true if the current user is restricted from using location.
+     */
+    private boolean isUserLocationRestricted(int userId) {
+        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        return um.hasUserRestriction(
+                UserManager.DISALLOW_SHARE_LOCATION,
+                new UserHandle(userId));
+    }
+
+    /**
+     * Returns true if there currently exist active high power location requests.
+     */
+    private boolean areActiveHighPowerLocationRequests() {
+        List<AppOpsManager.PackageOps> packages
+            = mAppOpsManager.getPackagesForOps(mHighPowerRequestAppOpArray);
+        // AppOpsManager can return null when there is no requested data.
+        if (packages != null) {
+            final int numPackages = packages.size();
+            for (int packageInd = 0; packageInd < numPackages; packageInd++) {
+                AppOpsManager.PackageOps packageOp = packages.get(packageInd);
+                List<AppOpsManager.OpEntry> opEntries = packageOp.getOps();
+                if (opEntries != null) {
+                    final int numOps = opEntries.size();
+                    for (int opInd = 0; opInd < numOps; opInd++) {
+                        AppOpsManager.OpEntry opEntry = opEntries.get(opInd);
+                        // AppOpsManager should only return OP_MONITOR_HIGH_POWER_LOCATION because
+                        // of the mHighPowerRequestAppOpArray filter, but checking defensively.
+                        if (opEntry.getOp() == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION) {
+                            if (opEntry.isRunning()) {
+                                return true;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    // Updates the status view based on the current state of location requests.
+    private void refreshViews() {
+        if (mAreActiveLocationRequests) {
+            mStatusBarManager.setIcon(LOCATION_STATUS_ICON_PLACEHOLDER, LOCATION_STATUS_ICON_ID, 0,
+                    mContext.getString(R.string.accessibility_location_active));
+        } else {
+            mStatusBarManager.removeIcon(LOCATION_STATUS_ICON_PLACEHOLDER);
+        }
+    }
+
+    // Reads the active location requests and updates the status view if necessary.
+    private void updateActiveLocationRequests() {
+        boolean hadActiveLocationRequests = mAreActiveLocationRequests;
+        mAreActiveLocationRequests = areActiveHighPowerLocationRequests();
+        if (mAreActiveLocationRequests != hadActiveLocationRequests) {
+            refreshViews();
+        }
+    }
+
+    private void locationSettingsChanged() {
+        boolean isEnabled = isLocationEnabled();
+        for (LocationSettingsChangeCallback cb : mSettingsChangeCallbacks) {
+            cb.onLocationSettingsChanged(isEnabled);
+        }
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        final String action = intent.getAction();
+        if (LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) {
+            updateActiveLocationRequests();
+        }
+    }
+}
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 92c008e..dc8f315 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 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.
@@ -16,153 +16,12 @@
 
 package com.android.systemui.statusbar.policy;
 
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.net.wimax.WimaxManagerConstants;
-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.TelephonyManager;
-import android.util.Log;
-import android.view.View;
-import android.widget.TextView;
+public interface NetworkController {
 
-import com.android.internal.telephony.IccCardConstants;
-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;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
-public class NetworkController extends BroadcastReceiver implements DemoMode {
-    // debug
-    static final String TAG = "StatusBar.NetworkController";
-    static final boolean DEBUG = false;
-    static final boolean CHATTY = false; // additional diagnostics, but not logspew
-
-    private static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_signal_flightmode;
-
-    // telephony
-    boolean mHspaDataDistinguishable;
-    final TelephonyManager mPhone;
-    boolean mDataConnected;
-    IccCardConstants.State mSimState = IccCardConstants.State.READY;
-    int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
-    int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
-    int mDataState = TelephonyManager.DATA_DISCONNECTED;
-    int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
-    ServiceState mServiceState;
-    SignalStrength mSignalStrength;
-    int[] mDataIconList = TelephonyIcons.DATA_G[0];
-    String mNetworkName;
-    String mNetworkNameDefault;
-    String mNetworkNameSeparator;
-    int mPhoneSignalIconId;
-    int mQSPhoneSignalIconId;
-    int mDataDirectionIconId; // data + data direction on phones
-    int mDataSignalIconId;
-    int mDataTypeIconId;
-    int mQSDataTypeIconId;
-    int mAirplaneIconId;
-    boolean mDataActive;
-    int mLastSignalLevel;
-    boolean mShowPhoneRSSIForData = false;
-    boolean mShowAtLeastThreeGees = false;
-    boolean mAlwaysShowCdmaRssi = false;
-
-    String mContentDescriptionPhoneSignal;
-    String mContentDescriptionWifi;
-    String mContentDescriptionWimax;
-    String mContentDescriptionCombinedSignal;
-    String mContentDescriptionDataType;
-
-    // wifi
-    final WifiManager mWifiManager;
-    AsyncChannel mWifiChannel;
-    boolean mWifiEnabled, mWifiConnected;
-    int mWifiRssi, mWifiLevel;
-    String mWifiSsid;
-    int mWifiIconId = 0;
-    int mQSWifiIconId = 0;
-    int mWifiActivity = WifiManager.DATA_ACTIVITY_NONE;
-
-    // bluetooth
-    private boolean mBluetoothTethered = false;
-    private int mBluetoothTetherIconId =
-        com.android.internal.R.drawable.stat_sys_tether_bluetooth;
-
-    //wimax
-    private boolean mWimaxSupported = false;
-    private boolean mIsWimaxEnabled = false;
-    private boolean mWimaxConnected = false;
-    private boolean mWimaxIdle = false;
-    private int mWimaxIconId = 0;
-    private int mWimaxSignal = 0;
-    private int mWimaxState = 0;
-    private int mWimaxExtraState = 0;
-
-    // data connectivity (regardless of state, can we access the internet?)
-    // state of inet connection - 0 not connected, 100 connected
-    private boolean mConnected = false;
-    private int mConnectedNetworkType = ConnectivityManager.TYPE_NONE;
-    private String mConnectedNetworkTypeName;
-    private int mInetCondition = 0;
-    private int mLastInetCondition = 0;
-    private static final int INET_CONDITION_THRESHOLD = 50;
-
-    private boolean mAirplaneMode = false;
-    private boolean mLastAirplaneMode = true;
-
-    private Locale mLocale = null;
-    private Locale mLastLocale = null;
-
-    // our ui
-    Context mContext;
-    ArrayList<TextView> mCombinedLabelViews = new ArrayList<TextView>();
-    ArrayList<TextView> mMobileLabelViews = new ArrayList<TextView>();
-    ArrayList<TextView> mWifiLabelViews = new ArrayList<TextView>();
-    ArrayList<TextView> mEmergencyLabelViews = new ArrayList<TextView>();
-    ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>();
-    ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks =
-            new ArrayList<NetworkSignalChangedCallback>();
-    int mLastPhoneSignalIconId = -1;
-    int mLastDataDirectionIconId = -1;
-    int mLastWifiIconId = -1;
-    int mLastWimaxIconId = -1;
-    int mLastCombinedSignalIconId = -1;
-    int mLastDataTypeIconId = -1;
-    String mLastCombinedLabel = "";
-
-    private boolean mHasMobileDataFeature;
-
-    boolean mDataAndWifiStacked = false;
-
-    public interface SignalCluster {
-        void setWifiIndicators(boolean visible, int strengthIcon, boolean problem,
-                String contentDescription);
-        void setMobileDataIndicators(boolean visible, int strengthIcon, boolean problem,
-                int typeIcon, String contentDescription, String typeContentDescription);
-        void setIsAirplaneMode(boolean is, int airplaneIcon);
-    }
+    boolean hasMobileDataFeature();
+    void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb);
+    void removeNetworkSignalChangedCallback(NetworkSignalChangedCallback cb);
+    void setWifiEnabled(boolean enabled);
 
     public interface NetworkSignalChangedCallback {
         void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
@@ -174,1304 +33,4 @@
                 String dataTypeContentDescriptionId, String description);
         void onAirplaneModeChanged(boolean enabled);
     }
-
-    /**
-     * Construct this controller object and register for updates.
-     */
-    public NetworkController(Context context) {
-        mContext = context;
-        final Resources res = context.getResources();
-
-        ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
-                Context.CONNECTIVITY_SERVICE);
-        mHasMobileDataFeature = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
-
-        mShowPhoneRSSIForData = res.getBoolean(R.bool.config_showPhoneRSSIForData);
-        mShowAtLeastThreeGees = res.getBoolean(R.bool.config_showMin3G);
-        mAlwaysShowCdmaRssi = res.getBoolean(
-                com.android.internal.R.bool.config_alwaysUseCdmaRssi);
-
-        // set up the default wifi icon, used when no radios have ever appeared
-        updateWifiIcons();
-        updateWimaxIcons();
-
-        // telephony
-        mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
-        mPhone.listen(mPhoneStateListener,
-                          PhoneStateListener.LISTEN_SERVICE_STATE
-                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
-                        | PhoneStateListener.LISTEN_CALL_STATE
-                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
-                        | PhoneStateListener.LISTEN_DATA_ACTIVITY);
-        mHspaDataDistinguishable = mContext.getResources().getBoolean(
-                R.bool.config_hspa_data_distinguishable);
-        mNetworkNameSeparator = mContext.getString(R.string.status_bar_network_name_separator);
-        mNetworkNameDefault = mContext.getString(
-                com.android.internal.R.string.lockscreen_carrier_default);
-        mNetworkName = mNetworkNameDefault;
-
-        // wifi
-        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
-        Handler handler = new WifiHandler();
-        mWifiChannel = new AsyncChannel();
-        Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger();
-        if (wifiMessenger != null) {
-            mWifiChannel.connect(mContext, handler, wifiMessenger);
-        }
-
-        // broadcasts
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
-        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
-        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
-        filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
-        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
-        filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
-        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
-        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        mWimaxSupported = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_wimaxEnabled);
-        if(mWimaxSupported) {
-            filter.addAction(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION);
-            filter.addAction(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION);
-            filter.addAction(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION);
-        }
-        context.registerReceiver(this, filter);
-
-        // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
-        updateAirplaneMode();
-
-        mLastLocale = mContext.getResources().getConfiguration().locale;
-    }
-
-    public boolean hasMobileDataFeature() {
-        return mHasMobileDataFeature;
-    }
-
-    public boolean hasVoiceCallingFeature() {
-        return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
-    }
-
-    public boolean isEmergencyOnly() {
-        return (mServiceState != null && mServiceState.isEmergencyOnly());
-    }
-
-    public void addCombinedLabelView(TextView v) {
-        mCombinedLabelViews.add(v);
-    }
-
-    public void addMobileLabelView(TextView v) {
-        mMobileLabelViews.add(v);
-    }
-
-    public void addWifiLabelView(TextView v) {
-        mWifiLabelViews.add(v);
-    }
-
-    public void addEmergencyLabelView(TextView v) {
-        mEmergencyLabelViews.add(v);
-    }
-
-    public void addSignalCluster(SignalCluster cluster) {
-        mSignalClusters.add(cluster);
-        refreshSignalCluster(cluster);
-    }
-
-    public void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) {
-        mSignalsChangedCallbacks.add(cb);
-        notifySignalsChangedCallbacks(cb);
-    }
-
-    public void refreshSignalCluster(SignalCluster cluster) {
-        if (mDemoMode) return;
-        cluster.setWifiIndicators(
-                // only show wifi in the cluster if connected or if wifi-only
-                mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature),
-                mWifiIconId,
-                mInetCondition == 0,
-                mContentDescriptionWifi);
-
-        if (mIsWimaxEnabled && mWimaxConnected) {
-            // wimax is special
-            cluster.setMobileDataIndicators(
-                    true,
-                    mAlwaysShowCdmaRssi ? mPhoneSignalIconId : mWimaxIconId,
-                    mInetCondition == 0,
-                    mDataTypeIconId,
-                    mContentDescriptionWimax,
-                    mContentDescriptionDataType);
-        } else {
-            // normal mobile data
-            cluster.setMobileDataIndicators(
-                    mHasMobileDataFeature,
-                    mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId,
-                    mInetCondition == 0,
-                    mDataTypeIconId,
-                    mContentDescriptionPhoneSignal,
-                    mContentDescriptionDataType);
-        }
-        cluster.setIsAirplaneMode(mAirplaneMode, mAirplaneIconId);
-    }
-
-    void notifySignalsChangedCallbacks(NetworkSignalChangedCallback cb) {
-        // only show wifi in the cluster if connected or if wifi-only
-        boolean wifiEnabled = mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature);
-        String wifiDesc = wifiEnabled ?
-                mWifiSsid : null;
-        boolean wifiIn = wifiEnabled && mWifiSsid != null
-                && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT
-                || mWifiActivity == WifiManager.DATA_ACTIVITY_IN);
-        boolean wifiOut = wifiEnabled && mWifiSsid != null
-                && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT
-                || mWifiActivity == WifiManager.DATA_ACTIVITY_OUT);
-        cb.onWifiSignalChanged(wifiEnabled, mQSWifiIconId, wifiIn, wifiOut,
-                mContentDescriptionWifi, wifiDesc);
-
-        boolean mobileIn = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT
-                || mDataActivity == TelephonyManager.DATA_ACTIVITY_IN);
-        boolean mobileOut = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT
-                || mDataActivity == TelephonyManager.DATA_ACTIVITY_OUT);
-        if (isEmergencyOnly()) {
-            cb.onMobileDataSignalChanged(false, mQSPhoneSignalIconId,
-                    mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
-                    mContentDescriptionDataType, null);
-        } else {
-            if (mIsWimaxEnabled && mWimaxConnected) {
-                // Wimax is special
-                cb.onMobileDataSignalChanged(true, mQSPhoneSignalIconId,
-                        mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
-                        mContentDescriptionDataType, mNetworkName);
-            } else {
-                // Normal mobile data
-                cb.onMobileDataSignalChanged(mHasMobileDataFeature, mQSPhoneSignalIconId,
-                        mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
-                        mContentDescriptionDataType, mNetworkName);
-            }
-        }
-        cb.onAirplaneModeChanged(mAirplaneMode);
-    }
-
-    public void setStackedMode(boolean stacked) {
-        mDataAndWifiStacked = true;
-    }
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        final String action = intent.getAction();
-        if (action.equals(WifiManager.RSSI_CHANGED_ACTION)
-                || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)
-                || action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-            updateWifiState(intent);
-            refreshViews();
-        } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
-            updateSimState(intent);
-            updateDataIcon();
-            refreshViews();
-        } else 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));
-            refreshViews();
-        } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
-                 action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
-            updateConnectivity(intent);
-            refreshViews();
-        } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
-            refreshLocale();
-            refreshViews();
-        } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
-            refreshLocale();
-            updateAirplaneMode();
-            refreshViews();
-        } else if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION) ||
-                action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION) ||
-                action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
-            updateWimaxState(intent);
-            refreshViews();
-        }
-    }
-
-
-    // ===== Telephony ==============================================================
-
-    PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
-        @Override
-        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
-            if (DEBUG) {
-                Log.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength +
-                    ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
-            }
-            mSignalStrength = signalStrength;
-            updateTelephonySignalStrength();
-            refreshViews();
-        }
-
-        @Override
-        public void onServiceStateChanged(ServiceState state) {
-            if (DEBUG) {
-                Log.d(TAG, "onServiceStateChanged voiceState=" + state.getVoiceRegState()
-                        + " dataState=" + state.getDataRegState());
-            }
-            mServiceState = state;
-            updateTelephonySignalStrength();
-            updateDataNetType();
-            updateDataIcon();
-            refreshViews();
-        }
-
-        @Override
-        public void onCallStateChanged(int state, String incomingNumber) {
-            if (DEBUG) {
-                Log.d(TAG, "onCallStateChanged state=" + state);
-            }
-            // In cdma, if a voice call is made, RSSI should switch to 1x.
-            if (isCdma()) {
-                updateTelephonySignalStrength();
-                refreshViews();
-            }
-        }
-
-        @Override
-        public void onDataConnectionStateChanged(int state, int networkType) {
-            if (DEBUG) {
-                Log.d(TAG, "onDataConnectionStateChanged: state=" + state
-                        + " type=" + networkType);
-            }
-            mDataState = state;
-            mDataNetType = networkType;
-            updateDataNetType();
-            updateDataIcon();
-            refreshViews();
-        }
-
-        @Override
-        public void onDataActivity(int direction) {
-            if (DEBUG) {
-                Log.d(TAG, "onDataActivity: direction=" + direction);
-            }
-            mDataActivity = direction;
-            updateDataIcon();
-            refreshViews();
-        }
-    };
-
-    private final void updateSimState(Intent intent) {
-        String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
-        if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
-            mSimState = IccCardConstants.State.ABSENT;
-        }
-        else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
-            mSimState = IccCardConstants.State.READY;
-        }
-        else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
-            final String lockedReason =
-                    intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
-            if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
-                mSimState = IccCardConstants.State.PIN_REQUIRED;
-            }
-            else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
-                mSimState = IccCardConstants.State.PUK_REQUIRED;
-            }
-            else {
-                mSimState = IccCardConstants.State.NETWORK_LOCKED;
-            }
-        } else {
-            mSimState = IccCardConstants.State.UNKNOWN;
-        }
-    }
-
-    private boolean isCdma() {
-        return (mSignalStrength != null) && !mSignalStrength.isGsm();
-    }
-
-    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 void updateAirplaneMode() {
-        mAirplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
-            Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
-    }
-
-    private void refreshLocale() {
-        mLocale = mContext.getResources().getConfiguration().locale;
-    }
-
-    private final void updateTelephonySignalStrength() {
-        if (!hasService()) {
-            if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: !hasService()");
-            mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
-            mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
-            mDataSignalIconId = R.drawable.stat_sys_signal_null;
-        } else {
-            if (mSignalStrength == null) {
-                if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: mSignalStrength == null");
-                mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
-                mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
-                mDataSignalIconId = R.drawable.stat_sys_signal_null;
-                mContentDescriptionPhoneSignal = mContext.getString(
-                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0]);
-            } else {
-                int iconLevel;
-                int[] iconList;
-                if (isCdma() && mAlwaysShowCdmaRssi) {
-                    mLastSignalLevel = iconLevel = mSignalStrength.getCdmaLevel();
-                    if(DEBUG) Log.d(TAG, "mAlwaysShowCdmaRssi=" + mAlwaysShowCdmaRssi
-                            + " set to cdmaLevel=" + mSignalStrength.getCdmaLevel()
-                            + " instead of level=" + mSignalStrength.getLevel());
-                } else {
-                    mLastSignalLevel = iconLevel = mSignalStrength.getLevel();
-                }
-
-                if (isCdma()) {
-                    if (isCdmaEri()) {
-                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
-                    } else {
-                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
-                    }
-                } else {
-                    // Though mPhone is a Manager, this call is not an IPC
-                    if (mPhone.isNetworkRoaming()) {
-                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
-                    } else {
-                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
-                    }
-                }
-                mPhoneSignalIconId = iconList[iconLevel];
-                mQSPhoneSignalIconId =
-                        TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[mInetCondition][iconLevel];
-                mContentDescriptionPhoneSignal = mContext.getString(
-                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]);
-                mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel];
-            }
-        }
-    }
-
-    private final void updateDataNetType() {
-        if (mIsWimaxEnabled && mWimaxConnected) {
-            // wimax is a special 4g network not handled by telephony
-            mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
-            mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g;
-            mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition];
-            mContentDescriptionDataType = mContext.getString(
-                    R.string.accessibility_data_connection_4g);
-        } else {
-            switch (mDataNetType) {
-                case TelephonyManager.NETWORK_TYPE_UNKNOWN:
-                    if (!mShowAtLeastThreeGees) {
-                        mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
-                        mDataTypeIconId = 0;
-                        mQSDataTypeIconId = 0;
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_gprs);
-                        break;
-                    } else {
-                        // fall through
-                    }
-                case TelephonyManager.NETWORK_TYPE_EDGE:
-                    if (!mShowAtLeastThreeGees) {
-                        mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_e;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_E[mInetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_edge);
-                        break;
-                    } else {
-                        // fall through
-                    }
-                case TelephonyManager.NETWORK_TYPE_UMTS:
-                    mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
-                    mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
-                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
-                    mContentDescriptionDataType = mContext.getString(
-                            R.string.accessibility_data_connection_3g);
-                    break;
-                case TelephonyManager.NETWORK_TYPE_HSDPA:
-                case TelephonyManager.NETWORK_TYPE_HSUPA:
-                case TelephonyManager.NETWORK_TYPE_HSPA:
-                case TelephonyManager.NETWORK_TYPE_HSPAP:
-                    if (mHspaDataDistinguishable) {
-                        mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_h;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_H[mInetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_3_5g);
-                    } else {
-                        mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_3g);
-                    }
-                    break;
-                case TelephonyManager.NETWORK_TYPE_CDMA:
-                    if (!mShowAtLeastThreeGees) {
-                        // display 1xRTT for IS95A/B
-                        mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_cdma);
-                        break;
-                    } else {
-                        // fall through
-                    }
-                case TelephonyManager.NETWORK_TYPE_1xRTT:
-                    if (!mShowAtLeastThreeGees) {
-                        mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_cdma);
-                        break;
-                    } else {
-                        // fall through
-                    }
-                case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
-                case TelephonyManager.NETWORK_TYPE_EVDO_A:
-                case TelephonyManager.NETWORK_TYPE_EVDO_B:
-                case TelephonyManager.NETWORK_TYPE_EHRPD:
-                    mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
-                    mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
-                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
-                    mContentDescriptionDataType = mContext.getString(
-                            R.string.accessibility_data_connection_3g);
-                    break;
-                case TelephonyManager.NETWORK_TYPE_LTE:
-                    boolean show4GforLTE = mContext.getResources().getBoolean(R.bool.config_show4GForLTE);
-                    if (show4GforLTE) {
-                        mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_4g);
-                    } else {
-                        mDataIconList = TelephonyIcons.DATA_LTE[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_lte;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_LTE[mInetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_lte);
-                    }
-                    break;
-                default:
-                    if (!mShowAtLeastThreeGees) {
-                        mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_g;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_G[mInetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_gprs);
-                    } else {
-                        mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
-                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
-                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
-                        mContentDescriptionDataType = mContext.getString(
-                                R.string.accessibility_data_connection_3g);
-                    }
-                    break;
-            }
-        }
-
-        if (isCdma()) {
-            if (isCdmaEri()) {
-                mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
-                mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
-            }
-        } else if (mPhone.isNetworkRoaming()) {
-                mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
-                mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
-        }
-    }
-
-    boolean isCdmaEri() {
-        if (mServiceState != null) {
-            final int iconIndex = mServiceState.getCdmaEriIconIndex();
-            if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) {
-                final int iconMode = mServiceState.getCdmaEriIconMode();
-                if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
-                        || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    private final void updateDataIcon() {
-        int iconId;
-        boolean visible = true;
-
-        if (!isCdma()) {
-            // GSM case, we have to check also the sim state
-            if (mSimState == IccCardConstants.State.READY ||
-                    mSimState == IccCardConstants.State.UNKNOWN) {
-                if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
-                    switch (mDataActivity) {
-                        case TelephonyManager.DATA_ACTIVITY_IN:
-                            iconId = mDataIconList[1];
-                            break;
-                        case TelephonyManager.DATA_ACTIVITY_OUT:
-                            iconId = mDataIconList[2];
-                            break;
-                        case TelephonyManager.DATA_ACTIVITY_INOUT:
-                            iconId = mDataIconList[3];
-                            break;
-                        default:
-                            iconId = mDataIconList[0];
-                            break;
-                    }
-                    mDataDirectionIconId = iconId;
-                } else {
-                    iconId = 0;
-                    visible = false;
-                }
-            } else {
-                iconId = R.drawable.stat_sys_no_sim;
-                visible = false; // no SIM? no data
-            }
-        } else {
-            // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
-            if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
-                switch (mDataActivity) {
-                    case TelephonyManager.DATA_ACTIVITY_IN:
-                        iconId = mDataIconList[1];
-                        break;
-                    case TelephonyManager.DATA_ACTIVITY_OUT:
-                        iconId = mDataIconList[2];
-                        break;
-                    case TelephonyManager.DATA_ACTIVITY_INOUT:
-                        iconId = mDataIconList[3];
-                        break;
-                    case TelephonyManager.DATA_ACTIVITY_DORMANT:
-                    default:
-                        iconId = mDataIconList[0];
-                        break;
-                }
-            } else {
-                iconId = 0;
-                visible = false;
-            }
-        }
-
-        mDataDirectionIconId = iconId;
-        mDataConnected = visible;
-    }
-
-    void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
-        if (false) {
-            Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
-                    + " showPlmn=" + showPlmn + " plmn=" + plmn);
-        }
-        StringBuilder str = new StringBuilder();
-        boolean something = false;
-        if (showPlmn && plmn != null) {
-            str.append(plmn);
-            something = true;
-        }
-        if (showSpn && spn != null) {
-            if (something) {
-                str.append(mNetworkNameSeparator);
-            }
-            str.append(spn);
-            something = true;
-        }
-        if (something) {
-            mNetworkName = str.toString();
-        } else {
-            mNetworkName = mNetworkNameDefault;
-        }
-    }
-
-    // ===== 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(TAG, "Failed to connect to wifi");
-                    }
-                    break;
-                case WifiManager.DATA_ACTIVITY_NOTIFICATION:
-                    if (msg.arg1 != mWifiActivity) {
-                        mWifiActivity = msg.arg1;
-                        refreshViews();
-                    }
-                    break;
-                default:
-                    //Ignore
-                    break;
-            }
-        }
-    }
-
-    private void updateWifiState(Intent intent) {
-        final String action = intent.getAction();
-        if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
-            mWifiEnabled = 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);
-            boolean wasConnected = mWifiConnected;
-            mWifiConnected = networkInfo != null && networkInfo.isConnected();
-            // If we just connected, grab the inintial signal strength and ssid
-            if (mWifiConnected && !wasConnected) {
-                // try getting it out of the intent first
-                WifiInfo info = (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
-                if (info == null) {
-                    info = mWifiManager.getConnectionInfo();
-                }
-                if (info != null) {
-                    mWifiSsid = huntForSsid(info);
-                } else {
-                    mWifiSsid = null;
-                }
-            } else if (!mWifiConnected) {
-                mWifiSsid = null;
-            }
-        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
-            mWifiRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
-            mWifiLevel = WifiManager.calculateSignalLevel(
-                    mWifiRssi, WifiIcons.WIFI_LEVEL_COUNT);
-        }
-
-        updateWifiIcons();
-    }
-
-    private void updateWifiIcons() {
-        if (mWifiConnected) {
-            mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
-            mQSWifiIconId = WifiIcons.QS_WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
-            mContentDescriptionWifi = mContext.getString(
-                    AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH[mWifiLevel]);
-        } else {
-            if (mDataAndWifiStacked) {
-                mWifiIconId = 0;
-                mQSWifiIconId = 0;
-            } else {
-                mWifiIconId = mWifiEnabled ? R.drawable.stat_sys_wifi_signal_null : 0;
-                mQSWifiIconId = mWifiEnabled ? R.drawable.ic_qs_wifi_no_network : 0;
-            }
-            mContentDescriptionWifi = mContext.getString(R.string.accessibility_no_wifi);
-        }
-    }
-
-    private String huntForSsid(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();
-        for (WifiConfiguration net : networks) {
-            if (net.networkId == info.getNetworkId()) {
-                return net.SSID;
-            }
-        }
-        return null;
-    }
-
-
-    // ===== Wimax ===================================================================
-    private final void updateWimaxState(Intent intent) {
-        final String action = intent.getAction();
-        boolean wasConnected = mWimaxConnected;
-        if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION)) {
-            int wimaxStatus = intent.getIntExtra(WimaxManagerConstants.EXTRA_4G_STATE,
-                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
-            mIsWimaxEnabled = (wimaxStatus ==
-                    WimaxManagerConstants.NET_4G_STATE_ENABLED);
-        } else if (action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION)) {
-            mWimaxSignal = intent.getIntExtra(WimaxManagerConstants.EXTRA_NEW_SIGNAL_LEVEL, 0);
-        } else if (action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
-            mWimaxState = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATE,
-                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
-            mWimaxExtraState = intent.getIntExtra(
-                    WimaxManagerConstants.EXTRA_WIMAX_STATE_DETAIL,
-                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
-            mWimaxConnected = (mWimaxState ==
-                    WimaxManagerConstants.WIMAX_STATE_CONNECTED);
-            mWimaxIdle = (mWimaxExtraState == WimaxManagerConstants.WIMAX_IDLE);
-        }
-        updateDataNetType();
-        updateWimaxIcons();
-    }
-
-    private void updateWimaxIcons() {
-        if (mIsWimaxEnabled) {
-            if (mWimaxConnected) {
-                if (mWimaxIdle)
-                    mWimaxIconId = WimaxIcons.WIMAX_IDLE;
-                else
-                    mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[mInetCondition][mWimaxSignal];
-                mContentDescriptionWimax = mContext.getString(
-                        AccessibilityContentDescriptions.WIMAX_CONNECTION_STRENGTH[mWimaxSignal]);
-            } else {
-                mWimaxIconId = WimaxIcons.WIMAX_DISCONNECTED;
-                mContentDescriptionWimax = mContext.getString(R.string.accessibility_no_wimax);
-            }
-        } else {
-            mWimaxIconId = 0;
-        }
-    }
-
-    // ===== Full or limited Internet connectivity ==================================
-
-    private void updateConnectivity(Intent intent) {
-        if (CHATTY) {
-            Log.d(TAG, "updateConnectivity: intent=" + intent);
-        }
-
-        final ConnectivityManager connManager = (ConnectivityManager) mContext
-                .getSystemService(Context.CONNECTIVITY_SERVICE);
-        final NetworkInfo info = connManager.getActiveNetworkInfo();
-
-        // Are we connected at all, by any interface?
-        mConnected = info != null && info.isConnected();
-        if (mConnected) {
-            mConnectedNetworkType = info.getType();
-            mConnectedNetworkTypeName = info.getTypeName();
-        } else {
-            mConnectedNetworkType = ConnectivityManager.TYPE_NONE;
-            mConnectedNetworkTypeName = null;
-        }
-
-        int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
-
-        if (CHATTY) {
-            Log.d(TAG, "updateConnectivity: networkInfo=" + info);
-            Log.d(TAG, "updateConnectivity: connectionStatus=" + connectionStatus);
-        }
-
-        mInetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
-
-        if (info != null && info.getType() == ConnectivityManager.TYPE_BLUETOOTH) {
-            mBluetoothTethered = info.isConnected();
-        } else {
-            mBluetoothTethered = false;
-        }
-
-        // We want to update all the icons, all at once, for any condition change
-        updateDataNetType();
-        updateWimaxIcons();
-        updateDataIcon();
-        updateTelephonySignalStrength();
-        updateWifiIcons();
-    }
-
-
-    // ===== Update the views =======================================================
-
-    void refreshViews() {
-        Context context = mContext;
-
-        int combinedSignalIconId = 0;
-        String combinedLabel = "";
-        String wifiLabel = "";
-        String mobileLabel = "";
-        int N;
-        final boolean emergencyOnly = isEmergencyOnly();
-
-        if (!mHasMobileDataFeature) {
-            mDataSignalIconId = mPhoneSignalIconId = 0;
-            mQSPhoneSignalIconId = 0;
-            mobileLabel = "";
-        } else {
-            // 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 (mDataConnected) {
-                mobileLabel = mNetworkName;
-            } else if (mConnected || emergencyOnly) {
-                if (hasService() || emergencyOnly) {
-                    // The isEmergencyOnly test covers the case of a phone with no SIM
-                    mobileLabel = mNetworkName;
-                } else {
-                    // Tablets, basically
-                    mobileLabel = "";
-                }
-            } else {
-                mobileLabel
-                    = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
-            }
-
-            // Now for things that should only be shown when actually using mobile data.
-            if (mDataConnected) {
-                combinedSignalIconId = mDataSignalIconId;
-
-                combinedLabel = mobileLabel;
-                combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon()
-                mContentDescriptionCombinedSignal = mContentDescriptionDataType;
-            }
-        }
-
-        if (mWifiConnected) {
-            if (mWifiSsid == null) {
-                wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid);
-            } else {
-                wifiLabel = mWifiSsid;
-                if (DEBUG) {
-                    wifiLabel += "xxxxXXXXxxxxXXXX";
-                }
-            }
-
-            combinedLabel = wifiLabel;
-            combinedSignalIconId = mWifiIconId; // set by updateWifiIcons()
-            mContentDescriptionCombinedSignal = mContentDescriptionWifi;
-        } else {
-            if (mHasMobileDataFeature) {
-                wifiLabel = "";
-            } else {
-                wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
-            }
-        }
-
-        if (mBluetoothTethered) {
-            combinedLabel = mContext.getString(R.string.bluetooth_tethered);
-            combinedSignalIconId = mBluetoothTetherIconId;
-            mContentDescriptionCombinedSignal = mContext.getString(
-                    R.string.accessibility_bluetooth_tether);
-        }
-
-        final boolean ethernetConnected = (mConnectedNetworkType == ConnectivityManager.TYPE_ETHERNET);
-        if (ethernetConnected) {
-            combinedLabel = context.getString(R.string.ethernet_label);
-        }
-
-        if (mAirplaneMode &&
-                (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) {
-            // Only display the flight-mode icon if not in "emergency calls only" mode.
-
-            // look again; your radios are now airplanes
-            mContentDescriptionPhoneSignal = mContext.getString(
-                    R.string.accessibility_airplane_mode);
-            mAirplaneIconId = FLIGHT_MODE_ICON;
-            mPhoneSignalIconId = mDataSignalIconId = mDataTypeIconId = mQSDataTypeIconId = 0;
-            mQSPhoneSignalIconId = 0;
-
-            // combined values from connected wifi take precedence over airplane mode
-            if (mWifiConnected) {
-                // Suppress "No internet connection." from mobile if wifi connected.
-                mobileLabel = "";
-            } else {
-                if (mHasMobileDataFeature) {
-                    // let the mobile icon show "No internet connection."
-                    wifiLabel = "";
-                } else {
-                    wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
-                    combinedLabel = wifiLabel;
-                }
-                mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal;
-                combinedSignalIconId = mDataSignalIconId;
-            }
-        }
-        else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected && !ethernetConnected) {
-            // pretty much totally disconnected
-
-            combinedLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
-            // On devices without mobile radios, we want to show the wifi icon
-            combinedSignalIconId =
-                mHasMobileDataFeature ? mDataSignalIconId : mWifiIconId;
-            mContentDescriptionCombinedSignal = mHasMobileDataFeature
-                ? mContentDescriptionDataType : mContentDescriptionWifi;
-
-            mDataTypeIconId = 0;
-            mQSDataTypeIconId = 0;
-            if (isCdma()) {
-                if (isCdmaEri()) {
-                    mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
-                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
-                }
-            } else if (mPhone.isNetworkRoaming()) {
-                mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
-                mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
-            }
-        }
-
-        if (DEBUG) {
-            Log.d(TAG, "refreshViews connected={"
-                    + (mWifiConnected?" wifi":"")
-                    + (mDataConnected?" data":"")
-                    + " } level="
-                    + ((mSignalStrength == null)?"??":Integer.toString(mSignalStrength.getLevel()))
-                    + " combinedSignalIconId=0x"
-                    + Integer.toHexString(combinedSignalIconId)
-                    + "/" + getResourceName(combinedSignalIconId)
-                    + " mobileLabel=" + mobileLabel
-                    + " wifiLabel=" + wifiLabel
-                    + " emergencyOnly=" + emergencyOnly
-                    + " combinedLabel=" + combinedLabel
-                    + " mAirplaneMode=" + mAirplaneMode
-                    + " mDataActivity=" + mDataActivity
-                    + " mPhoneSignalIconId=0x" + Integer.toHexString(mPhoneSignalIconId)
-                    + " mQSPhoneSignalIconId=0x" + Integer.toHexString(mQSPhoneSignalIconId)
-                    + " mDataDirectionIconId=0x" + Integer.toHexString(mDataDirectionIconId)
-                    + " mDataSignalIconId=0x" + Integer.toHexString(mDataSignalIconId)
-                    + " mDataTypeIconId=0x" + Integer.toHexString(mDataTypeIconId)
-                    + " mQSDataTypeIconId=0x" + Integer.toHexString(mQSDataTypeIconId)
-                    + " mWifiIconId=0x" + Integer.toHexString(mWifiIconId)
-                    + " mQSWifiIconId=0x" + Integer.toHexString(mQSWifiIconId)
-                    + " mBluetoothTetherIconId=0x" + Integer.toHexString(mBluetoothTetherIconId));
-        }
-
-        // update QS
-        for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) {
-            notifySignalsChangedCallbacks(cb);
-        }
-
-        if (mLastPhoneSignalIconId          != mPhoneSignalIconId
-         || mLastWifiIconId                 != mWifiIconId
-         || mLastInetCondition              != mInetCondition
-         || mLastWimaxIconId                != mWimaxIconId
-         || mLastDataTypeIconId             != mDataTypeIconId
-         || mLastAirplaneMode               != mAirplaneMode
-         || mLastLocale                     != mLocale)
-        {
-            // NB: the mLast*s will be updated later
-            for (SignalCluster cluster : mSignalClusters) {
-                refreshSignalCluster(cluster);
-            }
-        }
-
-        if (mLastAirplaneMode != mAirplaneMode) {
-            mLastAirplaneMode = mAirplaneMode;
-        }
-
-        if (mLastLocale != mLocale) {
-            mLastLocale = mLocale;
-        }
-
-        // the phone icon on phones
-        if (mLastPhoneSignalIconId != mPhoneSignalIconId) {
-            mLastPhoneSignalIconId = mPhoneSignalIconId;
-        }
-
-        // the data icon on phones
-        if (mLastDataDirectionIconId != mDataDirectionIconId) {
-            mLastDataDirectionIconId = mDataDirectionIconId;
-        }
-
-        // the wifi icon on phones
-        if (mLastWifiIconId != mWifiIconId) {
-            mLastWifiIconId = mWifiIconId;
-        }
-
-        if (mLastInetCondition != mInetCondition) {
-            mLastInetCondition = mInetCondition;
-        }
-
-        // the wimax icon on phones
-        if (mLastWimaxIconId != mWimaxIconId) {
-            mLastWimaxIconId = mWimaxIconId;
-        }
-        // the combined data signal icon
-        if (mLastCombinedSignalIconId != combinedSignalIconId) {
-            mLastCombinedSignalIconId = combinedSignalIconId;
-        }
-
-        // the data network type overlay
-        if (mLastDataTypeIconId != mDataTypeIconId) {
-            mLastDataTypeIconId = mDataTypeIconId;
-        }
-
-        // the combinedLabel in the notification panel
-        if (!mLastCombinedLabel.equals(combinedLabel)) {
-            mLastCombinedLabel = combinedLabel;
-            N = mCombinedLabelViews.size();
-            for (int i=0; i<N; i++) {
-                TextView v = mCombinedLabelViews.get(i);
-                v.setText(combinedLabel);
-            }
-        }
-
-        // wifi label
-        N = mWifiLabelViews.size();
-        for (int i=0; i<N; i++) {
-            TextView v = mWifiLabelViews.get(i);
-            v.setText(wifiLabel);
-            if ("".equals(wifiLabel)) {
-                v.setVisibility(View.GONE);
-            } else {
-                v.setVisibility(View.VISIBLE);
-            }
-        }
-
-        // mobile label
-        N = mMobileLabelViews.size();
-        for (int i=0; i<N; i++) {
-            TextView v = mMobileLabelViews.get(i);
-            v.setText(mobileLabel);
-            if ("".equals(mobileLabel)) {
-                v.setVisibility(View.GONE);
-            } else {
-                v.setVisibility(View.VISIBLE);
-            }
-        }
-
-        // e-call label
-        N = mEmergencyLabelViews.size();
-        for (int i=0; i<N; i++) {
-            TextView v = mEmergencyLabelViews.get(i);
-            if (!emergencyOnly) {
-                v.setVisibility(View.GONE);
-            } else {
-                v.setText(mobileLabel); // comes from the telephony stack
-                v.setVisibility(View.VISIBLE);
-            }
-        }
-    }
-
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println("NetworkController state:");
-        pw.println(String.format("  %s network type %d (%s)",
-                mConnected?"CONNECTED":"DISCONNECTED",
-                mConnectedNetworkType, mConnectedNetworkTypeName));
-        pw.println("  - telephony ------");
-        pw.print("  hasVoiceCallingFeature()=");
-        pw.println(hasVoiceCallingFeature());
-        pw.print("  hasService()=");
-        pw.println(hasService());
-        pw.print("  mHspaDataDistinguishable=");
-        pw.println(mHspaDataDistinguishable);
-        pw.print("  mDataConnected=");
-        pw.println(mDataConnected);
-        pw.print("  mSimState=");
-        pw.println(mSimState);
-        pw.print("  mPhoneState=");
-        pw.println(mPhoneState);
-        pw.print("  mDataState=");
-        pw.println(mDataState);
-        pw.print("  mDataActivity=");
-        pw.println(mDataActivity);
-        pw.print("  mDataNetType=");
-        pw.print(mDataNetType);
-        pw.print("/");
-        pw.println(TelephonyManager.getNetworkTypeName(mDataNetType));
-        pw.print("  mServiceState=");
-        pw.println(mServiceState);
-        pw.print("  mSignalStrength=");
-        pw.println(mSignalStrength);
-        pw.print("  mLastSignalLevel=");
-        pw.println(mLastSignalLevel);
-        pw.print("  mNetworkName=");
-        pw.println(mNetworkName);
-        pw.print("  mNetworkNameDefault=");
-        pw.println(mNetworkNameDefault);
-        pw.print("  mNetworkNameSeparator=");
-        pw.println(mNetworkNameSeparator.replace("\n","\\n"));
-        pw.print("  mPhoneSignalIconId=0x");
-        pw.print(Integer.toHexString(mPhoneSignalIconId));
-        pw.print("/");
-        pw.print("  mQSPhoneSignalIconId=0x");
-        pw.print(Integer.toHexString(mQSPhoneSignalIconId));
-        pw.print("/");
-        pw.println(getResourceName(mPhoneSignalIconId));
-        pw.print("  mDataDirectionIconId=");
-        pw.print(Integer.toHexString(mDataDirectionIconId));
-        pw.print("/");
-        pw.println(getResourceName(mDataDirectionIconId));
-        pw.print("  mDataSignalIconId=");
-        pw.print(Integer.toHexString(mDataSignalIconId));
-        pw.print("/");
-        pw.println(getResourceName(mDataSignalIconId));
-        pw.print("  mDataTypeIconId=");
-        pw.print(Integer.toHexString(mDataTypeIconId));
-        pw.print("/");
-        pw.println(getResourceName(mDataTypeIconId));
-        pw.print("  mQSDataTypeIconId=");
-        pw.print(Integer.toHexString(mQSDataTypeIconId));
-        pw.print("/");
-        pw.println(getResourceName(mQSDataTypeIconId));
-
-        pw.println("  - wifi ------");
-        pw.print("  mWifiEnabled=");
-        pw.println(mWifiEnabled);
-        pw.print("  mWifiConnected=");
-        pw.println(mWifiConnected);
-        pw.print("  mWifiRssi=");
-        pw.println(mWifiRssi);
-        pw.print("  mWifiLevel=");
-        pw.println(mWifiLevel);
-        pw.print("  mWifiSsid=");
-        pw.println(mWifiSsid);
-        pw.println(String.format("  mWifiIconId=0x%08x/%s",
-                    mWifiIconId, getResourceName(mWifiIconId)));
-        pw.println(String.format("  mQSWifiIconId=0x%08x/%s",
-                    mQSWifiIconId, getResourceName(mQSWifiIconId)));
-        pw.print("  mWifiActivity=");
-        pw.println(mWifiActivity);
-
-        if (mWimaxSupported) {
-            pw.println("  - wimax ------");
-            pw.print("  mIsWimaxEnabled="); pw.println(mIsWimaxEnabled);
-            pw.print("  mWimaxConnected="); pw.println(mWimaxConnected);
-            pw.print("  mWimaxIdle="); pw.println(mWimaxIdle);
-            pw.println(String.format("  mWimaxIconId=0x%08x/%s",
-                        mWimaxIconId, getResourceName(mWimaxIconId)));
-            pw.println(String.format("  mWimaxSignal=%d", mWimaxSignal));
-            pw.println(String.format("  mWimaxState=%d", mWimaxState));
-            pw.println(String.format("  mWimaxExtraState=%d", mWimaxExtraState));
-        }
-
-        pw.println("  - Bluetooth ----");
-        pw.print("  mBtReverseTethered=");
-        pw.println(mBluetoothTethered);
-
-        pw.println("  - connectivity ------");
-        pw.print("  mInetCondition=");
-        pw.println(mInetCondition);
-
-        pw.println("  - icons ------");
-        pw.print("  mLastPhoneSignalIconId=0x");
-        pw.print(Integer.toHexString(mLastPhoneSignalIconId));
-        pw.print("/");
-        pw.println(getResourceName(mLastPhoneSignalIconId));
-        pw.print("  mLastDataDirectionIconId=0x");
-        pw.print(Integer.toHexString(mLastDataDirectionIconId));
-        pw.print("/");
-        pw.println(getResourceName(mLastDataDirectionIconId));
-        pw.print("  mLastWifiIconId=0x");
-        pw.print(Integer.toHexString(mLastWifiIconId));
-        pw.print("/");
-        pw.println(getResourceName(mLastWifiIconId));
-        pw.print("  mLastCombinedSignalIconId=0x");
-        pw.print(Integer.toHexString(mLastCombinedSignalIconId));
-        pw.print("/");
-        pw.println(getResourceName(mLastCombinedSignalIconId));
-        pw.print("  mLastDataTypeIconId=0x");
-        pw.print(Integer.toHexString(mLastDataTypeIconId));
-        pw.print("/");
-        pw.println(getResourceName(mLastDataTypeIconId));
-        pw.print("  mLastCombinedLabel=");
-        pw.print(mLastCombinedLabel);
-        pw.println("");
-    }
-
-    private String getResourceName(int resId) {
-        if (resId != 0) {
-            final Resources res = mContext.getResources();
-            try {
-                return res.getResourceName(resId);
-            } catch (android.content.res.Resources.NotFoundException ex) {
-                return "(unknown)";
-            }
-        } else {
-            return "(null)";
-        }
-    }
-
-    private boolean mDemoMode;
-    private int mDemoInetCondition;
-    private int mDemoWifiLevel;
-    private int mDemoDataTypeIconId;
-    private int mDemoMobileLevel;
-
-    @Override
-    public void dispatchDemoCommand(String command, Bundle args) {
-        if (!mDemoMode && command.equals(COMMAND_ENTER)) {
-            mDemoMode = true;
-            mDemoWifiLevel = mWifiLevel;
-            mDemoInetCondition = mInetCondition;
-            mDemoDataTypeIconId = mDataTypeIconId;
-            mDemoMobileLevel = mLastSignalLevel;
-        } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
-            mDemoMode = false;
-            for (SignalCluster cluster : mSignalClusters) {
-                refreshSignalCluster(cluster);
-            }
-        } else if (mDemoMode && command.equals(COMMAND_NETWORK)) {
-            String airplane = args.getString("airplane");
-            if (airplane != null) {
-                boolean show = airplane.equals("show");
-                for (SignalCluster cluster : mSignalClusters) {
-                    cluster.setIsAirplaneMode(show, FLIGHT_MODE_ICON);
-                }
-            }
-            String fully = args.getString("fully");
-            if (fully != null) {
-                mDemoInetCondition = Boolean.parseBoolean(fully) ? 1 : 0;
-            }
-            String wifi = args.getString("wifi");
-            if (wifi != null) {
-                boolean show = wifi.equals("show");
-                String level = args.getString("level");
-                if (level != null) {
-                    mDemoWifiLevel = level.equals("null") ? -1
-                            : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1);
-                }
-                int iconId = mDemoWifiLevel < 0 ? R.drawable.stat_sys_wifi_signal_null
-                        : WifiIcons.WIFI_SIGNAL_STRENGTH[mDemoInetCondition][mDemoWifiLevel];
-                for (SignalCluster cluster : mSignalClusters) {
-                    cluster.setWifiIndicators(
-                            show,
-                            iconId,
-                            mDemoInetCondition == 0,
-                            "Demo");
-                }
-            }
-            String mobile = args.getString("mobile");
-            if (mobile != null) {
-                boolean show = mobile.equals("show");
-                String datatype = args.getString("datatype");
-                if (datatype != null) {
-                    mDemoDataTypeIconId =
-                            datatype.equals("1x") ? R.drawable.stat_sys_data_fully_connected_1x :
-                            datatype.equals("3g") ? R.drawable.stat_sys_data_fully_connected_3g :
-                            datatype.equals("4g") ? R.drawable.stat_sys_data_fully_connected_4g :
-                            datatype.equals("e") ? R.drawable.stat_sys_data_fully_connected_e :
-                            datatype.equals("g") ? R.drawable.stat_sys_data_fully_connected_g :
-                            datatype.equals("h") ? R.drawable.stat_sys_data_fully_connected_h :
-                            datatype.equals("lte") ? R.drawable.stat_sys_data_fully_connected_lte :
-                            datatype.equals("roam")
-                                    ? R.drawable.stat_sys_data_fully_connected_roam :
-                            0;
-                }
-                int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH;
-                String level = args.getString("level");
-                if (level != null) {
-                    mDemoMobileLevel = level.equals("null") ? -1
-                            : Math.min(Integer.parseInt(level), icons[0].length - 1);
-                }
-                int iconId = mDemoMobileLevel < 0 ? R.drawable.stat_sys_signal_null :
-                        icons[mDemoInetCondition][mDemoMobileLevel];
-                for (SignalCluster cluster : mSignalClusters) {
-                    cluster.setMobileDataIndicators(
-                            show,
-                            iconId,
-                            mDemoInetCondition == 0,
-                            mDemoDataTypeIconId,
-                            "Demo",
-                            "Demo");
-                }
-            }
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
new file mode 100644
index 0000000..966c0b0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -0,0 +1,1491 @@
+/*
+ * 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.systemui.statusbar.policy;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.net.wimax.WimaxManagerConstants;
+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.TelephonyManager;
+import android.util.Log;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.internal.telephony.IccCardConstants;
+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;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+/** Platform implementation of the network controller. **/
+public class NetworkControllerImpl extends BroadcastReceiver
+        implements NetworkController, DemoMode {
+    // debug
+    static final String TAG = "StatusBar.NetworkController";
+    static final boolean DEBUG = false;
+    static final boolean CHATTY = false; // additional diagnostics, but not logspew
+
+    private static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_signal_flightmode;
+
+    // telephony
+    boolean mHspaDataDistinguishable;
+    final TelephonyManager mPhone;
+    boolean mDataConnected;
+    IccCardConstants.State mSimState = IccCardConstants.State.READY;
+    int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
+    int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+    int mDataState = TelephonyManager.DATA_DISCONNECTED;
+    int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
+    ServiceState mServiceState;
+    SignalStrength mSignalStrength;
+    int[] mDataIconList = TelephonyIcons.DATA_G[0];
+    String mNetworkName;
+    String mNetworkNameDefault;
+    String mNetworkNameSeparator;
+    int mPhoneSignalIconId;
+    int mQSPhoneSignalIconId;
+    int mDataDirectionIconId; // data + data direction on phones
+    int mDataSignalIconId;
+    int mDataTypeIconId;
+    int mQSDataTypeIconId;
+    int mAirplaneIconId;
+    boolean mDataActive;
+    int mLastSignalLevel;
+    boolean mShowPhoneRSSIForData = false;
+    boolean mShowAtLeastThreeGees = false;
+    boolean mAlwaysShowCdmaRssi = false;
+
+    String mContentDescriptionPhoneSignal;
+    String mContentDescriptionWifi;
+    String mContentDescriptionWimax;
+    String mContentDescriptionCombinedSignal;
+    String mContentDescriptionDataType;
+
+    // wifi
+    final WifiManager mWifiManager;
+    AsyncChannel mWifiChannel;
+    boolean mWifiEnabled, mWifiConnected;
+    int mWifiRssi, mWifiLevel;
+    String mWifiSsid;
+    int mWifiIconId = 0;
+    int mQSWifiIconId = 0;
+    int mWifiActivity = WifiManager.DATA_ACTIVITY_NONE;
+
+    // bluetooth
+    private boolean mBluetoothTethered = false;
+    private int mBluetoothTetherIconId =
+        com.android.internal.R.drawable.stat_sys_tether_bluetooth;
+
+    //wimax
+    private boolean mWimaxSupported = false;
+    private boolean mIsWimaxEnabled = false;
+    private boolean mWimaxConnected = false;
+    private boolean mWimaxIdle = false;
+    private int mWimaxIconId = 0;
+    private int mWimaxSignal = 0;
+    private int mWimaxState = 0;
+    private int mWimaxExtraState = 0;
+
+    // data connectivity (regardless of state, can we access the internet?)
+    // state of inet connection - 0 not connected, 100 connected
+    private boolean mConnected = false;
+    private int mConnectedNetworkType = ConnectivityManager.TYPE_NONE;
+    private String mConnectedNetworkTypeName;
+    private int mInetCondition = 0;
+    private int mLastInetCondition = 0;
+    private static final int INET_CONDITION_THRESHOLD = 50;
+
+    private boolean mAirplaneMode = false;
+    private boolean mLastAirplaneMode = true;
+
+    private Locale mLocale = null;
+    private Locale mLastLocale = null;
+
+    // our ui
+    Context mContext;
+    ArrayList<TextView> mCombinedLabelViews = new ArrayList<TextView>();
+    ArrayList<TextView> mMobileLabelViews = new ArrayList<TextView>();
+    ArrayList<TextView> mWifiLabelViews = new ArrayList<TextView>();
+    ArrayList<TextView> mEmergencyLabelViews = new ArrayList<TextView>();
+    ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>();
+    ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks =
+            new ArrayList<NetworkSignalChangedCallback>();
+    int mLastPhoneSignalIconId = -1;
+    int mLastDataDirectionIconId = -1;
+    int mLastWifiIconId = -1;
+    int mLastWimaxIconId = -1;
+    int mLastCombinedSignalIconId = -1;
+    int mLastDataTypeIconId = -1;
+    String mLastCombinedLabel = "";
+
+    private boolean mHasMobileDataFeature;
+
+    boolean mDataAndWifiStacked = false;
+
+    public interface SignalCluster {
+        void setWifiIndicators(boolean visible, int strengthIcon, boolean problem,
+                String contentDescription);
+        void setMobileDataIndicators(boolean visible, int strengthIcon, boolean problem,
+                int typeIcon, String contentDescription, String typeContentDescription);
+        void setIsAirplaneMode(boolean is, int airplaneIcon);
+    }
+
+    /**
+     * Construct this controller object and register for updates.
+     */
+    public NetworkControllerImpl(Context context) {
+        mContext = context;
+        final Resources res = context.getResources();
+
+        ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
+                Context.CONNECTIVITY_SERVICE);
+        mHasMobileDataFeature = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+
+        mShowPhoneRSSIForData = res.getBoolean(R.bool.config_showPhoneRSSIForData);
+        mShowAtLeastThreeGees = res.getBoolean(R.bool.config_showMin3G);
+        mAlwaysShowCdmaRssi = res.getBoolean(
+                com.android.internal.R.bool.config_alwaysUseCdmaRssi);
+
+        // set up the default wifi icon, used when no radios have ever appeared
+        updateWifiIcons();
+        updateWimaxIcons();
+
+        // telephony
+        mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
+        mPhone.listen(mPhoneStateListener,
+                          PhoneStateListener.LISTEN_SERVICE_STATE
+                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
+                        | PhoneStateListener.LISTEN_CALL_STATE
+                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
+                        | PhoneStateListener.LISTEN_DATA_ACTIVITY);
+        mHspaDataDistinguishable = mContext.getResources().getBoolean(
+                R.bool.config_hspa_data_distinguishable);
+        mNetworkNameSeparator = mContext.getString(R.string.status_bar_network_name_separator);
+        mNetworkNameDefault = mContext.getString(
+                com.android.internal.R.string.lockscreen_carrier_default);
+        mNetworkName = mNetworkNameDefault;
+
+        // wifi
+        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+        Handler handler = new WifiHandler();
+        mWifiChannel = new AsyncChannel();
+        Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger();
+        if (wifiMessenger != null) {
+            mWifiChannel.connect(mContext, handler, wifiMessenger);
+        }
+
+        // broadcasts
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
+        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+        filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
+        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+        filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
+        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        mWimaxSupported = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_wimaxEnabled);
+        if(mWimaxSupported) {
+            filter.addAction(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION);
+            filter.addAction(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION);
+            filter.addAction(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION);
+        }
+        context.registerReceiver(this, filter);
+
+        // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
+        updateAirplaneMode();
+
+        mLastLocale = mContext.getResources().getConfiguration().locale;
+    }
+
+    public boolean hasMobileDataFeature() {
+        return mHasMobileDataFeature;
+    }
+
+    public boolean hasVoiceCallingFeature() {
+        return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
+    }
+
+    public boolean isEmergencyOnly() {
+        return (mServiceState != null && mServiceState.isEmergencyOnly());
+    }
+
+    public void addCombinedLabelView(TextView v) {
+        mCombinedLabelViews.add(v);
+    }
+
+    public void addMobileLabelView(TextView v) {
+        mMobileLabelViews.add(v);
+    }
+
+    public void addWifiLabelView(TextView v) {
+        mWifiLabelViews.add(v);
+    }
+
+    public void addEmergencyLabelView(TextView v) {
+        mEmergencyLabelViews.add(v);
+    }
+
+    public void addSignalCluster(SignalCluster cluster) {
+        mSignalClusters.add(cluster);
+        refreshSignalCluster(cluster);
+    }
+
+    public void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) {
+        mSignalsChangedCallbacks.add(cb);
+        notifySignalsChangedCallbacks(cb);
+    }
+
+    public void removeNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) {
+        mSignalsChangedCallbacks.remove(cb);
+    }
+
+    @Override
+    public void setWifiEnabled(final boolean enabled) {
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... args) {
+                // Disable tethering if enabling Wifi
+                final int wifiApState = mWifiManager.getWifiApState();
+                if (enabled && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
+                               (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
+                    mWifiManager.setWifiApEnabled(null, false);
+                }
+
+                mWifiManager.setWifiEnabled(enabled);
+                return null;
+            }
+        }.execute();
+    }
+
+    public void refreshSignalCluster(SignalCluster cluster) {
+        if (mDemoMode) return;
+        cluster.setWifiIndicators(
+                // only show wifi in the cluster if connected or if wifi-only
+                mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature),
+                mWifiIconId,
+                mInetCondition == 0,
+                mContentDescriptionWifi);
+
+        if (mIsWimaxEnabled && mWimaxConnected) {
+            // wimax is special
+            cluster.setMobileDataIndicators(
+                    true,
+                    mAlwaysShowCdmaRssi ? mPhoneSignalIconId : mWimaxIconId,
+                    mInetCondition == 0,
+                    mDataTypeIconId,
+                    mContentDescriptionWimax,
+                    mContentDescriptionDataType);
+        } else {
+            // normal mobile data
+            cluster.setMobileDataIndicators(
+                    mHasMobileDataFeature,
+                    mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId,
+                    mInetCondition == 0,
+                    mDataTypeIconId,
+                    mContentDescriptionPhoneSignal,
+                    mContentDescriptionDataType);
+        }
+        cluster.setIsAirplaneMode(mAirplaneMode, mAirplaneIconId);
+    }
+
+    void notifySignalsChangedCallbacks(NetworkSignalChangedCallback cb) {
+        // only show wifi in the cluster if connected or if wifi-only
+        boolean wifiEnabled = mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature);
+        String wifiDesc = wifiEnabled ?
+                mWifiSsid : null;
+        boolean wifiIn = wifiEnabled && mWifiSsid != null
+                && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT
+                || mWifiActivity == WifiManager.DATA_ACTIVITY_IN);
+        boolean wifiOut = wifiEnabled && mWifiSsid != null
+                && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT
+                || mWifiActivity == WifiManager.DATA_ACTIVITY_OUT);
+        cb.onWifiSignalChanged(wifiEnabled, mQSWifiIconId, wifiIn, wifiOut,
+                mContentDescriptionWifi, wifiDesc);
+
+        boolean mobileIn = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT
+                || mDataActivity == TelephonyManager.DATA_ACTIVITY_IN);
+        boolean mobileOut = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT
+                || mDataActivity == TelephonyManager.DATA_ACTIVITY_OUT);
+        if (isEmergencyOnly()) {
+            cb.onMobileDataSignalChanged(false, mQSPhoneSignalIconId,
+                    mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
+                    mContentDescriptionDataType, null);
+        } else {
+            if (mIsWimaxEnabled && mWimaxConnected) {
+                // Wimax is special
+                cb.onMobileDataSignalChanged(true, mQSPhoneSignalIconId,
+                        mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
+                        mContentDescriptionDataType, mNetworkName);
+            } else {
+                // Normal mobile data
+                cb.onMobileDataSignalChanged(mHasMobileDataFeature, mQSPhoneSignalIconId,
+                        mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
+                        mContentDescriptionDataType, mNetworkName);
+            }
+        }
+        cb.onAirplaneModeChanged(mAirplaneMode);
+    }
+
+    public void setStackedMode(boolean stacked) {
+        mDataAndWifiStacked = true;
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        final String action = intent.getAction();
+        if (action.equals(WifiManager.RSSI_CHANGED_ACTION)
+                || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)
+                || action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+            updateWifiState(intent);
+            refreshViews();
+        } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
+            updateSimState(intent);
+            updateDataIcon();
+            refreshViews();
+        } else 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));
+            refreshViews();
+        } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
+                 action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
+            updateConnectivity(intent);
+            refreshViews();
+        } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
+            refreshLocale();
+            refreshViews();
+        } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
+            refreshLocale();
+            updateAirplaneMode();
+            refreshViews();
+        } else if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION) ||
+                action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION) ||
+                action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
+            updateWimaxState(intent);
+            refreshViews();
+        }
+    }
+
+
+    // ===== Telephony ==============================================================
+
+    PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+        @Override
+        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+            if (DEBUG) {
+                Log.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength +
+                    ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
+            }
+            mSignalStrength = signalStrength;
+            updateTelephonySignalStrength();
+            refreshViews();
+        }
+
+        @Override
+        public void onServiceStateChanged(ServiceState state) {
+            if (DEBUG) {
+                Log.d(TAG, "onServiceStateChanged voiceState=" + state.getVoiceRegState()
+                        + " dataState=" + state.getDataRegState());
+            }
+            mServiceState = state;
+            updateTelephonySignalStrength();
+            updateDataNetType();
+            updateDataIcon();
+            refreshViews();
+        }
+
+        @Override
+        public void onCallStateChanged(int state, String incomingNumber) {
+            if (DEBUG) {
+                Log.d(TAG, "onCallStateChanged state=" + state);
+            }
+            // In cdma, if a voice call is made, RSSI should switch to 1x.
+            if (isCdma()) {
+                updateTelephonySignalStrength();
+                refreshViews();
+            }
+        }
+
+        @Override
+        public void onDataConnectionStateChanged(int state, int networkType) {
+            if (DEBUG) {
+                Log.d(TAG, "onDataConnectionStateChanged: state=" + state
+                        + " type=" + networkType);
+            }
+            mDataState = state;
+            mDataNetType = networkType;
+            updateDataNetType();
+            updateDataIcon();
+            refreshViews();
+        }
+
+        @Override
+        public void onDataActivity(int direction) {
+            if (DEBUG) {
+                Log.d(TAG, "onDataActivity: direction=" + direction);
+            }
+            mDataActivity = direction;
+            updateDataIcon();
+            refreshViews();
+        }
+    };
+
+    private final void updateSimState(Intent intent) {
+        String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
+        if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
+            mSimState = IccCardConstants.State.ABSENT;
+        }
+        else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
+            mSimState = IccCardConstants.State.READY;
+        }
+        else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
+            final String lockedReason =
+                    intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
+            if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
+                mSimState = IccCardConstants.State.PIN_REQUIRED;
+            }
+            else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
+                mSimState = IccCardConstants.State.PUK_REQUIRED;
+            }
+            else {
+                mSimState = IccCardConstants.State.NETWORK_LOCKED;
+            }
+        } else {
+            mSimState = IccCardConstants.State.UNKNOWN;
+        }
+    }
+
+    private boolean isCdma() {
+        return (mSignalStrength != null) && !mSignalStrength.isGsm();
+    }
+
+    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 void updateAirplaneMode() {
+        mAirplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
+            Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
+    }
+
+    private void refreshLocale() {
+        mLocale = mContext.getResources().getConfiguration().locale;
+    }
+
+    private final void updateTelephonySignalStrength() {
+        if (!hasService()) {
+            if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: !hasService()");
+            mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
+            mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
+            mDataSignalIconId = R.drawable.stat_sys_signal_null;
+        } else {
+            if (mSignalStrength == null) {
+                if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: mSignalStrength == null");
+                mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
+                mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
+                mDataSignalIconId = R.drawable.stat_sys_signal_null;
+                mContentDescriptionPhoneSignal = mContext.getString(
+                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0]);
+            } else {
+                int iconLevel;
+                int[] iconList;
+                if (isCdma() && mAlwaysShowCdmaRssi) {
+                    mLastSignalLevel = iconLevel = mSignalStrength.getCdmaLevel();
+                    if(DEBUG) Log.d(TAG, "mAlwaysShowCdmaRssi=" + mAlwaysShowCdmaRssi
+                            + " set to cdmaLevel=" + mSignalStrength.getCdmaLevel()
+                            + " instead of level=" + mSignalStrength.getLevel());
+                } else {
+                    mLastSignalLevel = iconLevel = mSignalStrength.getLevel();
+                }
+
+                if (isCdma()) {
+                    if (isCdmaEri()) {
+                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
+                    } else {
+                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
+                    }
+                } else {
+                    // Though mPhone is a Manager, this call is not an IPC
+                    if (mPhone.isNetworkRoaming()) {
+                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
+                    } else {
+                        iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
+                    }
+                }
+                mPhoneSignalIconId = iconList[iconLevel];
+                mQSPhoneSignalIconId =
+                        TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[mInetCondition][iconLevel];
+                mContentDescriptionPhoneSignal = mContext.getString(
+                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]);
+                mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel];
+            }
+        }
+    }
+
+    private final void updateDataNetType() {
+        if (mIsWimaxEnabled && mWimaxConnected) {
+            // wimax is a special 4g network not handled by telephony
+            mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
+            mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g;
+            mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition];
+            mContentDescriptionDataType = mContext.getString(
+                    R.string.accessibility_data_connection_4g);
+        } else {
+            switch (mDataNetType) {
+                case TelephonyManager.NETWORK_TYPE_UNKNOWN:
+                    if (!mShowAtLeastThreeGees) {
+                        mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
+                        mDataTypeIconId = 0;
+                        mQSDataTypeIconId = 0;
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_gprs);
+                        break;
+                    } else {
+                        // fall through
+                    }
+                case TelephonyManager.NETWORK_TYPE_EDGE:
+                    if (!mShowAtLeastThreeGees) {
+                        mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_e;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_E[mInetCondition];
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_edge);
+                        break;
+                    } else {
+                        // fall through
+                    }
+                case TelephonyManager.NETWORK_TYPE_UMTS:
+                    mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+                    mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
+                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
+                    mContentDescriptionDataType = mContext.getString(
+                            R.string.accessibility_data_connection_3g);
+                    break;
+                case TelephonyManager.NETWORK_TYPE_HSDPA:
+                case TelephonyManager.NETWORK_TYPE_HSUPA:
+                case TelephonyManager.NETWORK_TYPE_HSPA:
+                case TelephonyManager.NETWORK_TYPE_HSPAP:
+                    if (mHspaDataDistinguishable) {
+                        mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_h;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_H[mInetCondition];
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_3_5g);
+                    } else {
+                        mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_3g);
+                    }
+                    break;
+                case TelephonyManager.NETWORK_TYPE_CDMA:
+                    if (!mShowAtLeastThreeGees) {
+                        // display 1xRTT for IS95A/B
+                        mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition];
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_cdma);
+                        break;
+                    } else {
+                        // fall through
+                    }
+                case TelephonyManager.NETWORK_TYPE_1xRTT:
+                    if (!mShowAtLeastThreeGees) {
+                        mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition];
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_cdma);
+                        break;
+                    } else {
+                        // fall through
+                    }
+                case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
+                case TelephonyManager.NETWORK_TYPE_EVDO_A:
+                case TelephonyManager.NETWORK_TYPE_EVDO_B:
+                case TelephonyManager.NETWORK_TYPE_EHRPD:
+                    mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+                    mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
+                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
+                    mContentDescriptionDataType = mContext.getString(
+                            R.string.accessibility_data_connection_3g);
+                    break;
+                case TelephonyManager.NETWORK_TYPE_LTE:
+                    boolean show4GforLTE = mContext.getResources().getBoolean(R.bool.config_show4GForLTE);
+                    if (show4GforLTE) {
+                        mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition];
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_4g);
+                    } else {
+                        mDataIconList = TelephonyIcons.DATA_LTE[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_lte;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_LTE[mInetCondition];
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_lte);
+                    }
+                    break;
+                default:
+                    if (!mShowAtLeastThreeGees) {
+                        mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_g;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_G[mInetCondition];
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_gprs);
+                    } else {
+                        mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+                        mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
+                        mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
+                        mContentDescriptionDataType = mContext.getString(
+                                R.string.accessibility_data_connection_3g);
+                    }
+                    break;
+            }
+        }
+
+        if (isCdma()) {
+            if (isCdmaEri()) {
+                mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
+                mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
+            }
+        } else if (mPhone.isNetworkRoaming()) {
+                mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
+                mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
+        }
+    }
+
+    boolean isCdmaEri() {
+        if (mServiceState != null) {
+            final int iconIndex = mServiceState.getCdmaEriIconIndex();
+            if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) {
+                final int iconMode = mServiceState.getCdmaEriIconMode();
+                if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
+                        || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private final void updateDataIcon() {
+        int iconId;
+        boolean visible = true;
+
+        if (!isCdma()) {
+            // GSM case, we have to check also the sim state
+            if (mSimState == IccCardConstants.State.READY ||
+                    mSimState == IccCardConstants.State.UNKNOWN) {
+                if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
+                    switch (mDataActivity) {
+                        case TelephonyManager.DATA_ACTIVITY_IN:
+                            iconId = mDataIconList[1];
+                            break;
+                        case TelephonyManager.DATA_ACTIVITY_OUT:
+                            iconId = mDataIconList[2];
+                            break;
+                        case TelephonyManager.DATA_ACTIVITY_INOUT:
+                            iconId = mDataIconList[3];
+                            break;
+                        default:
+                            iconId = mDataIconList[0];
+                            break;
+                    }
+                    mDataDirectionIconId = iconId;
+                } else {
+                    iconId = 0;
+                    visible = false;
+                }
+            } else {
+                iconId = R.drawable.stat_sys_no_sim;
+                visible = false; // no SIM? no data
+            }
+        } else {
+            // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
+            if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
+                switch (mDataActivity) {
+                    case TelephonyManager.DATA_ACTIVITY_IN:
+                        iconId = mDataIconList[1];
+                        break;
+                    case TelephonyManager.DATA_ACTIVITY_OUT:
+                        iconId = mDataIconList[2];
+                        break;
+                    case TelephonyManager.DATA_ACTIVITY_INOUT:
+                        iconId = mDataIconList[3];
+                        break;
+                    case TelephonyManager.DATA_ACTIVITY_DORMANT:
+                    default:
+                        iconId = mDataIconList[0];
+                        break;
+                }
+            } else {
+                iconId = 0;
+                visible = false;
+            }
+        }
+
+        mDataDirectionIconId = iconId;
+        mDataConnected = visible;
+    }
+
+    void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
+        if (false) {
+            Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
+                    + " showPlmn=" + showPlmn + " plmn=" + plmn);
+        }
+        StringBuilder str = new StringBuilder();
+        boolean something = false;
+        if (showPlmn && plmn != null) {
+            str.append(plmn);
+            something = true;
+        }
+        if (showSpn && spn != null) {
+            if (something) {
+                str.append(mNetworkNameSeparator);
+            }
+            str.append(spn);
+            something = true;
+        }
+        if (something) {
+            mNetworkName = str.toString();
+        } else {
+            mNetworkName = mNetworkNameDefault;
+        }
+    }
+
+    // ===== 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(TAG, "Failed to connect to wifi");
+                    }
+                    break;
+                case WifiManager.DATA_ACTIVITY_NOTIFICATION:
+                    if (msg.arg1 != mWifiActivity) {
+                        mWifiActivity = msg.arg1;
+                        refreshViews();
+                    }
+                    break;
+                default:
+                    //Ignore
+                    break;
+            }
+        }
+    }
+
+    private void updateWifiState(Intent intent) {
+        final String action = intent.getAction();
+        if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+            mWifiEnabled = 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);
+            boolean wasConnected = mWifiConnected;
+            mWifiConnected = networkInfo != null && networkInfo.isConnected();
+            // If we just connected, grab the inintial signal strength and ssid
+            if (mWifiConnected && !wasConnected) {
+                // try getting it out of the intent first
+                WifiInfo info = (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
+                if (info == null) {
+                    info = mWifiManager.getConnectionInfo();
+                }
+                if (info != null) {
+                    mWifiSsid = huntForSsid(info);
+                } else {
+                    mWifiSsid = null;
+                }
+            } else if (!mWifiConnected) {
+                mWifiSsid = null;
+            }
+        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
+            mWifiRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
+            mWifiLevel = WifiManager.calculateSignalLevel(
+                    mWifiRssi, WifiIcons.WIFI_LEVEL_COUNT);
+        }
+
+        updateWifiIcons();
+    }
+
+    private void updateWifiIcons() {
+        if (mWifiConnected) {
+            mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
+            mQSWifiIconId = WifiIcons.QS_WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
+            mContentDescriptionWifi = mContext.getString(
+                    AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH[mWifiLevel]);
+        } else {
+            if (mDataAndWifiStacked) {
+                mWifiIconId = 0;
+                mQSWifiIconId = 0;
+            } else {
+                mWifiIconId = mWifiEnabled ? R.drawable.stat_sys_wifi_signal_null : 0;
+                mQSWifiIconId = mWifiEnabled ? R.drawable.ic_qs_wifi_no_network : 0;
+            }
+            mContentDescriptionWifi = mContext.getString(R.string.accessibility_no_wifi);
+        }
+    }
+
+    private String huntForSsid(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();
+        for (WifiConfiguration net : networks) {
+            if (net.networkId == info.getNetworkId()) {
+                return net.SSID;
+            }
+        }
+        return null;
+    }
+
+
+    // ===== Wimax ===================================================================
+    private final void updateWimaxState(Intent intent) {
+        final String action = intent.getAction();
+        boolean wasConnected = mWimaxConnected;
+        if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION)) {
+            int wimaxStatus = intent.getIntExtra(WimaxManagerConstants.EXTRA_4G_STATE,
+                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
+            mIsWimaxEnabled = (wimaxStatus ==
+                    WimaxManagerConstants.NET_4G_STATE_ENABLED);
+        } else if (action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION)) {
+            mWimaxSignal = intent.getIntExtra(WimaxManagerConstants.EXTRA_NEW_SIGNAL_LEVEL, 0);
+        } else if (action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
+            mWimaxState = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATE,
+                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
+            mWimaxExtraState = intent.getIntExtra(
+                    WimaxManagerConstants.EXTRA_WIMAX_STATE_DETAIL,
+                    WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
+            mWimaxConnected = (mWimaxState ==
+                    WimaxManagerConstants.WIMAX_STATE_CONNECTED);
+            mWimaxIdle = (mWimaxExtraState == WimaxManagerConstants.WIMAX_IDLE);
+        }
+        updateDataNetType();
+        updateWimaxIcons();
+    }
+
+    private void updateWimaxIcons() {
+        if (mIsWimaxEnabled) {
+            if (mWimaxConnected) {
+                if (mWimaxIdle)
+                    mWimaxIconId = WimaxIcons.WIMAX_IDLE;
+                else
+                    mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[mInetCondition][mWimaxSignal];
+                mContentDescriptionWimax = mContext.getString(
+                        AccessibilityContentDescriptions.WIMAX_CONNECTION_STRENGTH[mWimaxSignal]);
+            } else {
+                mWimaxIconId = WimaxIcons.WIMAX_DISCONNECTED;
+                mContentDescriptionWimax = mContext.getString(R.string.accessibility_no_wimax);
+            }
+        } else {
+            mWimaxIconId = 0;
+        }
+    }
+
+    // ===== Full or limited Internet connectivity ==================================
+
+    private void updateConnectivity(Intent intent) {
+        if (CHATTY) {
+            Log.d(TAG, "updateConnectivity: intent=" + intent);
+        }
+
+        final ConnectivityManager connManager = (ConnectivityManager) mContext
+                .getSystemService(Context.CONNECTIVITY_SERVICE);
+        final NetworkInfo info = connManager.getActiveNetworkInfo();
+
+        // Are we connected at all, by any interface?
+        mConnected = info != null && info.isConnected();
+        if (mConnected) {
+            mConnectedNetworkType = info.getType();
+            mConnectedNetworkTypeName = info.getTypeName();
+        } else {
+            mConnectedNetworkType = ConnectivityManager.TYPE_NONE;
+            mConnectedNetworkTypeName = null;
+        }
+
+        int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
+
+        if (CHATTY) {
+            Log.d(TAG, "updateConnectivity: networkInfo=" + info);
+            Log.d(TAG, "updateConnectivity: connectionStatus=" + connectionStatus);
+        }
+
+        mInetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
+
+        if (info != null && info.getType() == ConnectivityManager.TYPE_BLUETOOTH) {
+            mBluetoothTethered = info.isConnected();
+        } else {
+            mBluetoothTethered = false;
+        }
+
+        // We want to update all the icons, all at once, for any condition change
+        updateDataNetType();
+        updateWimaxIcons();
+        updateDataIcon();
+        updateTelephonySignalStrength();
+        updateWifiIcons();
+    }
+
+
+    // ===== Update the views =======================================================
+
+    void refreshViews() {
+        Context context = mContext;
+
+        int combinedSignalIconId = 0;
+        String combinedLabel = "";
+        String wifiLabel = "";
+        String mobileLabel = "";
+        int N;
+        final boolean emergencyOnly = isEmergencyOnly();
+
+        if (!mHasMobileDataFeature) {
+            mDataSignalIconId = mPhoneSignalIconId = 0;
+            mQSPhoneSignalIconId = 0;
+            mobileLabel = "";
+        } else {
+            // 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 (mDataConnected) {
+                mobileLabel = mNetworkName;
+            } else if (mConnected || emergencyOnly) {
+                if (hasService() || emergencyOnly) {
+                    // The isEmergencyOnly test covers the case of a phone with no SIM
+                    mobileLabel = mNetworkName;
+                } else {
+                    // Tablets, basically
+                    mobileLabel = "";
+                }
+            } else {
+                mobileLabel
+                    = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
+            }
+
+            // Now for things that should only be shown when actually using mobile data.
+            if (mDataConnected) {
+                combinedSignalIconId = mDataSignalIconId;
+
+                combinedLabel = mobileLabel;
+                combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon()
+                mContentDescriptionCombinedSignal = mContentDescriptionDataType;
+            }
+        }
+
+        if (mWifiConnected) {
+            if (mWifiSsid == null) {
+                wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid);
+            } else {
+                wifiLabel = mWifiSsid;
+                if (DEBUG) {
+                    wifiLabel += "xxxxXXXXxxxxXXXX";
+                }
+            }
+
+            combinedLabel = wifiLabel;
+            combinedSignalIconId = mWifiIconId; // set by updateWifiIcons()
+            mContentDescriptionCombinedSignal = mContentDescriptionWifi;
+        } else {
+            if (mHasMobileDataFeature) {
+                wifiLabel = "";
+            } else {
+                wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
+            }
+        }
+
+        if (mBluetoothTethered) {
+            combinedLabel = mContext.getString(R.string.bluetooth_tethered);
+            combinedSignalIconId = mBluetoothTetherIconId;
+            mContentDescriptionCombinedSignal = mContext.getString(
+                    R.string.accessibility_bluetooth_tether);
+        }
+
+        final boolean ethernetConnected = (mConnectedNetworkType == ConnectivityManager.TYPE_ETHERNET);
+        if (ethernetConnected) {
+            combinedLabel = context.getString(R.string.ethernet_label);
+        }
+
+        if (mAirplaneMode &&
+                (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) {
+            // Only display the flight-mode icon if not in "emergency calls only" mode.
+
+            // look again; your radios are now airplanes
+            mContentDescriptionPhoneSignal = mContext.getString(
+                    R.string.accessibility_airplane_mode);
+            mAirplaneIconId = FLIGHT_MODE_ICON;
+            mPhoneSignalIconId = mDataSignalIconId = mDataTypeIconId = mQSDataTypeIconId = 0;
+            mQSPhoneSignalIconId = 0;
+
+            // combined values from connected wifi take precedence over airplane mode
+            if (mWifiConnected) {
+                // Suppress "No internet connection." from mobile if wifi connected.
+                mobileLabel = "";
+            } else {
+                if (mHasMobileDataFeature) {
+                    // let the mobile icon show "No internet connection."
+                    wifiLabel = "";
+                } else {
+                    wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
+                    combinedLabel = wifiLabel;
+                }
+                mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal;
+                combinedSignalIconId = mDataSignalIconId;
+            }
+        }
+        else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected && !ethernetConnected) {
+            // pretty much totally disconnected
+
+            combinedLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
+            // On devices without mobile radios, we want to show the wifi icon
+            combinedSignalIconId =
+                mHasMobileDataFeature ? mDataSignalIconId : mWifiIconId;
+            mContentDescriptionCombinedSignal = mHasMobileDataFeature
+                ? mContentDescriptionDataType : mContentDescriptionWifi;
+
+            mDataTypeIconId = 0;
+            mQSDataTypeIconId = 0;
+            if (isCdma()) {
+                if (isCdmaEri()) {
+                    mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
+                    mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
+                }
+            } else if (mPhone.isNetworkRoaming()) {
+                mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
+                mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
+            }
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "refreshViews connected={"
+                    + (mWifiConnected?" wifi":"")
+                    + (mDataConnected?" data":"")
+                    + " } level="
+                    + ((mSignalStrength == null)?"??":Integer.toString(mSignalStrength.getLevel()))
+                    + " combinedSignalIconId=0x"
+                    + Integer.toHexString(combinedSignalIconId)
+                    + "/" + getResourceName(combinedSignalIconId)
+                    + " mobileLabel=" + mobileLabel
+                    + " wifiLabel=" + wifiLabel
+                    + " emergencyOnly=" + emergencyOnly
+                    + " combinedLabel=" + combinedLabel
+                    + " mAirplaneMode=" + mAirplaneMode
+                    + " mDataActivity=" + mDataActivity
+                    + " mPhoneSignalIconId=0x" + Integer.toHexString(mPhoneSignalIconId)
+                    + " mQSPhoneSignalIconId=0x" + Integer.toHexString(mQSPhoneSignalIconId)
+                    + " mDataDirectionIconId=0x" + Integer.toHexString(mDataDirectionIconId)
+                    + " mDataSignalIconId=0x" + Integer.toHexString(mDataSignalIconId)
+                    + " mDataTypeIconId=0x" + Integer.toHexString(mDataTypeIconId)
+                    + " mQSDataTypeIconId=0x" + Integer.toHexString(mQSDataTypeIconId)
+                    + " mWifiIconId=0x" + Integer.toHexString(mWifiIconId)
+                    + " mQSWifiIconId=0x" + Integer.toHexString(mQSWifiIconId)
+                    + " mBluetoothTetherIconId=0x" + Integer.toHexString(mBluetoothTetherIconId));
+        }
+
+        // update QS
+        for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) {
+            notifySignalsChangedCallbacks(cb);
+        }
+
+        if (mLastPhoneSignalIconId          != mPhoneSignalIconId
+         || mLastWifiIconId                 != mWifiIconId
+         || mLastInetCondition              != mInetCondition
+         || mLastWimaxIconId                != mWimaxIconId
+         || mLastDataTypeIconId             != mDataTypeIconId
+         || mLastAirplaneMode               != mAirplaneMode
+         || mLastLocale                     != mLocale)
+        {
+            // NB: the mLast*s will be updated later
+            for (SignalCluster cluster : mSignalClusters) {
+                refreshSignalCluster(cluster);
+            }
+        }
+
+        if (mLastAirplaneMode != mAirplaneMode) {
+            mLastAirplaneMode = mAirplaneMode;
+        }
+
+        if (mLastLocale != mLocale) {
+            mLastLocale = mLocale;
+        }
+
+        // the phone icon on phones
+        if (mLastPhoneSignalIconId != mPhoneSignalIconId) {
+            mLastPhoneSignalIconId = mPhoneSignalIconId;
+        }
+
+        // the data icon on phones
+        if (mLastDataDirectionIconId != mDataDirectionIconId) {
+            mLastDataDirectionIconId = mDataDirectionIconId;
+        }
+
+        // the wifi icon on phones
+        if (mLastWifiIconId != mWifiIconId) {
+            mLastWifiIconId = mWifiIconId;
+        }
+
+        if (mLastInetCondition != mInetCondition) {
+            mLastInetCondition = mInetCondition;
+        }
+
+        // the wimax icon on phones
+        if (mLastWimaxIconId != mWimaxIconId) {
+            mLastWimaxIconId = mWimaxIconId;
+        }
+        // the combined data signal icon
+        if (mLastCombinedSignalIconId != combinedSignalIconId) {
+            mLastCombinedSignalIconId = combinedSignalIconId;
+        }
+
+        // the data network type overlay
+        if (mLastDataTypeIconId != mDataTypeIconId) {
+            mLastDataTypeIconId = mDataTypeIconId;
+        }
+
+        // the combinedLabel in the notification panel
+        if (!mLastCombinedLabel.equals(combinedLabel)) {
+            mLastCombinedLabel = combinedLabel;
+            N = mCombinedLabelViews.size();
+            for (int i=0; i<N; i++) {
+                TextView v = mCombinedLabelViews.get(i);
+                v.setText(combinedLabel);
+            }
+        }
+
+        // wifi label
+        N = mWifiLabelViews.size();
+        for (int i=0; i<N; i++) {
+            TextView v = mWifiLabelViews.get(i);
+            v.setText(wifiLabel);
+            if ("".equals(wifiLabel)) {
+                v.setVisibility(View.GONE);
+            } else {
+                v.setVisibility(View.VISIBLE);
+            }
+        }
+
+        // mobile label
+        N = mMobileLabelViews.size();
+        for (int i=0; i<N; i++) {
+            TextView v = mMobileLabelViews.get(i);
+            v.setText(mobileLabel);
+            if ("".equals(mobileLabel)) {
+                v.setVisibility(View.GONE);
+            } else {
+                v.setVisibility(View.VISIBLE);
+            }
+        }
+
+        // e-call label
+        N = mEmergencyLabelViews.size();
+        for (int i=0; i<N; i++) {
+            TextView v = mEmergencyLabelViews.get(i);
+            if (!emergencyOnly) {
+                v.setVisibility(View.GONE);
+            } else {
+                v.setText(mobileLabel); // comes from the telephony stack
+                v.setVisibility(View.VISIBLE);
+            }
+        }
+    }
+
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("NetworkController state:");
+        pw.println(String.format("  %s network type %d (%s)",
+                mConnected?"CONNECTED":"DISCONNECTED",
+                mConnectedNetworkType, mConnectedNetworkTypeName));
+        pw.println("  - telephony ------");
+        pw.print("  hasVoiceCallingFeature()=");
+        pw.println(hasVoiceCallingFeature());
+        pw.print("  hasService()=");
+        pw.println(hasService());
+        pw.print("  mHspaDataDistinguishable=");
+        pw.println(mHspaDataDistinguishable);
+        pw.print("  mDataConnected=");
+        pw.println(mDataConnected);
+        pw.print("  mSimState=");
+        pw.println(mSimState);
+        pw.print("  mPhoneState=");
+        pw.println(mPhoneState);
+        pw.print("  mDataState=");
+        pw.println(mDataState);
+        pw.print("  mDataActivity=");
+        pw.println(mDataActivity);
+        pw.print("  mDataNetType=");
+        pw.print(mDataNetType);
+        pw.print("/");
+        pw.println(TelephonyManager.getNetworkTypeName(mDataNetType));
+        pw.print("  mServiceState=");
+        pw.println(mServiceState);
+        pw.print("  mSignalStrength=");
+        pw.println(mSignalStrength);
+        pw.print("  mLastSignalLevel=");
+        pw.println(mLastSignalLevel);
+        pw.print("  mNetworkName=");
+        pw.println(mNetworkName);
+        pw.print("  mNetworkNameDefault=");
+        pw.println(mNetworkNameDefault);
+        pw.print("  mNetworkNameSeparator=");
+        pw.println(mNetworkNameSeparator.replace("\n","\\n"));
+        pw.print("  mPhoneSignalIconId=0x");
+        pw.print(Integer.toHexString(mPhoneSignalIconId));
+        pw.print("/");
+        pw.print("  mQSPhoneSignalIconId=0x");
+        pw.print(Integer.toHexString(mQSPhoneSignalIconId));
+        pw.print("/");
+        pw.println(getResourceName(mPhoneSignalIconId));
+        pw.print("  mDataDirectionIconId=");
+        pw.print(Integer.toHexString(mDataDirectionIconId));
+        pw.print("/");
+        pw.println(getResourceName(mDataDirectionIconId));
+        pw.print("  mDataSignalIconId=");
+        pw.print(Integer.toHexString(mDataSignalIconId));
+        pw.print("/");
+        pw.println(getResourceName(mDataSignalIconId));
+        pw.print("  mDataTypeIconId=");
+        pw.print(Integer.toHexString(mDataTypeIconId));
+        pw.print("/");
+        pw.println(getResourceName(mDataTypeIconId));
+        pw.print("  mQSDataTypeIconId=");
+        pw.print(Integer.toHexString(mQSDataTypeIconId));
+        pw.print("/");
+        pw.println(getResourceName(mQSDataTypeIconId));
+
+        pw.println("  - wifi ------");
+        pw.print("  mWifiEnabled=");
+        pw.println(mWifiEnabled);
+        pw.print("  mWifiConnected=");
+        pw.println(mWifiConnected);
+        pw.print("  mWifiRssi=");
+        pw.println(mWifiRssi);
+        pw.print("  mWifiLevel=");
+        pw.println(mWifiLevel);
+        pw.print("  mWifiSsid=");
+        pw.println(mWifiSsid);
+        pw.println(String.format("  mWifiIconId=0x%08x/%s",
+                    mWifiIconId, getResourceName(mWifiIconId)));
+        pw.println(String.format("  mQSWifiIconId=0x%08x/%s",
+                    mQSWifiIconId, getResourceName(mQSWifiIconId)));
+        pw.print("  mWifiActivity=");
+        pw.println(mWifiActivity);
+
+        if (mWimaxSupported) {
+            pw.println("  - wimax ------");
+            pw.print("  mIsWimaxEnabled="); pw.println(mIsWimaxEnabled);
+            pw.print("  mWimaxConnected="); pw.println(mWimaxConnected);
+            pw.print("  mWimaxIdle="); pw.println(mWimaxIdle);
+            pw.println(String.format("  mWimaxIconId=0x%08x/%s",
+                        mWimaxIconId, getResourceName(mWimaxIconId)));
+            pw.println(String.format("  mWimaxSignal=%d", mWimaxSignal));
+            pw.println(String.format("  mWimaxState=%d", mWimaxState));
+            pw.println(String.format("  mWimaxExtraState=%d", mWimaxExtraState));
+        }
+
+        pw.println("  - Bluetooth ----");
+        pw.print("  mBtReverseTethered=");
+        pw.println(mBluetoothTethered);
+
+        pw.println("  - connectivity ------");
+        pw.print("  mInetCondition=");
+        pw.println(mInetCondition);
+
+        pw.println("  - icons ------");
+        pw.print("  mLastPhoneSignalIconId=0x");
+        pw.print(Integer.toHexString(mLastPhoneSignalIconId));
+        pw.print("/");
+        pw.println(getResourceName(mLastPhoneSignalIconId));
+        pw.print("  mLastDataDirectionIconId=0x");
+        pw.print(Integer.toHexString(mLastDataDirectionIconId));
+        pw.print("/");
+        pw.println(getResourceName(mLastDataDirectionIconId));
+        pw.print("  mLastWifiIconId=0x");
+        pw.print(Integer.toHexString(mLastWifiIconId));
+        pw.print("/");
+        pw.println(getResourceName(mLastWifiIconId));
+        pw.print("  mLastCombinedSignalIconId=0x");
+        pw.print(Integer.toHexString(mLastCombinedSignalIconId));
+        pw.print("/");
+        pw.println(getResourceName(mLastCombinedSignalIconId));
+        pw.print("  mLastDataTypeIconId=0x");
+        pw.print(Integer.toHexString(mLastDataTypeIconId));
+        pw.print("/");
+        pw.println(getResourceName(mLastDataTypeIconId));
+        pw.print("  mLastCombinedLabel=");
+        pw.print(mLastCombinedLabel);
+        pw.println("");
+    }
+
+    private String getResourceName(int resId) {
+        if (resId != 0) {
+            final Resources res = mContext.getResources();
+            try {
+                return res.getResourceName(resId);
+            } catch (android.content.res.Resources.NotFoundException ex) {
+                return "(unknown)";
+            }
+        } else {
+            return "(null)";
+        }
+    }
+
+    private boolean mDemoMode;
+    private int mDemoInetCondition;
+    private int mDemoWifiLevel;
+    private int mDemoDataTypeIconId;
+    private int mDemoMobileLevel;
+
+    @Override
+    public void dispatchDemoCommand(String command, Bundle args) {
+        if (!mDemoMode && command.equals(COMMAND_ENTER)) {
+            mDemoMode = true;
+            mDemoWifiLevel = mWifiLevel;
+            mDemoInetCondition = mInetCondition;
+            mDemoDataTypeIconId = mDataTypeIconId;
+            mDemoMobileLevel = mLastSignalLevel;
+        } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
+            mDemoMode = false;
+            for (SignalCluster cluster : mSignalClusters) {
+                refreshSignalCluster(cluster);
+            }
+        } else if (mDemoMode && command.equals(COMMAND_NETWORK)) {
+            String airplane = args.getString("airplane");
+            if (airplane != null) {
+                boolean show = airplane.equals("show");
+                for (SignalCluster cluster : mSignalClusters) {
+                    cluster.setIsAirplaneMode(show, FLIGHT_MODE_ICON);
+                }
+            }
+            String fully = args.getString("fully");
+            if (fully != null) {
+                mDemoInetCondition = Boolean.parseBoolean(fully) ? 1 : 0;
+            }
+            String wifi = args.getString("wifi");
+            if (wifi != null) {
+                boolean show = wifi.equals("show");
+                String level = args.getString("level");
+                if (level != null) {
+                    mDemoWifiLevel = level.equals("null") ? -1
+                            : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1);
+                }
+                int iconId = mDemoWifiLevel < 0 ? R.drawable.stat_sys_wifi_signal_null
+                        : WifiIcons.WIFI_SIGNAL_STRENGTH[mDemoInetCondition][mDemoWifiLevel];
+                for (SignalCluster cluster : mSignalClusters) {
+                    cluster.setWifiIndicators(
+                            show,
+                            iconId,
+                            mDemoInetCondition == 0,
+                            "Demo");
+                }
+            }
+            String mobile = args.getString("mobile");
+            if (mobile != null) {
+                boolean show = mobile.equals("show");
+                String datatype = args.getString("datatype");
+                if (datatype != null) {
+                    mDemoDataTypeIconId =
+                            datatype.equals("1x") ? R.drawable.stat_sys_data_fully_connected_1x :
+                            datatype.equals("3g") ? R.drawable.stat_sys_data_fully_connected_3g :
+                            datatype.equals("4g") ? R.drawable.stat_sys_data_fully_connected_4g :
+                            datatype.equals("e") ? R.drawable.stat_sys_data_fully_connected_e :
+                            datatype.equals("g") ? R.drawable.stat_sys_data_fully_connected_g :
+                            datatype.equals("h") ? R.drawable.stat_sys_data_fully_connected_h :
+                            datatype.equals("lte") ? R.drawable.stat_sys_data_fully_connected_lte :
+                            datatype.equals("roam")
+                                    ? R.drawable.stat_sys_data_fully_connected_roam :
+                            0;
+                }
+                int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH;
+                String level = args.getString("level");
+                if (level != null) {
+                    mDemoMobileLevel = level.equals("null") ? -1
+                            : Math.min(Integer.parseInt(level), icons[0].length - 1);
+                }
+                int iconId = mDemoMobileLevel < 0 ? R.drawable.stat_sys_signal_null :
+                        icons[mDemoInetCondition][mDemoMobileLevel];
+                for (SignalCluster cluster : mSignalClusters) {
+                    cluster.setMobileDataIndicators(
+                            show,
+                            iconId,
+                            mDemoInetCondition == 0,
+                            mDemoDataTypeIconId,
+                            "Demo",
+                            "Demo");
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
index 98d205a..1eb678d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 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.
@@ -16,65 +16,15 @@
 
 package com.android.systemui.statusbar.policy;
 
-import android.content.Context;
-import android.content.res.Configuration;
-import android.os.UserHandle;
-
-import com.android.internal.view.RotationPolicy;
-
-import java.util.concurrent.CopyOnWriteArrayList;
-
-public final class RotationLockController {
-    private final Context mContext;
-    private final CopyOnWriteArrayList<RotationLockControllerCallback> mCallbacks =
-            new CopyOnWriteArrayList<RotationLockControllerCallback>();
-
-    private final RotationPolicy.RotationPolicyListener mRotationPolicyListener =
-            new RotationPolicy.RotationPolicyListener() {
-        @Override
-        public void onChange() {
-            notifyChanged();
-        }
-    };
+public interface RotationLockController extends Disposable {
+    int getRotationLockOrientation();
+    boolean isRotationLockAffordanceVisible();
+    boolean isRotationLocked();
+    void setRotationLocked(boolean locked);
+    void addRotationLockControllerCallback(RotationLockControllerCallback callback);
+    void removeRotationLockControllerCallback(RotationLockControllerCallback callback);
 
     public interface RotationLockControllerCallback {
-        public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible);
-    }
-
-    public RotationLockController(Context context) {
-        mContext = context;
-        RotationPolicy.registerRotationPolicyListener(mContext,
-                mRotationPolicyListener, UserHandle.USER_ALL);
-    }
-
-    public void addRotationLockControllerCallback(RotationLockControllerCallback callback) {
-        mCallbacks.add(callback);
-    }
-
-    public int getRotationLockOrientation() {
-        return RotationPolicy.getRotationLockOrientation(mContext);
-    }
-
-    public boolean isRotationLocked() {
-        return RotationPolicy.isRotationLocked(mContext);
-    }
-
-    public void setRotationLocked(boolean locked) {
-        RotationPolicy.setRotationLock(mContext, locked);
-    }
-
-    public boolean isRotationLockAffordanceVisible() {
-        return RotationPolicy.isRotationLockToggleVisible(mContext);
-    }
-
-    public void release() {
-        RotationPolicy.unregisterRotationPolicyListener(mContext, mRotationPolicyListener);
-    }
-
-    private void notifyChanged() {
-        for (RotationLockControllerCallback callback : mCallbacks) {
-            callback.onRotationLockStateChanged(RotationPolicy.isRotationLocked(mContext),
-                    RotationPolicy.isRotationLockToggleVisible(mContext));
-        }
+        void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
new file mode 100644
index 0000000..caa07ef
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
@@ -0,0 +1,81 @@
+/*
+ * 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.systemui.statusbar.policy;
+
+import android.content.Context;
+import android.os.UserHandle;
+
+import com.android.internal.view.RotationPolicy;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/** Platform implementation of the rotation lock controller. **/
+public final class RotationLockControllerImpl implements RotationLockController {
+    private final Context mContext;
+    private final CopyOnWriteArrayList<RotationLockControllerCallback> mCallbacks =
+            new CopyOnWriteArrayList<RotationLockControllerCallback>();
+
+    private final RotationPolicy.RotationPolicyListener mRotationPolicyListener =
+            new RotationPolicy.RotationPolicyListener() {
+        @Override
+        public void onChange() {
+            notifyChanged();
+        }
+    };
+
+    public RotationLockControllerImpl(Context context) {
+        mContext = context;
+        RotationPolicy.registerRotationPolicyListener(mContext,
+                mRotationPolicyListener, UserHandle.USER_ALL);
+    }
+
+    public void addRotationLockControllerCallback(RotationLockControllerCallback callback) {
+        mCallbacks.add(callback);
+    }
+
+    public void removeRotationLockControllerCallback(RotationLockControllerCallback callback) {
+        mCallbacks.remove(callback);
+    }
+
+    public int getRotationLockOrientation() {
+        return RotationPolicy.getRotationLockOrientation(mContext);
+    }
+
+    public boolean isRotationLocked() {
+        return RotationPolicy.isRotationLocked(mContext);
+    }
+
+    public void setRotationLocked(boolean locked) {
+        RotationPolicy.setRotationLock(mContext, locked);
+    }
+
+    public boolean isRotationLockAffordanceVisible() {
+        return RotationPolicy.isRotationLockToggleVisible(mContext);
+    }
+
+    @Override
+    public void dispose() {
+        RotationPolicy.unregisterRotationPolicyListener(mContext, mRotationPolicyListener);
+    }
+
+    private void notifyChanged() {
+        for (RotationLockControllerCallback callback : mCallbacks) {
+            callback.onRotationLockStateChanged(RotationPolicy.isRotationLocked(mContext),
+                    RotationPolicy.isRotationLockToggleVisible(mContext));
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TetheringController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TetheringController.java
new file mode 100644
index 0000000..143ebaa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TetheringController.java
@@ -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 com.android.systemui.statusbar.policy;
+
+public interface TetheringController {
+    void addCallback(Callback callback);
+    void removeCallback(Callback callback);
+    boolean isHotspotEnabled();
+    boolean isHotspotSupported();
+
+    public interface Callback {
+        void onHotspotChanged(boolean hotspot);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
new file mode 100644
index 0000000..173af40
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.app.ActivityManagerNative;
+import android.bluetooth.BluetoothAdapter;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.hardware.display.DisplayManager;
+import android.os.AsyncTask;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.ContactsContract;
+import android.security.KeyChain;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.internal.view.RotationPolicy;
+import com.android.systemui.R;
+
+import java.util.ArrayList;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+public final class UserInfoController {
+
+    private static final String TAG = "UserInfoController";
+
+    private final Context mContext;
+    private final ArrayList<OnUserInfoChangedListener> mCallbacks =
+            new ArrayList<OnUserInfoChangedListener>();
+    private AsyncTask<Void, Void, Pair<String, Drawable>> mUserInfoTask;
+
+    private boolean mUseDefaultAvatar;
+    private String mUserName;
+    private Drawable mUserDrawable;
+
+    public UserInfoController(Context context) {
+        mContext = context;
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_USER_SWITCHED);
+        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+        mContext.registerReceiver(mReceiver, filter);
+
+        IntentFilter profileFilter = new IntentFilter();
+        profileFilter.addAction(ContactsContract.Intents.ACTION_PROFILE_CHANGED);
+        profileFilter.addAction(Intent.ACTION_USER_INFO_CHANGED);
+        mContext.registerReceiverAsUser(mProfileReceiver, UserHandle.ALL, profileFilter,
+                null, null);
+    }
+
+    public void addListener(OnUserInfoChangedListener callback) {
+        mCallbacks.add(callback);
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                reloadUserInfo();
+            } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
+                if (mUseDefaultAvatar) {
+                    reloadUserInfo();
+                }
+            }
+        }
+    };
+
+    private final BroadcastReceiver mProfileReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (ContactsContract.Intents.ACTION_PROFILE_CHANGED.equals(action) ||
+                    Intent.ACTION_USER_INFO_CHANGED.equals(action)) {
+                try {
+                    final int currentUser = ActivityManagerNative.getDefault().getCurrentUser().id;
+                    final int changedUser =
+                            intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId());
+                    if (changedUser == currentUser) {
+                        reloadUserInfo();
+                    }
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Couldn't get current user id for profile change", e);
+                }
+            }
+        }
+    };
+
+    public void reloadUserInfo() {
+        if (mUserInfoTask != null) {
+            mUserInfoTask.cancel(false);
+            mUserInfoTask = null;
+        }
+        queryForUserInformation();
+    }
+
+    private Bitmap circularClip(Bitmap input) {
+        Bitmap output = Bitmap.createBitmap(input.getWidth(),
+                input.getHeight(), Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(output);
+        final Paint paint = new Paint();
+        paint.setShader(new BitmapShader(input, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
+        paint.setAntiAlias(true);
+        canvas.drawCircle(input.getWidth() / 2, input.getHeight() / 2, input.getWidth() / 2, paint);
+        return output;
+    }
+
+    private void queryForUserInformation() {
+        Context currentUserContext;
+        UserInfo userInfo;
+        try {
+            userInfo = ActivityManagerNative.getDefault().getCurrentUser();
+            currentUserContext = mContext.createPackageContextAsUser("android", 0,
+                    new UserHandle(userInfo.id));
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.e(TAG, "Couldn't create user context", e);
+            throw new RuntimeException(e);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Couldn't get user info", e);
+            throw new RuntimeException(e);
+        }
+        final int userId = userInfo.id;
+        final String userName = userInfo.name;
+
+        final Context context = currentUserContext;
+        mUserInfoTask = new AsyncTask<Void, Void, Pair<String, Drawable>>() {
+            @Override
+            protected Pair<String, Drawable> doInBackground(Void... params) {
+                final UserManager um = UserManager.get(mContext);
+
+                // Fall back to the UserManager nickname if we can't read the name from the local
+                // profile below.
+                String name = userName;
+                Drawable avatar = null;
+                Bitmap rawAvatar = um.getUserIcon(userId);
+                if (rawAvatar != null) {
+                    avatar = new BitmapDrawable(mContext.getResources(), circularClip(rawAvatar));
+                } else {
+                    avatar = mContext.getResources().getDrawable(R.drawable.ic_qs_default_user);
+                    mUseDefaultAvatar = true;
+                }
+
+                // If it's a single-user device, get the profile name, since the nickname is not
+                // usually valid
+                if (um.getUsers().size() <= 1) {
+                    // Try and read the display name from the local profile
+                    final Cursor cursor = context.getContentResolver().query(
+                            ContactsContract.Profile.CONTENT_URI, new String[] {
+                            ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME},
+                            null, null, null);
+                    if (cursor != null) {
+                        try {
+                            if (cursor.moveToFirst()) {
+                                name = cursor.getString(cursor.getColumnIndex(
+                                        ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
+                            }
+                        } finally {
+                            cursor.close();
+                        }
+                    }
+                }
+                return new Pair<String, Drawable>(name, avatar);
+            }
+
+            @Override
+            protected void onPostExecute(Pair<String, Drawable> result) {
+                mUserName = result.first;
+                mUserDrawable = result.second;
+                mUserInfoTask = null;
+                notifyChanged();
+            }
+        };
+        mUserInfoTask.execute();
+    }
+
+    private void notifyChanged() {
+        for (OnUserInfoChangedListener listener : mCallbacks) {
+            listener.onUserInfoChanged(mUserName, mUserDrawable);
+        }
+    }
+
+    public interface OnUserInfoChangedListener {
+        public void onUserInfoChanged(String name, Drawable picture);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
new file mode 100644
index 0000000..6225c12
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.service.notification.Condition;
+
+public interface ZenModeController {
+    void addCallback(Callback callback);
+    void removeCallback(Callback callback);
+    void setZen(boolean zen);
+    boolean isZen();
+    void requestConditions(boolean request);
+    void select(Condition condition);
+
+    public static class Callback {
+        public void onZenChanged(boolean zen) {}
+        public void onConditionsChanged(Condition[] conditions) {}
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
new file mode 100644
index 0000000..d760f78
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.app.INotificationManager;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings.Global;
+import android.service.notification.Condition;
+import android.service.notification.IConditionListener;
+import android.util.Slog;
+
+import com.android.systemui.qs.GlobalSetting;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+
+/** Platform implementation of the zen mode controller. **/
+public class ZenModeControllerImpl implements ZenModeController {
+    private static final String TAG = "ZenModeControllerImpl";
+
+    private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
+    private final Context mContext;
+    private final GlobalSetting mSetting;
+    private final INotificationManager mNoMan;
+    private final LinkedHashMap<Uri, Condition> mConditions = new LinkedHashMap<Uri, Condition>();
+
+    private boolean mRequesting;
+
+    public ZenModeControllerImpl(Context context, Handler handler) {
+        mContext = context;
+        mSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE) {
+            @Override
+            protected void handleValueChanged(int value) {
+                fireZenChanged(value != 0);
+            }
+        };
+        mNoMan = INotificationManager.Stub.asInterface(
+                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+    }
+
+    @Override
+    public void addCallback(Callback callback) {
+        mCallbacks.add(callback);
+    }
+
+    @Override
+    public void removeCallback(Callback callback) {
+        mCallbacks.remove(callback);
+    }
+
+    @Override
+    public boolean isZen() {
+        return mSetting.getValue() != 0;
+    }
+
+    @Override
+    public void setZen(boolean zen) {
+        mSetting.setValue(zen ? 1 : 0);
+    }
+
+    @Override
+    public void requestConditions(boolean request) {
+        mRequesting = request;
+        try {
+            mNoMan.requestZenModeConditions(mListener, request ? Condition.FLAG_RELEVANT_NOW : 0);
+        } catch (RemoteException e) {
+            // noop
+        }
+        if (!mRequesting) {
+            mConditions.clear();
+        }
+    }
+
+    @Override
+    public void select(Condition condition) {
+        try {
+            mNoMan.setZenModeCondition(condition == null ? null : condition.id);
+        } catch (RemoteException e) {
+            // noop
+        }
+    }
+
+    private void fireZenChanged(boolean zen) {
+        for (Callback cb : mCallbacks) {
+            cb.onZenChanged(zen);
+        }
+    }
+
+    private void fireConditionsChanged(Condition[] conditions) {
+        for (Callback cb : mCallbacks) {
+            cb.onConditionsChanged(conditions);
+        }
+    }
+
+    private void updateConditions(Condition[] conditions) {
+        if (conditions == null || conditions.length == 0) return;
+        for (Condition c : conditions) {
+            if ((c.flags & Condition.FLAG_RELEVANT_NOW) == 0) continue;
+            mConditions.put(c.id, c);
+        }
+        fireConditionsChanged(
+                mConditions.values().toArray(new Condition[mConditions.values().size()]));
+    }
+
+    private final IConditionListener mListener = new IConditionListener.Stub() {
+        @Override
+        public void onConditionsReceived(Condition[] conditions) {
+            Slog.d(TAG, "onConditionsReceived " + (conditions == null ? 0 : conditions.length)
+                    + " mRequesting=" + mRequesting); 
+            if (!mRequesting) return;
+            updateConditions(conditions);
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
new file mode 100644
index 0000000..deab757
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.stack;
+
+import android.view.View;
+
+import java.util.ArrayList;
+
+/**
+ * A global state to track all input states for the algorithm.
+ */
+public class AmbientState {
+    private ArrayList<View> mDraggedViews = new ArrayList<View>();
+    private int mScrollY;
+    private boolean mDimmed;
+    private View mActivatedChild;
+    private float mOverScrollTopAmount;
+    private float mOverScrollBottomAmount;
+
+    public int getScrollY() {
+        return mScrollY;
+    }
+
+    public void setScrollY(int scrollY) {
+        this.mScrollY = scrollY;
+    }
+
+    public void onBeginDrag(View view) {
+        mDraggedViews.add(view);
+    }
+
+    public void onDragFinished(View view) {
+        mDraggedViews.remove(view);
+    }
+
+    public ArrayList<View> getDraggedViews() {
+        return mDraggedViews;
+    }
+
+    /**
+     * @param dimmed Whether we are in a dimmed state (on the lockscreen), where the backgrounds are
+     *               translucent and everything is scaled back a bit.
+     */
+    public void setDimmed(boolean dimmed) {
+        mDimmed = dimmed;
+    }
+
+    /**
+     * In dimmed mode, a child can be activated, which happens on the first tap of the double-tap
+     * interaction. This child is then scaled normally and its background is fully opaque.
+     */
+    public void setActivatedChild(View activatedChild) {
+        mActivatedChild = activatedChild;
+    }
+
+    public boolean isDimmed() {
+        return mDimmed;
+    }
+
+    public View getActivatedChild() {
+        return mActivatedChild;
+    }
+
+    public void setOverScrollAmount(float amount, boolean onTop) {
+        if (onTop) {
+            mOverScrollTopAmount = amount;
+        } else {
+            mOverScrollBottomAmount = amount;
+        }
+    }
+
+    public float getOverScrollAmount(boolean top) {
+        return top ? mOverScrollTopAmount : mOverScrollBottomAmount;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
new file mode 100644
index 0000000..41914ed
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.stack;
+
+import java.util.ArrayList;
+
+/**
+ * Filters the animations for only a certain type of properties.
+ */
+public class AnimationFilter {
+    boolean animateAlpha;
+    boolean animateY;
+    boolean animateZ;
+    boolean animateScale;
+    boolean animateHeight;
+    boolean animateDimmed;
+
+    public AnimationFilter animateAlpha() {
+        animateAlpha = true;
+        return this;
+    }
+
+    public AnimationFilter animateY() {
+        animateY = true;
+        return this;
+    }
+
+    public AnimationFilter animateZ() {
+        animateZ = true;
+        return this;
+    }
+
+    public AnimationFilter animateScale() {
+        animateScale = true;
+        return this;
+    }
+
+    public AnimationFilter animateHeight() {
+        animateHeight = true;
+        return this;
+    }
+
+    public AnimationFilter animateDimmed() {
+        animateDimmed = true;
+        return this;
+    }
+
+    /**
+     * Combines multiple filters into {@code this} filter, using or as the operand .
+     *
+     * @param events The animation events from the filters to combine.
+     */
+    public void applyCombination(ArrayList<NotificationStackScrollLayout.AnimationEvent> events) {
+        reset();
+        int size = events.size();
+        for (int i = 0; i < size; i++) {
+            combineFilter(events.get(i).filter);
+        }
+    }
+
+    private void combineFilter(AnimationFilter filter) {
+        animateAlpha |= filter.animateAlpha;
+        animateY |= filter.animateY;
+        animateZ |= filter.animateZ;
+        animateScale |= filter.animateScale;
+        animateHeight |= filter.animateHeight;
+        animateDimmed |= filter.animateDimmed;
+    }
+
+    private void reset() {
+        animateAlpha = false;
+        animateY = false;
+        animateZ = false;
+        animateScale = false;
+        animateHeight = false;
+        animateDimmed = false;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 9a43e37..fbb6695 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -53,6 +53,7 @@
 
     private static final String TAG = "NotificationStackScrollLayout";
     private static final boolean DEBUG = false;
+    private static final float RUBBER_BAND_FACTOR = 0.35f;
 
     /**
      * Sentinel value for no current active pointer. Used by {@link #mActivePointerId}.
@@ -70,8 +71,8 @@
     private int mTouchSlop;
     private int mMinimumVelocity;
     private int mMaximumVelocity;
-    private int mOverscrollDistance;
     private int mOverflingDistance;
+    private float mMaxOverScroll;
     private boolean mIsBeingDragged;
     private int mLastMotionY;
     private int mActivePointerId;
@@ -80,11 +81,13 @@
     private Paint mDebugPaint;
     private int mContentHeight;
     private int mCollapsedSize;
+    private int mBottomStackSlowDownHeight;
     private int mBottomStackPeekSize;
     private int mEmptyMarginBottom;
     private int mPaddingBetweenElements;
+    private int mPaddingBetweenElementsDimmed;
+    private int mPaddingBetweenElementsNormal;
     private int mTopPadding;
-    private boolean mListenForHeightChanges = true;
 
     /**
      * The algorithm which calculates the properties for our children
@@ -95,23 +98,40 @@
      * The current State this Layout is in
      */
     private StackScrollState mCurrentStackScrollState = new StackScrollState(this);
+    private AmbientState mAmbientState = new AmbientState();
     private ArrayList<View> mChildrenToAddAnimated = new ArrayList<View>();
     private ArrayList<View> mChildrenToRemoveAnimated = new ArrayList<View>();
-    private ArrayList<ChildHierarchyChangeEvent> mAnimationEvents
-            = new ArrayList<ChildHierarchyChangeEvent>();
+    private ArrayList<View> mSnappedBackChildren = new ArrayList<View>();
+    private ArrayList<View> mDragAnimPendingChildren = new ArrayList<View>();
+    private ArrayList<AnimationEvent> mAnimationEvents
+            = new ArrayList<AnimationEvent>();
     private ArrayList<View> mSwipedOutViews = new ArrayList<View>();
     private final StackStateAnimator mStateAnimator = new StackStateAnimator(this);
 
+    /**
+     * The raw amount of the overScroll on the top, which is not rubber-banded.
+     */
+    private float mOverScrolledTopPixels;
+
+    /**
+     * The raw amount of the overScroll on the bottom, which is not rubber-banded.
+     */
+    private float mOverScrolledBottomPixels;
+
     private OnChildLocationsChangedListener mListener;
     private ExpandableView.OnHeightChangedListener mOnHeightChangedListener;
-    private boolean mChildHierarchyDirty;
+    private boolean mNeedsAnimation;
+    private boolean mTopPaddingNeedsAnimation;
+    private boolean mDimmedNeedsAnimation;
+    private boolean mActivateNeedsAnimation;
     private boolean mIsExpanded = true;
-    private ViewTreeObserver.OnPreDrawListener mAfterLayoutPreDrawListener
+    private boolean mChildrenUpdateRequested;
+    private ViewTreeObserver.OnPreDrawListener mChildrenUpdater
             = new ViewTreeObserver.OnPreDrawListener() {
         @Override
         public boolean onPreDraw() {
-            updateScrollPositionIfNecessary();
             updateChildren();
+            mChildrenUpdateRequested = false;
             getViewTreeObserver().removeOnPreDrawListener(this);
             return true;
         }
@@ -147,7 +167,10 @@
         if (DEBUG) {
             int y = mCollapsedSize;
             canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
-            y = (int) (getLayoutHeight() - mBottomStackPeekSize - mCollapsedSize);
+            y = (int) (getLayoutHeight() - mBottomStackPeekSize
+                    - mBottomStackSlowDownHeight);
+            canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
+            y = (int) (getLayoutHeight() - mBottomStackPeekSize);
             canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
             y = (int) getLayoutHeight();
             canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
@@ -158,11 +181,11 @@
         mScroller = new OverScroller(getContext());
         setFocusable(true);
         setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
+        setClipChildren(false);
         final ViewConfiguration configuration = ViewConfiguration.get(context);
         mTouchSlop = configuration.getScaledTouchSlop();
         mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
         mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
-        mOverscrollDistance = configuration.getScaledOverscrollDistance();
         mOverflingDistance = configuration.getScaledOverflingDistance();
         float densityScale = getResources().getDisplayMetrics().density;
         float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
@@ -176,9 +199,20 @@
                 .getDimensionPixelSize(R.dimen.bottom_stack_peek_amount);
         mEmptyMarginBottom = context.getResources().getDimensionPixelSize(
                 R.dimen.notification_stack_margin_bottom);
-        mPaddingBetweenElements = context.getResources()
-                .getDimensionPixelSize(R.dimen.notification_padding);
         mStackScrollAlgorithm = new StackScrollAlgorithm(context);
+        mPaddingBetweenElementsDimmed = context.getResources()
+                .getDimensionPixelSize(R.dimen.notification_padding_dimmed);
+        mPaddingBetweenElementsNormal = context.getResources()
+                .getDimensionPixelSize(R.dimen.notification_padding);
+        updatePadding(false);
+    }
+
+    private void updatePadding(boolean dimmed) {
+        mPaddingBetweenElements = dimmed
+                ? mPaddingBetweenElementsDimmed
+                : mPaddingBetweenElementsNormal;
+        mBottomStackSlowDownHeight = mStackScrollAlgorithm.getBottomStackSlowDownLength();
+        updateContentHeight();
     }
 
     @Override
@@ -206,7 +240,8 @@
         }
         setMaxLayoutHeight(getHeight() - mEmptyMarginBottom);
         updateContentHeight();
-        getViewTreeObserver().addOnPreDrawListener(mAfterLayoutPreDrawListener);
+        updateScrollPositionIfNecessary();
+        requestChildrenUpdate();
     }
 
     public void setChildLocationsChangedListener(OnChildLocationsChangedListener listener) {
@@ -238,19 +273,43 @@
     }
 
     /**
+     * @return whether the height of the layout needs to be adapted, in order to ensure that the
+     *         last child is not in the bottom stack.
+     */
+    private boolean needsHeightAdaption() {
+        View lastChild = getLastChildNotGone();
+        View firstChild = getFirstChildNotGone();
+        boolean isLastChildExpanded = isViewExpanded(lastChild);
+        return isLastChildExpanded && lastChild != firstChild;
+    }
+
+    private boolean isViewExpanded(View view) {
+        if (view != null) {
+            ExpandableView expandView = (ExpandableView) view;
+            return expandView.getActualHeight() > mCollapsedSize;
+        }
+        return false;
+    }
+
+    /**
      * Updates the children views according to the stack scroll algorithm. Call this whenever
      * modifications to {@link #mOwnScrollY} are performed to reflect it in the view layout.
      */
     private void updateChildren() {
-        mCurrentStackScrollState.setScrollY(mOwnScrollY);
-        mStackScrollAlgorithm.getStackScrollState(mCurrentStackScrollState);
-        if (!isCurrentlyAnimating() && !mChildHierarchyDirty) {
+        mAmbientState.setScrollY(mOwnScrollY);
+        mStackScrollAlgorithm.getStackScrollState(mAmbientState, mCurrentStackScrollState);
+        if (!isCurrentlyAnimating() && !mNeedsAnimation) {
             applyCurrentState();
-            if (mListener != null) {
-                mListener.onChildLocationsChanged(this);
-            }
         } else {
-            startAnimationToState(mCurrentStackScrollState);
+            startAnimationToState();
+        }
+    }
+
+    private void requestChildrenUpdate() {
+        if (!mChildrenUpdateRequested) {
+            getViewTreeObserver().addOnPreDrawListener(mChildrenUpdater);
+            mChildrenUpdateRequested = true;
+            invalidate();
         }
     }
 
@@ -269,12 +328,19 @@
         return mTopPadding;
     }
 
-    public void setTopPadding(int topPadding) {
+    public void setTopPadding(int topPadding, boolean animate) {
         if (mTopPadding != topPadding) {
             mTopPadding = topPadding;
             updateAlgorithmHeightAndPadding();
             updateContentHeight();
-            updateChildren();
+            if (animate) {
+                mTopPaddingNeedsAnimation = true;
+                mNeedsAnimation =  true;
+            }
+            requestChildrenUpdate();
+            if (mOnHeightChangedListener != null) {
+                mOnHeightChangedListener.onHeightChanged(null);
+            }
         }
     }
 
@@ -309,7 +375,7 @@
         if (stackHeight != mCurrentStackHeight) {
             mCurrentStackHeight = stackHeight;
             updateAlgorithmHeightAndPadding();
-            updateChildren();
+            requestChildrenUpdate();
         }
     }
 
@@ -342,11 +408,34 @@
             veto.performClick();
         }
         setSwipingInProgress(false);
+        if (mDragAnimPendingChildren.contains(v)) {
+            // We start the swipe and finish it in the same frame, we don't want any animation
+            // for the drag
+            mDragAnimPendingChildren.remove(v);
+        }
         mSwipedOutViews.add(v);
+        mAmbientState.onDragFinished(v);
+    }
+
+    @Override
+    public void onChildSnappedBack(View animView) {
+        mAmbientState.onDragFinished(animView);
+        if (!mDragAnimPendingChildren.contains(animView)) {
+            mSnappedBackChildren.add(animView);
+            requestChildrenUpdate();
+            mNeedsAnimation = true;
+        } else {
+            // We start the swipe and snap back in the same frame, we don't want any animation
+            mDragAnimPendingChildren.remove(animView);
+        }
     }
 
     public void onBeginDrag(View v) {
         setSwipingInProgress(true);
+        mDragAnimPendingChildren.add(v);
+        mAmbientState.onBeginDrag(v);
+        requestChildrenUpdate();
+        mNeedsAnimation = true;
     }
 
     public void onDragCancelled(View v) {
@@ -357,13 +446,13 @@
         return getChildAtPosition(ev.getX(), ev.getY());
     }
 
-    public View getChildAtRawPosition(float touchX, float touchY) {
+    public ExpandableView getChildAtRawPosition(float touchX, float touchY) {
         int[] location = new int[2];
         getLocationOnScreen(location);
-        return getChildAtPosition(touchX - location[0],touchY - location[1]);
+        return getChildAtPosition(touchX - location[0], touchY - location[1]);
     }
 
-    public View getChildAtPosition(float touchX, float touchY) {
+    public ExpandableView getChildAtPosition(float touchX, float touchY) {
         // find the view under the pointer, accounting for GONE views
         final int count = getChildCount();
         for (int childIdx = 0; childIdx < count; childIdx++) {
@@ -432,6 +521,9 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
+        if (!isEnabled()) {
+            return false;
+        }
         boolean scrollerWantsIt = false;
         if (!mSwipingInProgress) {
             scrollerWantsIt = onScrollTouch(ev);
@@ -451,7 +543,7 @@
 
         switch (action & MotionEvent.ACTION_MASK) {
             case MotionEvent.ACTION_DOWN: {
-                if (getChildCount() == 0) {
+                if (getChildCount() == 0 || !isInContentBounds(ev)) {
                     return false;
                 }
                 boolean isBeingDragged = !mScroller.isFinished();
@@ -462,7 +554,7 @@
                  * will be false if being flinged.
                  */
                 if (!mScroller.isFinished()) {
-                    mScroller.abortAnimation();
+                    mScroller.forceFinished(true);
                 }
 
                 // Remember where the motion event started
@@ -490,40 +582,23 @@
                 if (mIsBeingDragged) {
                     // Scroll to follow the motion event
                     mLastMotionY = y;
-
-                    final int oldX = mScrollX;
-                    final int oldY = mOwnScrollY;
                     final int range = getScrollRange();
-                    final int overscrollMode = getOverScrollMode();
-                    final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
-                            (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
+
+                    float scrollAmount;
+                    if (deltaY < 0) {
+                        scrollAmount = overScrollDown(deltaY);
+                    } else {
+                        scrollAmount = overScrollUp(deltaY, range);
+                    }
 
                     // Calling overScrollBy will call onOverScrolled, which
                     // calls onScrollChanged if applicable.
-                    if (overScrollBy(0, deltaY, 0, mOwnScrollY,
-                            0, range, 0, mOverscrollDistance, true)) {
-                        // Break our velocity if we hit a scroll barrier.
-                        mVelocityTracker.clear();
+                    if (scrollAmount != 0.0f) {
+                        // The scrolling motion could not be compensated with the
+                        // existing overScroll, we have to scroll the view
+                        overScrollBy(0, (int) scrollAmount, 0, mOwnScrollY,
+                                0, range, 0, getHeight() / 2, true);
                     }
-                    // TODO: Overscroll
-//                    if (canOverscroll) {
-//                        final int pulledToY = oldY + deltaY;
-//                        if (pulledToY < 0) {
-//                            mEdgeGlowTop.onPull((float) deltaY / getHeight());
-//                            if (!mEdgeGlowBottom.isFinished()) {
-//                                mEdgeGlowBottom.onRelease();
-//                            }
-//                        } else if (pulledToY > range) {
-//                            mEdgeGlowBottom.onPull((float) deltaY / getHeight());
-//                            if (!mEdgeGlowTop.isFinished()) {
-//                                mEdgeGlowTop.onRelease();
-//                            }
-//                        }
-//                        if (mEdgeGlowTop != null
-//                                && (!mEdgeGlowTop.isFinished() || !mEdgeGlowBottom.isFinished())){
-//                            postInvalidateOnAnimation();
-//                        }
-//                    }
                 }
                 break;
             case MotionEvent.ACTION_UP:
@@ -570,6 +645,68 @@
         return true;
     }
 
+    /**
+     * Perform a scroll upwards and adapt the overscroll amounts accordingly
+     *
+     * @param deltaY The amount to scroll upwards, has to be positive.
+     * @return The amount of scrolling to be performed by the scroller,
+     *         not handled by the overScroll amount.
+     */
+    private float overScrollUp(int deltaY, int range) {
+        deltaY = Math.max(deltaY, 0);
+        float currentTopAmount = getCurrentOverScrollAmount(true);
+        float newTopAmount = currentTopAmount - deltaY;
+        if (currentTopAmount > 0) {
+            setOverScrollAmount(newTopAmount, true /* onTop */,
+                    false /* animate */);
+        }
+        // Top overScroll might not grab all scrolling motion,
+        // we have to scroll as well.
+        float scrollAmount = newTopAmount < 0 ? -newTopAmount : 0.0f;
+        float newScrollY = mOwnScrollY + scrollAmount;
+        if (newScrollY > range) {
+            float currentBottomPixels = getCurrentOverScrolledPixels(false);
+            // We overScroll on the top
+            setOverScrolledPixels(currentBottomPixels + newScrollY - range,
+                    false /* onTop */,
+                    false /* animate */);
+            mOwnScrollY = range;
+            scrollAmount = 0.0f;
+        }
+        return scrollAmount;
+    }
+
+    /**
+     * Perform a scroll downward and adapt the overscroll amounts accordingly
+     *
+     * @param deltaY The amount to scroll downwards, has to be negative.
+     * @return The amount of scrolling to be performed by the scroller,
+     *         not handled by the overScroll amount.
+     */
+    private float overScrollDown(int deltaY) {
+        deltaY = Math.min(deltaY, 0);
+        float currentBottomAmount = getCurrentOverScrollAmount(false);
+        float newBottomAmount = currentBottomAmount + deltaY;
+        if (currentBottomAmount > 0) {
+            setOverScrollAmount(newBottomAmount, false /* onTop */,
+                    false /* animate */);
+        }
+        // Bottom overScroll might not grab all scrolling motion,
+        // we have to scroll as well.
+        float scrollAmount = newBottomAmount < 0 ? newBottomAmount : 0.0f;
+        float newScrollY = mOwnScrollY + scrollAmount;
+        if (newScrollY < 0) {
+            float currentTopPixels = getCurrentOverScrolledPixels(true);
+            // We overScroll on the top
+            setOverScrolledPixels(currentTopPixels - newScrollY,
+                    true /* onTop */,
+                    false /* animate */);
+            mOwnScrollY = 0;
+            scrollAmount = 0.0f;
+        }
+        return scrollAmount;
+    }
+
     private void onSecondaryPointerUp(MotionEvent ev) {
         final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
                 MotionEvent.ACTION_POINTER_INDEX_SHIFT;
@@ -619,23 +756,16 @@
 
             if (oldX != x || oldY != y) {
                 final int range = getScrollRange();
-                final int overscrollMode = getOverScrollMode();
-                final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
-                        (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
+                if (y < 0 && oldY >= 0 || y > range && oldY <= range) {
+                    float currVelocity = mScroller.getCurrVelocity();
+                    if (currVelocity >= mMinimumVelocity) {
+                        mMaxOverScroll = Math.abs(currVelocity) / 1000 * mOverflingDistance;
+                    }
+                }
 
                 overScrollBy(x - oldX, y - oldY, oldX, oldY, 0, range,
-                        0, mOverflingDistance, false);
+                        0, (int) (mMaxOverScroll), false);
                 onScrollChanged(mScrollX, mOwnScrollY, oldX, oldY);
-
-                if (canOverscroll) {
-                    // TODO: Overscroll
-//                    if (y < 0 && oldY >= 0) {
-//                        mEdgeGlowTop.onAbsorb((int) mScroller.getCurrVelocity());
-//                    } else if (y > range && oldY <= range) {
-//                        mEdgeGlowBottom.onAbsorb((int) mScroller.getCurrVelocity());
-//                    }
-                }
-                updateChildren();
             }
 
             // Keep on drawing until the animation has finished.
@@ -643,46 +773,139 @@
         }
     }
 
-    public void customScrollBy(int y) {
-        mOwnScrollY += y;
-        updateChildren();
+    @Override
+    protected int computeVerticalScrollRange() {
+        // needed for the overScroller
+        return mContentHeight;
     }
 
-    public void customScrollTo(int y) {
+    /**
+     * Set the amount of overScrolled pixels which will force the view to apply a rubber-banded
+     * overscroll effect based on numPixels. By default this will also cancel animations on the
+     * same overScroll edge.
+     *
+     * @param numPixels The amount of pixels to overScroll by. These will be scaled according to
+     *                  the rubber-banding logic.
+     * @param onTop Should the effect be applied on top of the scroller.
+     * @param animate Should an animation be performed.
+     */
+    public void setOverScrolledPixels(float numPixels, boolean onTop, boolean animate) {
+        setOverScrollAmount(numPixels * RUBBER_BAND_FACTOR, onTop, animate, true);
+    }
+
+    /**
+     * Set the effective overScroll amount which will be directly reflected in the layout.
+     * By default this will also cancel animations on the same overScroll edge.
+     *
+     * @param amount The amount to overScroll by.
+     * @param onTop Should the effect be applied on top of the scroller.
+     * @param animate Should an animation be performed.
+     */
+    public void setOverScrollAmount(float amount, boolean onTop, boolean animate) {
+        setOverScrollAmount(amount, onTop, animate, true);
+    }
+
+    /**
+     * Set the effective overScroll amount which will be directly reflected in the layout.
+     *
+     * @param amount The amount to overScroll by.
+     * @param onTop Should the effect be applied on top of the scroller.
+     * @param animate Should an animation be performed.
+     * @param cancelAnimators Should running animations be cancelled.
+     */
+    public void setOverScrollAmount(float amount, boolean onTop, boolean animate,
+            boolean cancelAnimators) {
+        if (cancelAnimators) {
+            mStateAnimator.cancelOverScrollAnimators(onTop);
+        }
+        setOverScrollAmountInternal(amount, onTop, animate);
+    }
+
+    private void setOverScrollAmountInternal(float amount, boolean onTop, boolean animate) {
+        amount = Math.max(0, amount);
+        if (animate) {
+            mStateAnimator.animateOverScrollToAmount(amount, onTop);
+        } else {
+            setOverScrolledPixels(amount / RUBBER_BAND_FACTOR, onTop);
+            mAmbientState.setOverScrollAmount(amount, onTop);
+            requestChildrenUpdate();
+        }
+    }
+
+    public float getCurrentOverScrollAmount(boolean top) {
+        return mAmbientState.getOverScrollAmount(top);
+    }
+
+    public float getCurrentOverScrolledPixels(boolean top) {
+        return top? mOverScrolledTopPixels : mOverScrolledBottomPixels;
+    }
+
+    private void setOverScrolledPixels(float amount, boolean onTop) {
+        if (onTop) {
+            mOverScrolledTopPixels = amount;
+        } else {
+            mOverScrolledBottomPixels = amount;
+        }
+    }
+
+    private void customScrollTo(int y) {
         mOwnScrollY = y;
         updateChildren();
     }
 
     @Override
-    protected void onOverScrolled(int scrollX, int scrollY,
-                                  boolean clampedX, boolean clampedY) {
+    protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
         // Treat animating scrolls differently; see #computeScroll() for why.
         if (!mScroller.isFinished()) {
             final int oldX = mScrollX;
             final int oldY = mOwnScrollY;
             mScrollX = scrollX;
             mOwnScrollY = scrollY;
-            invalidateParentIfNeeded();
-            onScrollChanged(mScrollX, mOwnScrollY, oldX, oldY);
             if (clampedY) {
-                mScroller.springBack(mScrollX, mOwnScrollY, 0, 0, 0, getScrollRange());
+                springBack();
+            } else {
+                onScrollChanged(mScrollX, mOwnScrollY, oldX, oldY);
+                invalidateParentIfNeeded();
+                updateChildren();
             }
-            updateChildren();
         } else {
             customScrollTo(scrollY);
             scrollTo(scrollX, mScrollY);
         }
     }
 
+    private void springBack() {
+        int scrollRange = getScrollRange();
+        boolean overScrolledTop = mOwnScrollY <= 0;
+        boolean overScrolledBottom = mOwnScrollY >= scrollRange;
+        if (overScrolledTop || overScrolledBottom) {
+            boolean onTop;
+            float newAmount;
+            if (overScrolledTop) {
+                onTop = true;
+                newAmount = -mOwnScrollY;
+                mOwnScrollY = 0;
+            } else {
+                onTop = false;
+                newAmount = mOwnScrollY - scrollRange;
+                mOwnScrollY = scrollRange;
+            }
+            setOverScrollAmount(newAmount, onTop, false);
+            setOverScrollAmount(0.0f, onTop, true);
+            mScroller.forceFinished(true);
+        }
+    }
+
     private int getScrollRange() {
         int scrollRange = 0;
         ExpandableView firstChild = (ExpandableView) getFirstChildNotGone();
         if (firstChild != null) {
             int contentHeight = getContentHeight();
             int firstChildMaxExpandHeight = getMaxExpandHeight(firstChild);
-
-            scrollRange = Math.max(0, contentHeight - mMaxLayoutHeight + mBottomStackPeekSize);
-            if (scrollRange > 0 && getChildCount() > 0) {
+            scrollRange = Math.max(0, contentHeight - mMaxLayoutHeight + mBottomStackPeekSize
+                    + mBottomStackSlowDownHeight);
+            if (scrollRange > 0) {
+                View lastChild = getLastChildNotGone();
                 // We want to at least be able collapse the first item and not ending in a weird
                 // end state.
                 scrollRange = Math.max(scrollRange, firstChildMaxExpandHeight - mCollapsedSize);
@@ -705,10 +928,24 @@
         return null;
     }
 
+    /**
+     * @return the last child which has visibility unequal to GONE
+     */
+    private View getLastChildNotGone() {
+        int childCount = getChildCount();
+        for (int i = childCount - 1; i >= 0; i--) {
+            View child = getChildAt(i);
+            if (child.getVisibility() != View.GONE) {
+                return child;
+            }
+        }
+        return null;
+    }
+
     private int getMaxExpandHeight(View view) {
         if (view instanceof ExpandableNotificationRow) {
             ExpandableNotificationRow row = (ExpandableNotificationRow) view;
-            return row.getMaximumAllowedExpandHeight();
+            return row.getIntrinsicHeight();
         }
         return view.getHeight();
     }
@@ -728,7 +965,7 @@
                 }
                 if (child instanceof ExpandableNotificationRow) {
                     ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                    height += row.getMaximumAllowedExpandHeight();
+                    height += row.getIntrinsicHeight();
                 } else if (child instanceof ExpandableView) {
                     ExpandableView expandableView = (ExpandableView) child;
                     height += expandableView.getActualHeight();
@@ -750,7 +987,23 @@
             int height = (int) getLayoutHeight();
             int bottom = getContentHeight();
 
-            mScroller.fling(mScrollX, mOwnScrollY, 0, velocityY, 0, 0, 0,
+            float topAmount = getCurrentOverScrollAmount(true);
+            float bottomAmount = getCurrentOverScrollAmount(false);
+            if (velocityY < 0 && topAmount > 0) {
+                mOwnScrollY -= (int) topAmount;
+                setOverScrollAmount(0, true, false);
+                mMaxOverScroll = Math.abs(velocityY) / 1000f * RUBBER_BAND_FACTOR
+                        * mOverflingDistance + topAmount;
+            } else if (velocityY > 0 && bottomAmount > 0) {
+                mOwnScrollY += bottomAmount;
+                setOverScrollAmount(0, false, false);
+                mMaxOverScroll = Math.abs(velocityY) / 1000f * RUBBER_BAND_FACTOR
+                        * mOverflingDistance + bottomAmount;
+            } else {
+                // it will be set once we reach the boundary
+                mMaxOverScroll = 0.0f;
+            }
+            mScroller.fling(mScrollX, mOwnScrollY, 1, velocityY, 0, 0, 0,
                     Math.max(0, bottom - height), 0, height/2);
 
             postInvalidateOnAnimation();
@@ -762,11 +1015,12 @@
 
         recycleVelocityTracker();
 
-        // TODO: Overscroll
-//        if (mEdgeGlowTop != null) {
-//            mEdgeGlowTop.onRelease();
-//            mEdgeGlowBottom.onRelease();
-//        }
+        if (getCurrentOverScrollAmount(true /* onTop */) > 0) {
+            setOverScrollAmount(0, true /* onTop */, true /* animate */);
+        }
+        if (getCurrentOverScrollAmount(false /* onTop */) > 0) {
+            setOverScrollAmount(0, false /* onTop */, true /* animate */);
+        }
     }
 
     @Override
@@ -792,9 +1046,13 @@
         updateScrollStateForRemovedChild(child);
         if (mIsExpanded) {
 
-            // Generate Animations
-            mChildrenToRemoveAnimated.add(child);
-            mChildHierarchyDirty = true;
+            if (!mChildrenToAddAnimated.contains(child)) {
+                // Generate Animations
+                mChildrenToRemoveAnimated.add(child);
+                mNeedsAnimation = true;
+            } else {
+                mChildrenToAddAnimated.remove(child);
+            }
         }
     }
 
@@ -850,7 +1108,7 @@
 
             // Generate Animations
             mChildrenToAddAnimated.add(child);
-            mChildHierarchyDirty = true;
+            mNeedsAnimation = true;
         }
     }
 
@@ -866,40 +1124,89 @@
         }
     }
 
-    private void startAnimationToState(StackScrollState finalState) {
-        if (mChildHierarchyDirty) {
+    private void startAnimationToState() {
+        if (mNeedsAnimation) {
             generateChildHierarchyEvents();
-            mChildHierarchyDirty = false;
+            mNeedsAnimation = false;
         }
-        mStateAnimator.startAnimationForEvents(mAnimationEvents, finalState);
+        if (!mAnimationEvents.isEmpty()) {
+            mStateAnimator.startAnimationForEvents(mAnimationEvents, mCurrentStackScrollState);
+        } else {
+            applyCurrentState();
+        }
     }
 
     private void generateChildHierarchyEvents() {
         generateChildAdditionEvents();
         generateChildRemovalEvents();
-        mChildHierarchyDirty = false;
+        generateSnapBackEvents();
+        generateDragEvents();
+        generateTopPaddingEvent();
+        generateActivateEvent();
+        generateDimmedEvent();
+        mNeedsAnimation = false;
+    }
+
+    private void generateSnapBackEvents() {
+        for (View child : mSnappedBackChildren) {
+            mAnimationEvents.add(new AnimationEvent(child,
+                    AnimationEvent.ANIMATION_TYPE_SNAP_BACK));
+        }
+        mSnappedBackChildren.clear();
+    }
+
+    private void generateDragEvents() {
+        for (View child : mDragAnimPendingChildren) {
+            mAnimationEvents.add(new AnimationEvent(child,
+                    AnimationEvent.ANIMATION_TYPE_START_DRAG));
+        }
+        mDragAnimPendingChildren.clear();
     }
 
     private void generateChildRemovalEvents() {
-        for (View  child : mChildrenToRemoveAnimated) {
+        for (View child : mChildrenToRemoveAnimated) {
             boolean childWasSwipedOut = mSwipedOutViews.contains(child);
             int animationType = childWasSwipedOut
-                    ? ChildHierarchyChangeEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT
-                    : ChildHierarchyChangeEvent.ANIMATION_TYPE_REMOVE;
-            mAnimationEvents.add(new ChildHierarchyChangeEvent(child, animationType));
+                    ? AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT
+                    : AnimationEvent.ANIMATION_TYPE_REMOVE;
+            mAnimationEvents.add(new AnimationEvent(child, animationType));
         }
         mSwipedOutViews.clear();
         mChildrenToRemoveAnimated.clear();
     }
 
     private void generateChildAdditionEvents() {
-        for (View  child : mChildrenToAddAnimated) {
-            mAnimationEvents.add(new ChildHierarchyChangeEvent(child,
-                    ChildHierarchyChangeEvent.ANIMATION_TYPE_ADD));
+        for (View child : mChildrenToAddAnimated) {
+            mAnimationEvents.add(new AnimationEvent(child,
+                    AnimationEvent.ANIMATION_TYPE_ADD));
         }
         mChildrenToAddAnimated.clear();
     }
 
+    private void generateTopPaddingEvent() {
+        if (mTopPaddingNeedsAnimation) {
+            mAnimationEvents.add(
+                    new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_TOP_PADDING_CHANGED));
+        }
+        mTopPaddingNeedsAnimation = false;
+    }
+
+    private void generateActivateEvent() {
+        if (mActivateNeedsAnimation) {
+            mAnimationEvents.add(
+                    new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_ACTIVATED_CHILD));
+        }
+        mActivateNeedsAnimation = false;
+    }
+
+    private void generateDimmedEvent() {
+        if (mDimmedNeedsAnimation) {
+            mAnimationEvents.add(
+                    new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_DIMMED));
+        }
+        mDimmedNeedsAnimation = false;
+    }
+
     private boolean onInterceptTouchEventScroll(MotionEvent ev) {
         /*
          * This method JUST determines whether we want to intercept the motion.
@@ -1008,6 +1315,13 @@
         return mIsBeingDragged;
     }
 
+    /**
+     * @return Whether the specified motion event is actually happening over the content.
+     */
+    private boolean isInContentBounds(MotionEvent event) {
+        return event.getY() < getHeight() - getEmptyBottomMargin();
+    }
+
     private void setIsBeingDragged(boolean isDragged) {
         mIsBeingDragged = isDragged;
         if (isDragged) {
@@ -1040,7 +1354,11 @@
     }
 
     public int getEmptyBottomMargin() {
-        return Math.max(getHeight() - mContentHeight, 0);
+        int emptyMargin = mMaxLayoutHeight - mContentHeight;
+        if (needsHeightAdaption()) {
+            emptyMargin = emptyMargin - mBottomStackSlowDownHeight - mBottomStackPeekSize;
+        }
+        return Math.max(emptyMargin, 0);
     }
 
     public void onExpansionStarted() {
@@ -1061,14 +1379,12 @@
 
     @Override
     public void onHeightChanged(ExpandableView view) {
-        if (mListenForHeightChanges && !isCurrentlyAnimating()) {
-            updateContentHeight();
-            updateScrollPositionIfNecessary();
-            if (mOnHeightChangedListener != null) {
-                mOnHeightChangedListener.onHeightChanged(view);
-            }
-            updateChildren();
+        updateContentHeight();
+        updateScrollPositionIfNecessary();
+        if (mOnHeightChangedListener != null) {
+            mOnHeightChangedListener.onHeightChanged(view);
         }
+        requestChildrenUpdate();
     }
 
     public void setOnHeightChangedListener(
@@ -1077,14 +1393,43 @@
     }
 
     public void onChildAnimationFinished() {
-        applyCurrentState();
+        requestChildrenUpdate();
         mAnimationEvents.clear();
     }
 
+    /**
+     * See {@link AmbientState#setDimmed}.
+     */
+    public void setDimmed(boolean dimmed, boolean animate) {
+        mStackScrollAlgorithm.setDimmed(dimmed);
+        mAmbientState.setDimmed(dimmed);
+        updatePadding(dimmed);
+        if (animate) {
+            mDimmedNeedsAnimation = true;
+            mNeedsAnimation =  true;
+        }
+        requestChildrenUpdate();
+    }
+
+    /**
+     * See {@link AmbientState#setActivatedChild}.
+     */
+    public void setActivatedChild(View activatedChild) {
+        mAmbientState.setActivatedChild(activatedChild);
+        mActivateNeedsAnimation = true;
+        mNeedsAnimation =  true;
+        requestChildrenUpdate();
+    }
+
+    public View getActivatedChild() {
+        return mAmbientState.getActivatedChild();
+    }
+
     private void applyCurrentState() {
-        mListenForHeightChanges = false;
         mCurrentStackScrollState.apply();
-        mListenForHeightChanges = true;
+        if (mListener != null) {
+            mListener.onChildLocationsChanged(this);
+        }
     }
 
     /**
@@ -1094,19 +1439,123 @@
         public void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout);
     }
 
-    static class ChildHierarchyChangeEvent {
+    static class AnimationEvent {
 
-        static int ANIMATION_TYPE_ADD = 1;
-        static int ANIMATION_TYPE_REMOVE = 2;
-        static int ANIMATION_TYPE_REMOVE_SWIPED_OUT = 3;
+        static AnimationFilter[] FILTERS = new AnimationFilter[] {
+
+                // ANIMATION_TYPE_ADD
+                new AnimationFilter()
+                        .animateAlpha()
+                        .animateHeight()
+                        .animateY()
+                        .animateZ(),
+
+                // ANIMATION_TYPE_REMOVE
+                new AnimationFilter()
+                        .animateAlpha()
+                        .animateHeight()
+                        .animateY()
+                        .animateZ(),
+
+                // ANIMATION_TYPE_REMOVE_SWIPED_OUT
+                new AnimationFilter()
+                        .animateAlpha()
+                        .animateHeight()
+                        .animateY()
+                        .animateZ(),
+
+                // ANIMATION_TYPE_TOP_PADDING_CHANGED
+                new AnimationFilter()
+                        .animateAlpha()
+                        .animateHeight()
+                        .animateY()
+                        .animateDimmed()
+                        .animateScale()
+                        .animateZ(),
+
+                // ANIMATION_TYPE_START_DRAG
+                new AnimationFilter()
+                        .animateAlpha(),
+
+                // ANIMATION_TYPE_SNAP_BACK
+                new AnimationFilter()
+                        .animateAlpha(),
+
+                // ANIMATION_TYPE_ACTIVATED_CHILD
+                new AnimationFilter()
+                        .animateScale()
+                        .animateAlpha(),
+
+                // ANIMATION_TYPE_DIMMED
+                new AnimationFilter()
+                        .animateY()
+                        .animateScale()
+                        .animateDimmed()
+        };
+
+        static int[] LENGTHS = new int[] {
+
+                // ANIMATION_TYPE_ADD
+                StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+                // ANIMATION_TYPE_REMOVE
+                StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+                // ANIMATION_TYPE_REMOVE_SWIPED_OUT
+                StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+                // ANIMATION_TYPE_TOP_PADDING_CHANGED
+                StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+                // ANIMATION_TYPE_START_DRAG
+                StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+                // ANIMATION_TYPE_SNAP_BACK
+                StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+                // ANIMATION_TYPE_ACTIVATED_CHILD
+                StackStateAnimator.ANIMATION_DURATION_DIMMED_ACTIVATED,
+
+                // ANIMATION_TYPE_DIMMED
+                StackStateAnimator.ANIMATION_DURATION_DIMMED_ACTIVATED,
+        };
+
+        static int ANIMATION_TYPE_ADD = 0;
+        static int ANIMATION_TYPE_REMOVE = 1;
+        static int ANIMATION_TYPE_REMOVE_SWIPED_OUT = 2;
+        static int ANIMATION_TYPE_TOP_PADDING_CHANGED = 3;
+        static int ANIMATION_TYPE_START_DRAG = 4;
+        static int ANIMATION_TYPE_SNAP_BACK = 5;
+        static int ANIMATION_TYPE_ACTIVATED_CHILD = 6;
+        static int ANIMATION_TYPE_DIMMED = 7;
+
         final long eventStartTime;
         final View changingView;
         final int animationType;
+        final AnimationFilter filter;
+        final long length;
 
-        ChildHierarchyChangeEvent(View view, int type) {
+        AnimationEvent(View view, int type) {
             eventStartTime = AnimationUtils.currentAnimationTimeMillis();
             changingView = view;
             animationType = type;
+            filter = FILTERS[type];
+            length = LENGTHS[type];
+        }
+
+        /**
+         * Combines the length of several animation events into a single value.
+         *
+         * @param events The events of the lengths to combine.
+         * @return The combined length. This is just the maximum of all length.
+         */
+        static long combineLength(ArrayList<AnimationEvent> events) {
+            long length = 0;
+            int size = events.size();
+            for (int i = 0; i < size; i++) {
+                length = Math.max(length, events.get(i).length);
+            }
+            return length;
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java
index 38b544f..1c37c35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java
@@ -38,27 +38,26 @@
      *                 the actual visual distance below the top card but is a maximum,
      *                 achieved when the next card just starts transitioning into the stack and
      *                 the stack is full.
-     *                 If totalTransitionDistance is equal to this, we directly start at the peek,
-     *                 otherwise the first element transitions between 0 and
-     *                 totalTransitionDistance - peekSize.
+     *                 If distanceToPeekStart is 0, we directly start at the peek, otherwise the
+     *                 first element transitions between 0 and distanceToPeekStart.
      *                 Visualization:
      *           ---------------------------------------------------   ---
      *          |                                                   |   |
-     *          |                  FIRST ITEM                       |   | <- totalTransitionDistance
+     *          |                  FIRST ITEM                       |   | <- distanceToPeekStart
      *          |                                                   |   |
-     *          |---------------------------------------------------|   |   ---
-     *          |__________________SECOND ITEM______________________|   |    |  <- peekSize
-     *          |===================================================|  _|_  _|_
+     *          |---------------------------------------------------|  ---  ---
+     *          |__________________SECOND ITEM______________________|        |  <- peekSize
+     *          |===================================================|       _|_
      *
-     * @param totalTransitionDistance The total transition distance an element has to go through
+     * @param distanceToPeekStart The distance to the start of the peak.
      * @param linearPart The interpolation factor between the linear and the quadratic amount taken.
      *                   This factor must be somewhere in [0 , 1]
      */
     PiecewiseLinearIndentationFunctor(int maxItemsInStack,
                                       int peekSize,
-                                      int totalTransitionDistance,
+                                      int distanceToPeekStart,
                                       float linearPart) {
-        super(maxItemsInStack, peekSize, totalTransitionDistance);
+        super(maxItemsInStack, peekSize, distanceToPeekStart);
         mBaseValues = new ArrayList<Float>(maxItemsInStack+1);
         initBaseValues();
         mLinearPart = linearPart;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java
index f72947a..034eba6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java
@@ -21,8 +21,8 @@
  */
 public abstract class StackIndentationFunctor {
 
-    protected final int mTotalTransitionDistance;
-    protected final int mDistanceToPeekStart;
+    protected int mTotalTransitionDistance;
+    protected int mDistanceToPeekStart;
     protected int mMaxItemsInStack;
     protected int mPeekSize;
     protected boolean mStackStartsAtPeek;
@@ -37,31 +37,41 @@
      *                 the actual visual distance below the top card but is a maximum,
      *                 achieved when the next card just starts transitioning into the stack and
      *                 the stack is full.
-     *                 If totalTransitionDistance is equal to this, we directly start at the peek,
-     *                 otherwise the first element transitions between 0 and
-     *                 totalTransitionDistance - peekSize.
+     *                 If distanceToPeekStart is 0, we directly start at the peek, otherwise the
+     *                 first element transitions between 0 and distanceToPeekStart.
      *                 Visualization:
      *           ---------------------------------------------------   ---
      *          |                                                   |   |
-     *          |                  FIRST ITEM                       |   | <- totalTransitionDistance
+     *          |                  FIRST ITEM                       |   | <- distanceToPeekStart
      *          |                                                   |   |
-     *          |---------------------------------------------------|   |   ---
-     *          |__________________SECOND ITEM______________________|   |    |  <- peekSize
-     *          |===================================================|  _|_  _|_
+     *          |---------------------------------------------------|  ---  ---
+     *          |__________________SECOND ITEM______________________|        |  <- peekSize
+     *          |===================================================|       _|_
      *
-     * @param totalTransitionDistance The total transition distance an element has to go through
+     * @param distanceToPeekStart The distance to the start of the peak.
      */
-    StackIndentationFunctor(int maxItemsInStack, int peekSize, int totalTransitionDistance) {
-        mTotalTransitionDistance = totalTransitionDistance;
-        mDistanceToPeekStart = mTotalTransitionDistance - peekSize;
+    StackIndentationFunctor(int maxItemsInStack, int peekSize, int distanceToPeekStart) {
+        mDistanceToPeekStart = distanceToPeekStart;
         mStackStartsAtPeek = mDistanceToPeekStart == 0;
         mMaxItemsInStack = maxItemsInStack;
         mPeekSize = peekSize;
+        updateTotalTransitionDistance();
 
     }
 
+    private void updateTotalTransitionDistance() {
+        mTotalTransitionDistance = mDistanceToPeekStart + mPeekSize;
+    }
+
     public void setPeekSize(int mPeekSize) {
         this.mPeekSize = mPeekSize;
+        updateTotalTransitionDistance();
+    }
+
+    public void setDistanceToPeekStart(int distanceToPeekStart) {
+        mDistanceToPeekStart = distanceToPeekStart;
+        mStackStartsAtPeek = mDistanceToPeekStart == 0;
+        updateTotalTransitionDistance();
     }
 
     /**
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 9bde673..d572ea5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -39,6 +39,10 @@
     private static final int MAX_ITEMS_IN_BOTTOM_STACK = 3;
     private static final int MAX_ITEMS_IN_TOP_STACK = 3;
 
+    /** When a child is activated, the other cards' alpha fade to this value. */
+    private static final float ACTIVATED_INVERSE_ALPHA = 0.9f;
+    private static final float DIMMED_SCALE = 0.95f;
+
     private int mPaddingBetweenElements;
     private int mCollapsedSize;
     private int mTopStackPeekSize;
@@ -61,13 +65,40 @@
     private ExpandableView mFirstChildWhileExpanding;
     private boolean mExpandedOnStart;
     private int mTopStackTotalSize;
+    private int mPaddingBetweenElementsDimmed;
+    private int mPaddingBetweenElementsNormal;
+    private int mBottomStackSlowDownLength;
 
     public StackScrollAlgorithm(Context context) {
         initConstants(context);
+        updatePadding(false);
+    }
+
+    private void updatePadding(boolean dimmed) {
+        mPaddingBetweenElements = dimmed
+                ? mPaddingBetweenElementsDimmed
+                : mPaddingBetweenElementsNormal;
+        mTopStackTotalSize = mCollapsedSize + mPaddingBetweenElements;
+        mTopStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
+                MAX_ITEMS_IN_TOP_STACK,
+                mTopStackPeekSize,
+                mTopStackTotalSize - mTopStackPeekSize,
+                0.5f);
+        mBottomStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
+                MAX_ITEMS_IN_BOTTOM_STACK,
+                mBottomStackPeekSize,
+                getBottomStackSlowDownLength(),
+                0.5f);
+    }
+
+    public int getBottomStackSlowDownLength() {
+        return mBottomStackSlowDownLength + mPaddingBetweenElements;
     }
 
     private void initConstants(Context context) {
-        mPaddingBetweenElements = context.getResources()
+        mPaddingBetweenElementsDimmed = context.getResources()
+                .getDimensionPixelSize(R.dimen.notification_padding_dimmed);
+        mPaddingBetweenElementsNormal = context.getResources()
                 .getDimensionPixelSize(R.dimen.notification_padding);
         mCollapsedSize = context.getResources()
                 .getDimensionPixelSize(R.dimen.notification_min_height);
@@ -78,21 +109,12 @@
         mZDistanceBetweenElements = context.getResources()
                 .getDimensionPixelSize(R.dimen.z_distance_between_notifications);
         mZBasicHeight = (MAX_ITEMS_IN_BOTTOM_STACK + 1) * mZDistanceBetweenElements;
-        mTopStackTotalSize = mCollapsedSize + mPaddingBetweenElements;
-        mTopStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
-                MAX_ITEMS_IN_TOP_STACK,
-                mTopStackPeekSize,
-                mTopStackTotalSize,
-                0.5f);
-        mBottomStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
-                MAX_ITEMS_IN_BOTTOM_STACK,
-                mBottomStackPeekSize,
-                mCollapsedSize + mBottomStackPeekSize + mPaddingBetweenElements,
-                0.5f);
+        mBottomStackSlowDownLength = context.getResources()
+                .getDimensionPixelSize(R.dimen.bottom_stack_slow_down_length);
     }
 
 
-    public void getStackScrollState(StackScrollState resultState) {
+    public void getStackScrollState(AmbientState ambientState, StackScrollState resultState) {
         // The state of the local variables are saved in an algorithmState to easily subdivide it
         // into multiple phases.
         StackScrollAlgorithmState algorithmState = mTempAlgorithmState;
@@ -106,7 +128,10 @@
         algorithmState.scrolledPixelsTop = 0;
         algorithmState.itemsInBottomStack = 0.0f;
         algorithmState.partialInBottom = 0.0f;
-        algorithmState.scrollY = resultState.getScrollY() + mCollapsedSize;
+        float topOverScroll = ambientState.getOverScrollAmount(true /* onTop */);
+        float bottomOverScroll = ambientState.getOverScrollAmount(false /* onTop */);
+        algorithmState.scrollY = (int) (ambientState.getScrollY() + mCollapsedSize
+                + bottomOverScroll - topOverScroll);
 
         updateVisibleChildren(resultState, algorithmState);
 
@@ -118,6 +143,57 @@
 
         // Phase 3:
         updateZValuesForState(resultState, algorithmState);
+
+        handleDraggedViews(ambientState, resultState, algorithmState);
+        updateDimmedActivated(ambientState, resultState, algorithmState);
+    }
+
+    /**
+     * Updates the dimmed and activated states of the children.
+     */
+    private void updateDimmedActivated(AmbientState ambientState, StackScrollState resultState,
+            StackScrollAlgorithmState algorithmState) {
+        boolean dimmed = ambientState.isDimmed();
+        View activatedChild = ambientState.getActivatedChild();
+        int childCount = algorithmState.visibleChildren.size();
+        for (int i = 0; i < childCount; i++) {
+            View child = algorithmState.visibleChildren.get(i);
+            StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
+            childViewState.dimmed = dimmed;
+            childViewState.scale = !dimmed || activatedChild == child
+                    ? 1.0f
+                    : DIMMED_SCALE;
+            if (dimmed && activatedChild != null && child != activatedChild) {
+                childViewState.alpha *= ACTIVATED_INVERSE_ALPHA;
+            }
+        }
+    }
+
+    /**
+     * Handle the special state when views are being dragged
+     */
+    private void handleDraggedViews(AmbientState ambientState, StackScrollState resultState,
+            StackScrollAlgorithmState algorithmState) {
+        ArrayList<View> draggedViews = ambientState.getDraggedViews();
+        for (View draggedView : draggedViews) {
+            int childIndex = algorithmState.visibleChildren.indexOf(draggedView);
+            if (childIndex >= 0 && childIndex < algorithmState.visibleChildren.size() - 1) {
+                View nextChild = algorithmState.visibleChildren.get(childIndex + 1);
+                if (!draggedViews.contains(nextChild)) {
+                    // only if the view is not dragged itself we modify its state to be fully
+                    // visible
+                    StackScrollState.ViewState 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);
+                // The dragged child should keep the set alpha
+                viewState.alpha = draggedView.getAlpha();
+            }
+        }
     }
 
     /**
@@ -142,7 +218,6 @@
      *
      * @param resultState The result state to update if a change to the properties of a child occurs
      * @param algorithmState The state in which the current pass of the algorithm is currently in
-     *                       and which will be updated
      */
     private void updatePositionsForState(StackScrollState resultState,
             StackScrollAlgorithmState algorithmState) {
@@ -151,7 +226,7 @@
         float bottomPeekStart = mInnerHeight - mBottomStackPeekSize;
 
         // The position where the bottom stack starts.
-        float bottomStackStart = bottomPeekStart - mCollapsedSize;
+        float bottomStackStart = bottomPeekStart - mBottomStackSlowDownLength;
 
         // The y coordinate of the current child.
         float currentYPosition = 0.0f;
@@ -192,7 +267,7 @@
                 clampYTranslation(childViewState, childHeight);
                 // check if we are overlapping with the bottom stack
                 if (childViewState.yTranslation + childHeight + mPaddingBetweenElements
-                        >= bottomStackStart && !mIsExpansionChanging) {
+                        >= bottomStackStart && !mIsExpansionChanging && i != 0) {
                     // TODO: handle overlapping sizes with end stack better
                     // we just collapse this element
                     childViewState.height = mCollapsedSize;
@@ -222,7 +297,7 @@
             // The first card is always rendered.
             if (i == 0) {
                 childViewState.alpha = 1.0f;
-                childViewState.yTranslation = 0;
+                childViewState.yTranslation = Math.max(mCollapsedSize - algorithmState.scrollY, 0);
                 childViewState.location = StackScrollState.ViewState.LOCATION_FIRST_CARD;
             }
             if (childViewState.location == StackScrollState.ViewState.LOCATION_UNKNOWN) {
@@ -275,7 +350,7 @@
     private int getMaxAllowedChildHeight(View child) {
         if (child instanceof ExpandableNotificationRow) {
             ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-            return row.getMaximumAllowedExpandHeight();
+            return row.getIntrinsicHeight();
         } else if (child instanceof ExpandableView) {
             ExpandableView expandableView = (ExpandableView) child;
             return expandableView.getActualHeight();
@@ -297,7 +372,7 @@
         algorithmState.itemsInBottomStack += algorithmState.partialInBottom;
         childViewState.yTranslation = transitioningPositionStart + offset - childHeight
                 - mPaddingBetweenElements;
-
+        
         // We want at least to be at the end of the top stack when collapsing
         clampPositionToTopStackEnd(childViewState, childHeight);
         childViewState.location = StackScrollState.ViewState.LOCATION_MAIN_AREA;
@@ -381,7 +456,6 @@
      *
      * @param resultState The result state to update if a height change of an child occurs
      * @param algorithmState The state in which the current pass of the algorithm is currently in
-     *                       and which will be updated
      */
     private void findNumberOfItemsInTopStackAndUpdateState(StackScrollState resultState,
             StackScrollAlgorithmState algorithmState) {
@@ -399,7 +473,7 @@
                     + childHeight
                     + mPaddingBetweenElements;
             if (yPositionInScrollView < algorithmState.scrollY) {
-                if (i == 0 && algorithmState.scrollY == mCollapsedSize) {
+                if (i == 0 && algorithmState.scrollY <= mCollapsedSize) {
 
                     // The starting position of the bottom stack peek
                     int bottomPeekStart = mInnerHeight - mBottomStackPeekSize;
@@ -566,6 +640,10 @@
         }
     }
 
+    public void setDimmed(boolean dimmed) {
+        updatePadding(dimmed);
+    }
+
     class StackScrollAlgorithmState {
 
         /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 8c75adc..8fc26d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -37,19 +37,10 @@
 
     private final ViewGroup mHostView;
     private Map<ExpandableView, ViewState> mStateMap;
-    private int mScrollY;
     private final Rect mClipRect = new Rect();
     private int mBackgroundRoundedRectCornerRadius;
     private final Outline mChildOutline = new Outline();
 
-    public int getScrollY() {
-        return mScrollY;
-    }
-
-    public void setScrollY(int scrollY) {
-        this.mScrollY = scrollY;
-    }
-
     public StackScrollState(ViewGroup hostView) {
         mHostView = hostView;
         mStateMap = new HashMap<ExpandableView, ViewState>();
@@ -71,7 +62,7 @@
                 mStateMap.put(child, viewState);
             }
             // initialize with the default values of the view
-            viewState.height = child.getActualHeight();
+            viewState.height = child.getIntrinsicHeight();
             viewState.gone = child.getVisibility() == View.GONE;
             viewState.alpha = 1;
         }
@@ -93,6 +84,7 @@
         int numChildren = mHostView.getChildCount();
         float previousNotificationEnd = 0;
         float previousNotificationStart = 0;
+        boolean previousNotificationIsSwiped = false;
         for (int i = 0; i < numChildren; i++) {
             ExpandableView child = (ExpandableView) mHostView.getChildAt(i);
             ViewState state = mStateMap.get(child);
@@ -105,10 +97,12 @@
                 float alpha = child.getAlpha();
                 float yTranslation = child.getTranslationY();
                 float zTranslation = child.getTranslationZ();
+                float scale = child.getScaleX();
                 int height = child.getActualHeight();
                 float newAlpha = state.alpha;
                 float newYTranslation = state.yTranslation;
                 float newZTranslation = state.zTranslation;
+                float newScale = state.scale;
                 int newHeight = state.height;
                 boolean becomesInvisible = newAlpha == 0.0f;
                 if (alpha != newAlpha) {
@@ -146,19 +140,36 @@
                     child.setTranslationZ(newZTranslation);
                 }
 
+                // apply scale
+                if (scale != newScale) {
+                    child.setScaleX(newScale);
+                    child.setScaleY(newScale);
+                }
+
                 // apply height
                 if (height != newHeight) {
-                    child.setActualHeight(newHeight);
+                    child.setActualHeight(newHeight, false /* notifyListeners */);
                 }
 
+                // apply dimming
+                child.setDimmed(state.dimmed, false /* animate */);
+
                 // apply clipping and shadow
                 float newNotificationEnd = newYTranslation + newHeight;
+
+                // When the previous notification is swiped, we don't clip the content to the
+                // bottom of it.
+                float clipHeight = previousNotificationIsSwiped
+                        ? newHeight
+                        : newNotificationEnd - (previousNotificationEnd);
+
                 updateChildClippingAndBackground(child, newHeight,
-                        newNotificationEnd - (previousNotificationEnd),
+                        clipHeight,
                         (int) (newHeight - (previousNotificationStart - newYTranslation)));
 
-                previousNotificationStart = newYTranslation;
+                previousNotificationStart = newYTranslation + child.getClipTopAmount();
                 previousNotificationEnd = newNotificationEnd;
+                previousNotificationIsSwiped = child.getTranslationX() != 0;
             }
         }
     }
@@ -219,6 +230,8 @@
         float zTranslation;
         int height;
         boolean gone;
+        float scale;
+        boolean dimmed;
 
         /**
          * The location this view is currently rendered at.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 9c6238f..5ac51f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -17,132 +17,551 @@
 package com.android.systemui.statusbar.stack;
 
 import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
 import android.view.View;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
+
+import com.android.systemui.R;
 import com.android.systemui.statusbar.ExpandableView;
 
 import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Stack;
 
 /**
  * An stack state animator which handles animations to new StackScrollStates
  */
 public class StackStateAnimator {
 
-    private static final int ANIMATION_DURATION = 360;
+    public static final int ANIMATION_DURATION_STANDARD = 360;
+    public static final int ANIMATION_DURATION_DIMMED_ACTIVATED = 220;
+
+    private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
+    private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag;
+    private static final int TAG_ANIMATOR_SCALE = R.id.scale_animator_tag;
+    private static final int TAG_ANIMATOR_ALPHA = R.id.alpha_animator_tag;
+    private static final int TAG_ANIMATOR_HEIGHT = R.id.height_animator_tag;
+    private static final int TAG_ANIMATOR_TOP_INSET = R.id.top_inset_animator_tag;
+    private static final int TAG_END_TRANSLATION_Y = R.id.translation_y_animator_end_value_tag;
+    private static final int TAG_END_TRANSLATION_Z = R.id.translation_z_animator_end_value_tag;
+    private static final int TAG_END_SCALE = R.id.scale_animator_end_value_tag;
+    private static final int TAG_END_ALPHA = R.id.alpha_animator_end_value_tag;
+    private static final int TAG_END_HEIGHT = R.id.height_animator_end_value_tag;
+    private static final int TAG_END_TOP_INSET = R.id.top_inset_animator_end_value_tag;
+    private static final int TAG_START_TRANSLATION_Y = R.id.translation_y_animator_start_value_tag;
+    private static final int TAG_START_TRANSLATION_Z = R.id.translation_z_animator_start_value_tag;
+    private static final int TAG_START_SCALE = R.id.scale_animator_start_value_tag;
+    private static final int TAG_START_ALPHA = R.id.alpha_animator_start_value_tag;
+    private static final int TAG_START_HEIGHT = R.id.height_animator_start_value_tag;
+    private static final int TAG_START_TOP_INSET = R.id.top_inset_animator_start_value_tag;
 
     private final Interpolator mFastOutSlowInInterpolator;
     public NotificationStackScrollLayout mHostLayout;
-    private boolean mAnimationIsRunning;
-    private ArrayList<NotificationStackScrollLayout.ChildHierarchyChangeEvent> mHandledEvents =
+    private ArrayList<NotificationStackScrollLayout.AnimationEvent> mHandledEvents =
             new ArrayList<>();
+    private ArrayList<NotificationStackScrollLayout.AnimationEvent> mNewEvents =
+            new ArrayList<>();
+    private Set<Animator> mAnimatorSet = new HashSet<Animator>();
+    private Stack<AnimatorListenerAdapter> mAnimationListenerPool
+            = new Stack<AnimatorListenerAdapter>();
+    private AnimationFilter mAnimationFilter = new AnimationFilter();
+    private long mCurrentLength;
+
+    private ValueAnimator mTopOverScrollAnimator;
+    private ValueAnimator mBottomOverScrollAnimator;
 
     public StackStateAnimator(NotificationStackScrollLayout hostLayout) {
         mHostLayout = hostLayout;
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(hostLayout.getContext(),
-                        android.R.interpolator.fast_out_slow_in);
+                android.R.interpolator.fast_out_slow_in);
     }
 
     public boolean isRunning() {
-        return mAnimationIsRunning;
+        return !mAnimatorSet.isEmpty();
     }
 
     public void startAnimationForEvents(
-            ArrayList<NotificationStackScrollLayout.ChildHierarchyChangeEvent> mAnimationEvents,
+            ArrayList<NotificationStackScrollLayout.AnimationEvent> mAnimationEvents,
             StackScrollState finalState) {
-        int numEvents = mAnimationEvents.size();
-        if (numEvents == 0) {
-            // No events, so we don't perform any animation
-            return;
-        }
-        long lastEventStartTime = mAnimationEvents.get(numEvents - 1).eventStartTime;
-        long eventEnd = lastEventStartTime + ANIMATION_DURATION;
-        long currentTime = AnimationUtils.currentAnimationTimeMillis();
-        long newDuration = eventEnd - currentTime;
-        if (newDuration <= 0) {
-            // last event is long before this, so we don't do anything
-            return;
-        }
-        initializeAddedViewStates(mAnimationEvents, finalState);
+
+        processAnimationEvents(mAnimationEvents, finalState);
+
         int childCount = mHostLayout.getChildCount();
+        mAnimationFilter.applyCombination(mNewEvents);
+        mCurrentLength = NotificationStackScrollLayout.AnimationEvent.combineLength(mNewEvents);
         for (int i = 0; i < childCount; i++) {
-            final boolean isFirstView = i == 0;
             final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
             StackScrollState.ViewState viewState = finalState.getViewStateForView(child);
             if (viewState == null) {
                 continue;
             }
-            int childVisibility = child.getVisibility();
-            boolean wasVisible = childVisibility == View.VISIBLE;
-            final float alpha = viewState.alpha;
-            if (!wasVisible && alpha != 0 && !viewState.gone) {
-                child.setVisibility(View.VISIBLE);
-            }
 
-            startPropertyAnimation(newDuration, isFirstView, child, viewState, alpha);
+            startAnimations(child, viewState);
 
-            // TODO: animate clipBounds
             child.setClipBounds(null);
-            int currentHeigth = child.getActualHeight();
-            if (viewState.height != currentHeigth) {
-                startHeightAnimation(newDuration, child, viewState, currentHeigth);
+        }
+        if (!isRunning()) {
+            // no child has preformed any animation, lets finish
+            onAnimationFinished();
+        }
+    }
+
+    /**
+     * Start an animation to the given viewState
+     */
+    private void startAnimations(final ExpandableView child, StackScrollState.ViewState viewState) {
+        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 translationY animation
+        if (child.getTranslationY() != viewState.yTranslation) {
+            startYTranslationAnimation(child, viewState);
+        }
+        // start translationZ animation
+        if (child.getTranslationZ() != viewState.zTranslation) {
+            startZTranslationAnimation(child, viewState);
+        }
+        // start scale animation
+        if (child.getScaleX() != viewState.scale) {
+            startScaleAnimation(child, viewState);
+        }
+        // start alpha animation
+        if (alpha != child.getAlpha()) {
+            startAlphaAnimation(child, viewState);
+        }
+        // start height animation
+        if (viewState.height != child.getActualHeight()) {
+            startHeightAnimation(child, viewState);
+        }
+        // start dimmed animation
+        child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed);
+    }
+
+    private void startHeightAnimation(final ExpandableView child,
+            StackScrollState.ViewState viewState) {
+        Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT);
+        Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT);
+        int newEndValue = viewState.height;
+        if (previousEndValue != null && previousEndValue == newEndValue) {
+            return;
+        }
+        ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_HEIGHT);
+        if (!mAnimationFilter.animateHeight) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                int relativeDiff = newEndValue - previousEndValue;
+                int newStartValue = previousStartValue + relativeDiff;
+                values[0].setIntValues(newStartValue, newEndValue);
+                child.setTag(TAG_START_HEIGHT, newStartValue);
+                child.setTag(TAG_END_HEIGHT, newEndValue);
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                child.setActualHeight(newEndValue, false);
+                return;
             }
         }
-        mAnimationIsRunning = true;
-    }
 
-    private void startPropertyAnimation(long newDuration, final boolean isFirstView,
-            final ExpandableView child, StackScrollState.ViewState viewState, final float alpha) {
-        child.animate().setInterpolator(mFastOutSlowInInterpolator)
-                .alpha(alpha)
-                .translationY(viewState.yTranslation)
-                .translationZ(viewState.zTranslation)
-                .setDuration(newDuration)
-                .withEndAction(new Runnable() {
-                    @Override
-                    public void run() {
-                        mAnimationIsRunning = false;
-                        if (isFirstView) {
-                            mHandledEvents.clear();
-                            mHostLayout.onChildAnimationFinished();
-                        }
-                        if (alpha == 0) {
-                            child.setVisibility(View.INVISIBLE);
-                        }
-                    }
-                });
-    }
-
-    private void startHeightAnimation(long newDuration, final ExpandableView child,
-            StackScrollState.ViewState viewState, int currentHeigth) {
-        ValueAnimator heightAnimator = ValueAnimator.ofInt(currentHeigth, viewState.height);
-        heightAnimator.setInterpolator(mFastOutSlowInInterpolator);
-        heightAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+        ValueAnimator animator = ValueAnimator.ofInt(child.getActualHeight(), newEndValue);
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
-                child.setActualHeight((int) animation.getAnimatedValue());
+                child.setActualHeight((int) animation.getAnimatedValue(),
+                        false /* notifyListeners */);
             }
         });
-        heightAnimator.setDuration(newDuration);
-        heightAnimator.start();
+        animator.setInterpolator(mFastOutSlowInInterpolator);
+        long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+        animator.setDuration(newDuration);
+        animator.addListener(getGlobalAnimationFinishedListener());
+        // remove the tag when the animation is finished
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                child.setTag(TAG_ANIMATOR_HEIGHT, null);
+                child.setTag(TAG_START_HEIGHT, null);
+                child.setTag(TAG_END_HEIGHT, null);
+            }
+        });
+        startInstantly(animator);
+        child.setTag(TAG_ANIMATOR_HEIGHT, animator);
+        child.setTag(TAG_START_HEIGHT, child.getActualHeight());
+        child.setTag(TAG_END_HEIGHT, newEndValue);
     }
 
-    private void initializeAddedViewStates(
-            ArrayList<NotificationStackScrollLayout.ChildHierarchyChangeEvent> mAnimationEvents,
-            StackScrollState finalState) {
-        for (NotificationStackScrollLayout.ChildHierarchyChangeEvent event: mAnimationEvents) {
-            View changingView = event.changingView;
-            if (event.animationType == NotificationStackScrollLayout.ChildHierarchyChangeEvent
-                    .ANIMATION_TYPE_ADD && !mHandledEvents.contains(event)) {
-
-                // This item is added, initialize it's properties.
-                StackScrollState.ViewState viewState = finalState.getViewStateForView(changingView);
-                changingView.setAlpha(0);
-                changingView.setTranslationY(viewState.yTranslation);
-                changingView.setTranslationZ(viewState.zTranslation);
-                mHandledEvents.add(event);
+    private void startAlphaAnimation(final ExpandableView child,
+            final StackScrollState.ViewState viewState) {
+        Float previousStartValue = getChildTag(child,TAG_START_ALPHA);
+        Float previousEndValue = getChildTag(child,TAG_END_ALPHA);
+        final float newEndValue = viewState.alpha;
+        if (previousEndValue != null && previousEndValue == newEndValue) {
+            return;
+        }
+        ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_ALPHA);
+        if (!mAnimationFilter.animateAlpha) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                float relativeDiff = newEndValue - previousEndValue;
+                float newStartValue = previousStartValue + relativeDiff;
+                values[0].setFloatValues(newStartValue, newEndValue);
+                child.setTag(TAG_START_ALPHA, newStartValue);
+                child.setTag(TAG_END_ALPHA, newEndValue);
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                child.setAlpha(newEndValue);
+                if (newEndValue == 0) {
+                    child.setVisibility(View.INVISIBLE);
+                }
             }
         }
+
+        ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.ALPHA,
+                child.getAlpha(), newEndValue);
+        animator.setInterpolator(mFastOutSlowInInterpolator);
+        // Handle layer type
+        final int currentLayerType = child.getLayerType();
+        child.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+        animator.addListener(new AnimatorListenerAdapter() {
+            public boolean mWasCancelled;
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                child.setLayerType(currentLayerType, null);
+                if (newEndValue == 0 && !mWasCancelled) {
+                    child.setVisibility(View.INVISIBLE);
+                }
+                child.setTag(TAG_ANIMATOR_ALPHA, null);
+                child.setTag(TAG_START_ALPHA, null);
+                child.setTag(TAG_END_ALPHA, null);
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                mWasCancelled = true;
+            }
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mWasCancelled = false;
+            }
+        });
+        long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+        animator.setDuration(newDuration);
+        animator.addListener(getGlobalAnimationFinishedListener());
+        // remove the tag when the animation is finished
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+
+            }
+        });
+        startInstantly(animator);
+        child.setTag(TAG_ANIMATOR_ALPHA, animator);
+        child.setTag(TAG_START_ALPHA, child.getAlpha());
+        child.setTag(TAG_END_ALPHA, newEndValue);
+    }
+
+    private void startZTranslationAnimation(final ExpandableView child,
+            final StackScrollState.ViewState viewState) {
+        Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Z);
+        Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z);
+        float newEndValue = viewState.zTranslation;
+        if (previousEndValue != null && previousEndValue == newEndValue) {
+            return;
+        }
+        ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Z);
+        if (!mAnimationFilter.animateZ) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                float relativeDiff = newEndValue - previousEndValue;
+                float newStartValue = previousStartValue + relativeDiff;
+                values[0].setFloatValues(newStartValue, newEndValue);
+                child.setTag(TAG_START_TRANSLATION_Z, newStartValue);
+                child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                child.setTranslationZ(newEndValue);
+            }
+        }
+
+        ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Z,
+                child.getTranslationZ(), newEndValue);
+        animator.setInterpolator(mFastOutSlowInInterpolator);
+        long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+        animator.setDuration(newDuration);
+        animator.addListener(getGlobalAnimationFinishedListener());
+        // remove the tag when the animation is finished
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                child.setTag(TAG_ANIMATOR_TRANSLATION_Z, null);
+                child.setTag(TAG_START_TRANSLATION_Z, null);
+                child.setTag(TAG_END_TRANSLATION_Z, null);
+            }
+        });
+        startInstantly(animator);
+        child.setTag(TAG_ANIMATOR_TRANSLATION_Z, animator);
+        child.setTag(TAG_START_TRANSLATION_Z, child.getTranslationZ());
+        child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
+    }
+
+    private void startYTranslationAnimation(final ExpandableView child,
+            StackScrollState.ViewState viewState) {
+        Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Y);
+        Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y);
+        float newEndValue = viewState.yTranslation;
+        if (previousEndValue != null && previousEndValue == newEndValue) {
+            return;
+        }
+        ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y);
+        if (!mAnimationFilter.animateY) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                float relativeDiff = newEndValue - previousEndValue;
+                float newStartValue = previousStartValue + relativeDiff;
+                values[0].setFloatValues(newStartValue, newEndValue);
+                child.setTag(TAG_START_TRANSLATION_Y, newStartValue);
+                child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                child.setTranslationY(newEndValue);
+                return;
+            }
+        }
+
+        ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Y,
+                child.getTranslationY(), newEndValue);
+        animator.setInterpolator(mFastOutSlowInInterpolator);
+        long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+        animator.setDuration(newDuration);
+        animator.addListener(getGlobalAnimationFinishedListener());
+        // remove the tag when the animation is finished
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                child.setTag(TAG_ANIMATOR_TRANSLATION_Y, null);
+                child.setTag(TAG_START_TRANSLATION_Y, null);
+                child.setTag(TAG_END_TRANSLATION_Y, null);
+            }
+        });
+        startInstantly(animator);
+        child.setTag(TAG_ANIMATOR_TRANSLATION_Y, animator);
+        child.setTag(TAG_START_TRANSLATION_Y, child.getTranslationY());
+        child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
+    }
+
+    private void startScaleAnimation(final ExpandableView child,
+            StackScrollState.ViewState viewState) {
+        Float previousStartValue = getChildTag(child, TAG_START_SCALE);
+        Float previousEndValue = getChildTag(child, TAG_END_SCALE);
+        float newEndValue = viewState.scale;
+        if (previousEndValue != null && previousEndValue == newEndValue) {
+            return;
+        }
+        ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_SCALE);
+        if (!mAnimationFilter.animateScale) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                float relativeDiff = newEndValue - previousEndValue;
+                float newStartValue = previousStartValue + relativeDiff;
+                values[0].setFloatValues(newStartValue, newEndValue);
+                values[1].setFloatValues(newStartValue, newEndValue);
+                child.setTag(TAG_START_SCALE, newStartValue);
+                child.setTag(TAG_END_SCALE, newEndValue);
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                child.setScaleX(newEndValue);
+                child.setScaleY(newEndValue);
+            }
+        }
+
+        PropertyValuesHolder holderX =
+                PropertyValuesHolder.ofFloat(View.SCALE_X, child.getScaleX(), newEndValue);
+        PropertyValuesHolder holderY =
+                PropertyValuesHolder.ofFloat(View.SCALE_Y, child.getScaleY(), newEndValue);
+        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(child, holderX, holderY);
+        animator.setInterpolator(mFastOutSlowInInterpolator);
+        long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+        animator.setDuration(newDuration);
+        animator.addListener(getGlobalAnimationFinishedListener());
+        // remove the tag when the animation is finished
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                child.setTag(TAG_ANIMATOR_SCALE, null);
+                child.setTag(TAG_START_SCALE, null);
+                child.setTag(TAG_END_SCALE, null);
+            }
+        });
+        startInstantly(animator);
+        child.setTag(TAG_ANIMATOR_SCALE, animator);
+        child.setTag(TAG_START_SCALE, child.getScaleX());
+        child.setTag(TAG_END_SCALE, newEndValue);
+    }
+
+    /**
+     * Start an animator instantly instead of waiting on the next synchronization frame
+     */
+    private void startInstantly(ValueAnimator animator) {
+        animator.start();
+        animator.setCurrentPlayTime(0);
+    }
+
+    /**
+     * @return an adapter which ensures that onAnimationFinished is called once no animation is
+     *         running anymore
+     */
+    private AnimatorListenerAdapter getGlobalAnimationFinishedListener() {
+        if (!mAnimationListenerPool.empty()) {
+            return mAnimationListenerPool.pop();
+        }
+
+        // We need to create a new one, no reusable ones found
+        return new AnimatorListenerAdapter() {
+            private boolean mWasCancelled;
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mAnimatorSet.remove(animation);
+                if (mAnimatorSet.isEmpty() && !mWasCancelled) {
+                    onAnimationFinished();
+                }
+                mAnimationListenerPool.push(this);
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                mWasCancelled = true;
+            }
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mAnimatorSet.add(animation);
+                mWasCancelled = false;
+            }
+        };
+    }
+
+    private <T> T getChildTag(View child, int tag) {
+        return (T) child.getTag(tag);
+    }
+
+    /**
+     * Cancel the previous animator and get the duration of the new animation.
+     *
+     * @param previousAnimator the animator which was running before
+     * @return the new duration
+     */
+    private long cancelAnimatorAndGetNewDuration(ValueAnimator previousAnimator) {
+        long newDuration = mCurrentLength;
+        if (previousAnimator != null) {
+            // We take either the desired length of the new animation or the remaining time of
+            // the previous animator, whichever is longer.
+            newDuration = Math.max(previousAnimator.getDuration()
+                    - previousAnimator.getCurrentPlayTime(), newDuration);
+            previousAnimator.cancel();
+        }
+        return newDuration;
+    }
+
+    private void onAnimationFinished() {
+        mHandledEvents.clear();
+        mNewEvents.clear();
+        mHostLayout.onChildAnimationFinished();
+    }
+
+    /**
+     * Process the animationEvents for a new animation
+     *
+     * @param animationEvents the animation events for the animation to perform
+     * @param finalState the final state to animate to
+     */
+    private void processAnimationEvents(
+            ArrayList<NotificationStackScrollLayout.AnimationEvent> animationEvents,
+            StackScrollState finalState) {
+        mNewEvents.clear();
+        for (NotificationStackScrollLayout.AnimationEvent event : animationEvents) {
+            View changingView = event.changingView;
+            if (!mHandledEvents.contains(event)) {
+                if (event.animationType == NotificationStackScrollLayout.AnimationEvent
+                        .ANIMATION_TYPE_ADD) {
+
+                    // This item is added, initialize it's properties.
+                    StackScrollState.ViewState viewState = finalState
+                            .getViewStateForView(changingView);
+                    if (viewState == null) {
+                        // The position for this child was never generated, let's continue.
+                        continue;
+                    }
+                    changingView.setAlpha(0);
+                    changingView.setTranslationY(viewState.yTranslation);
+                    changingView.setTranslationZ(viewState.zTranslation);
+                }
+                mHandledEvents.add(event);
+                mNewEvents.add(event);
+            }
+        }
+    }
+
+    public void animateOverScrollToAmount(float targetAmount, final boolean onTop) {
+        final float startOverScrollAmount = mHostLayout.getCurrentOverScrollAmount(onTop);
+        cancelOverScrollAnimators(onTop);
+        ValueAnimator overScrollAnimator = ValueAnimator.ofFloat(startOverScrollAmount,
+                targetAmount);
+        overScrollAnimator.setDuration(ANIMATION_DURATION_STANDARD);
+        overScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float currentOverScroll = (float) animation.getAnimatedValue();
+                mHostLayout.setOverScrollAmount(currentOverScroll, onTop, false /* animate */,
+                        false /* cancelAnimators */);
+            }
+        });
+        overScrollAnimator.setInterpolator(mFastOutSlowInInterpolator);
+        overScrollAnimator.start();
+        if (onTop) {
+            mTopOverScrollAnimator = overScrollAnimator;
+        } else {
+            mBottomOverScrollAnimator = overScrollAnimator;
+        }
+    }
+
+    public void cancelOverScrollAnimators(boolean onTop) {
+        ValueAnimator currentAnimator = onTop ? mTopOverScrollAnimator : mBottomOverScrollAnimator;
+        if (currentAnimator != null) {
+            currentAnimator.cancel();
+        }
     }
 }
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 d615542..9006c9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -78,7 +78,8 @@
     }
 
     @Override
-    public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
+    public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+            boolean showImeSwitcher) {
     }
 
     @Override
@@ -120,11 +121,6 @@
     }
 
     @Override
-    protected int getExpandedViewMaxHeight() {
-        return 0;
-    }
-
-    @Override
     protected boolean shouldDisableNavbarGestures() {
         return true;
     }
@@ -154,4 +150,11 @@
     protected void refreshLayout(int layoutDirection) {
     }
 
+    @Override
+    public void onActivated(View view) {
+    }
+
+    @Override
+    public void onActivationReset(View view) {
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 0550dd4..6341a0c 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -44,6 +44,7 @@
 import android.app.KeyguardManager;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -301,6 +302,11 @@
             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);
     }
 
@@ -3560,27 +3566,19 @@
         swipeDismiss.setOnDismissedListener(new SwipeDismissLayout.OnDismissedListener() {
             @Override
             public void onDismissed(SwipeDismissLayout layout) {
-                Callback cb = getCallback();
-                if (cb != null) {
-                    try {
-                        cb.onWindowDismissed();
-                    } catch (AbstractMethodError e) {
-                        Log.e(TAG, "onWindowDismissed not implemented in " +
-                                cb.getClass().getSimpleName(), e);
-                    }
-                }
+                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;
+                        newParams.alpha = 1 - (progress * ALPHA_DECREASE);
                         setAttributes(newParams);
 
                         int flags = 0;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 8bc669a..4ee8103 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -667,7 +667,8 @@
     private void interceptPowerKeyDown(boolean handled) {
         mPowerKeyHandled = handled;
         if (!handled) {
-            mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
+            mHandler.postDelayed(mPowerLongPress,
+                    ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
         }
     }
 
@@ -706,9 +707,9 @@
         if (mKeyguardDelegate.isShowing()) {
             // Double the time it takes to take a screenshot from the keyguard
             return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER *
-                    ViewConfiguration.getGlobalActionKeyTimeout());
+                    ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
         }
-        return ViewConfiguration.getGlobalActionKeyTimeout();
+        return ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout();
     }
 
     private void cancelPendingScreenshotChordAction() {
@@ -990,9 +991,9 @@
 
         // Match current screen state.
         if (mPowerManager.isInteractive()) {
-            screenTurningOn(null);
+            wakingUp(null);
         } else {
-            screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
+            goingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
         }
     }
 
@@ -4314,7 +4315,7 @@
     }
 
     @Override
-    public void screenTurnedOff(int why) {
+    public void goingToSleep(int why) {
         EventLog.writeEvent(70000, 0);
         synchronized (mLock) {
             mScreenOnEarly = false;
@@ -4330,7 +4331,7 @@
     }
 
     @Override
-    public void screenTurningOn(final ScreenOnListener screenOnListener) {
+    public void wakingUp(final ScreenOnListener screenOnListener) {
         EventLog.writeEvent(70000, 1);
         if (false) {
             RuntimeException here = new RuntimeException("here");
@@ -4776,7 +4777,18 @@
         mHandler.post(new Runnable() {
             @Override public void run() {
                 if (mBootMsgDialog == null) {
-                    mBootMsgDialog = new ProgressDialog(mContext) {
+                    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) {
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index dce4f581..a62d1fd 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -63,6 +63,25 @@
     static Method registerNativeAllocation;
     static Method registerNativeFree;
 
+    /*
+     * Context creation flag which specifies a normal context.
+    */
+    public static final long CREATE_FLAG_NONE = 0x0000;
+
+    /*
+     * Context creation flag which specifies a context optimized for low
+     * latency over peak performance. This is a hint and may have no effect
+     * on some implementations.
+    */
+    public static final long CREATE_FLAG_LOW_LATENCY = 0x0001;
+
+    /*
+     * Context creation flag which specifies a context optimized for long
+     * battery life over peak performance. This is a hint and may have no effect
+     * on some implementations.
+    */
+    public static final long CREATE_FLAG_LOW_POWER = 0x0002;
+
     static {
         sInitialized = false;
         if (!SystemProperties.getBoolean("config.disable_renderscript", false)) {
@@ -1145,7 +1164,7 @@
      * @hide
      */
     public static RenderScript create(Context ctx, int sdkVersion) {
-        return create(ctx, sdkVersion, ContextType.NORMAL);
+        return create(ctx, sdkVersion, ContextType.NORMAL, CREATE_FLAG_NONE);
     }
 
     /**
@@ -1155,7 +1174,7 @@
      * @param ctx The context.
      * @return RenderScript
      */
-    public static RenderScript create(Context ctx, int sdkVersion, ContextType ct) {
+    public static RenderScript create(Context ctx, int sdkVersion, ContextType ct, long flags) {
         if (!sInitialized) {
             Log.e(LOG_TAG, "RenderScript.create() called when disabled; someone is likely to crash");
             return null;
@@ -1194,7 +1213,21 @@
      */
     public static RenderScript create(Context ctx, ContextType ct) {
         int v = ctx.getApplicationInfo().targetSdkVersion;
-        return create(ctx, v, ct);
+        return create(ctx, v, ct, CREATE_FLAG_NONE);
+    }
+
+     /**
+     * Create a RenderScript context.
+     *
+     *
+     * @param ctx The context.
+     * @param ct The type of context to be created.
+     * @param flags The OR of the CREATE_FLAG_* options desired
+     * @return RenderScript
+     */
+    public static RenderScript create(Context ctx, ContextType ct, long flags) {
+        int v = ctx.getApplicationInfo().targetSdkVersion;
+        return create(ctx, v, ct, flags);
     }
 
     /**
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index 07933b4..f1ddc07 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -27,7 +27,6 @@
 
 LOCAL_CFLAGS += -Wno-unused-parameter
 
-LOCAL_LDLIBS := -lpthread
 LOCAL_ADDITIONAL_DEPENDENCIES := $(addprefix $(rs_generated_include_dir)/,rsgApiFuncDecl.h)
 LOCAL_MODULE:= librs_jni
 LOCAL_ADDITIONAL_DEPENDENCIES += $(rs_generated_source)
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 3619112..36b5cfb 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -38,6 +38,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -197,6 +198,8 @@
 
     private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
 
+    private final UserManager mUserManager;
+
     private int mCurrentUserId = UserHandle.USER_OWNER;
 
     private final LongArray mTempLongArray = new LongArray();
@@ -210,15 +213,6 @@
         return getUserStateLocked(mCurrentUserId);
     }
 
-    private UserState getUserStateLocked(int userId) {
-        UserState state = mUserStates.get(userId);
-        if (state == null) {
-            state = new UserState(userId);
-            mUserStates.put(userId, state);
-        }
-        return state;
-    }
-
     /**
      * Creates a new instance.
      *
@@ -228,6 +222,7 @@
         mContext = context;
         mPackageManager = mContext.getPackageManager();
         mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
+        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
         mSecurityPolicy = new SecurityPolicy();
         mMainHandler = new MainHandler(mContext.getMainLooper());
         registerBroadcastReceivers();
@@ -235,11 +230,22 @@
                 context.getContentResolver());
     }
 
+    private UserState getUserStateLocked(int userId) {
+        UserState state = mUserStates.get(userId);
+        if (state == null) {
+            state = new UserState(userId);
+            mUserStates.put(userId, state);
+        }
+        return state;
+    }
+
     private void registerBroadcastReceivers() {
         PackageMonitor monitor = new PackageMonitor() {
             @Override
             public void onSomePackagesChanged() {
                 synchronized (mLock) {
+                    // Only the profile parent can install accessibility services.
+                    // Therefore we ignore packages from linked profiles.
                     if (getChangingUserId() != mCurrentUserId) {
                         return;
                     }
@@ -262,6 +268,8 @@
             public void onPackageRemoved(String packageName, int uid) {
                 synchronized (mLock) {
                     final int userId = getChangingUserId();
+                    // Only the profile parent can install accessibility services.
+                    // Therefore we ignore packages from linked profiles.
                     if (userId != mCurrentUserId) {
                         return;
                     }
@@ -297,6 +305,8 @@
                     int uid, boolean doit) {
                 synchronized (mLock) {
                     final int userId = getChangingUserId();
+                    // Only the profile parent can install accessibility services.
+                    // Therefore we ignore packages from linked profiles.
                     if (userId != mCurrentUserId) {
                         return false;
                     }
@@ -359,6 +369,9 @@
     @Override
     public int addClient(IAccessibilityManagerClient client, int userId) {
         synchronized (mLock) {
+            // We treat calls from a profile as if made by its parent as profiles
+            // share the accessibility state of the parent. The call below
+            // performs the current profile parent resolution.
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
             // If the client is from a process that runs across users such as
@@ -388,6 +401,9 @@
     @Override
     public boolean sendAccessibilityEvent(AccessibilityEvent event, int userId) {
         synchronized (mLock) {
+            // We treat calls from a profile as if made by its parent as profiles
+            // share the accessibility state of the parent. The call below
+            // performs the current profile parent resolution..
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
             // This method does nothing for a background user.
@@ -414,6 +430,9 @@
     @Override
     public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
         synchronized (mLock) {
+            // We treat calls from a profile as if made by its parent as profiles
+            // share the accessibility state of the parent. The call below
+            // performs the current profile parent resolution.
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
             // The automation service is a fake one and should not be reported
@@ -435,6 +454,9 @@
             int userId) {
         List<AccessibilityServiceInfo> result = null;
         synchronized (mLock) {
+            // We treat calls from a profile as if made by its parent as profiles
+            // share the accessibility state of the parent. The call below
+            // performs the current profile parent resolution.
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
 
@@ -468,6 +490,9 @@
     public void interrupt(int userId) {
         CopyOnWriteArrayList<Service> services;
         synchronized (mLock) {
+            // We treat calls from a profile as if made by its parent as profiles
+            // share the accessibility state of the parent. The call below
+            // performs the current profile parent resolution.
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
             // This method does nothing for a background user.
@@ -491,6 +516,9 @@
     public int addAccessibilityInteractionConnection(IWindow windowToken,
             IAccessibilityInteractionConnection connection, int userId) throws RemoteException {
         synchronized (mLock) {
+            // We treat calls from a profile as if made by its parent as profiles
+            // share the accessibility state of the parent. The call below
+            // performs the current profile parent resolution.
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
             final int windowId = sNextWindowId++;
@@ -527,6 +555,9 @@
     @Override
     public void removeAccessibilityInteractionConnection(IWindow window) {
         synchronized (mLock) {
+            // We treat calls from a profile as if made by its parent as profiles
+            // share the accessibility state of the parent. The call below
+            // performs the current profile parent resolution.
             mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
                     UserHandle.getCallingUserId());
             IBinder token = window.asBinder();
@@ -675,6 +706,9 @@
                 Manifest.permission.RETRIEVE_WINDOW_TOKEN,
                 GET_WINDOW_TOKEN);
         synchronized (mLock) {
+            // We treat calls from a profile as if made by its parent as profiles
+            // share the accessibility state of the parent. The call below
+            // performs the current profile parent resolution.
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(
                             UserHandle.getCallingUserId());
@@ -770,7 +804,7 @@
             }
 
             // Disconnect from services for the old user.
-            UserState oldUserState = getUserStateLocked(mCurrentUserId);
+            UserState oldUserState = getCurrentUserStateLocked();
             oldUserState.onSwitchToAnotherUser();
 
             // Disable the local managers for the old user.
@@ -2034,6 +2068,9 @@
         @Override
         public List<AccessibilityWindowInfo> getWindows() {
             synchronized (mLock) {
+                // We treat calls from a profile as if made by its perent as profiles
+                // share the accessibility state of the parent. The call below
+                // performs the current profile parent resolution.
                 final int resolvedUserId = mSecurityPolicy
                         .resolveCallingUserIdEnforcingPermissionsLocked(
                                 UserHandle.getCallingUserId());
@@ -2062,6 +2099,9 @@
         @Override
         public AccessibilityWindowInfo getWindow(int windowId) {
             synchronized (mLock) {
+                // We treat calls from a profile as if made by its parent as profiles
+                // share the accessibility state of the parent. The call below
+                // performs the current profile parent resolution.
                 final int resolvedUserId = mSecurityPolicy
                         .resolveCallingUserIdEnforcingPermissionsLocked(
                                 UserHandle.getCallingUserId());
@@ -2092,6 +2132,9 @@
             final int resolvedWindowId;
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                // We treat calls from a profile as if made by its parent as profiles
+                // share the accessibility state of the parent. The call below
+                // performs the current profile parent resolution.
                 final int resolvedUserId = mSecurityPolicy
                         .resolveCallingUserIdEnforcingPermissionsLocked(
                                 UserHandle.getCallingUserId());
@@ -2136,9 +2179,12 @@
             final int resolvedWindowId;
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                // We treat calls from a profile as if made by its parent as profiles
+                // share the accessibility state of the parent. The call below
+                // performs the current profile parent resolution.
                 final int resolvedUserId = mSecurityPolicy
                         .resolveCallingUserIdEnforcingPermissionsLocked(
-                        UserHandle.getCallingUserId());
+                                UserHandle.getCallingUserId());
                 if (resolvedUserId != mCurrentUserId) {
                     return false;
                 }
@@ -2180,9 +2226,12 @@
             final int resolvedWindowId;
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                // We treat calls from a profile as if made by its parent as profiles
+                // share the accessibility state of the parent. The call below
+                // performs the current profile parent resolution.
                 final int resolvedUserId = mSecurityPolicy
                         .resolveCallingUserIdEnforcingPermissionsLocked(
-                        UserHandle.getCallingUserId());
+                                UserHandle.getCallingUserId());
                 if (resolvedUserId != mCurrentUserId) {
                     return false;
                 }
@@ -2224,9 +2273,12 @@
             final int resolvedWindowId;
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                // We treat calls from a profile as if made by its parent as profiles
+                // share the accessibility state of the parent. The call below
+                // performs the current profile parent resolution.
                 final int resolvedUserId = mSecurityPolicy
                         .resolveCallingUserIdEnforcingPermissionsLocked(
-                        UserHandle.getCallingUserId());
+                                UserHandle.getCallingUserId());
                 if (resolvedUserId != mCurrentUserId) {
                     return false;
                 }
@@ -2268,9 +2320,12 @@
             final int resolvedWindowId;
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                // We treat calls from a profile as if made by its parent as profiles
+                // share the accessibility state of the parent. The call below
+                // performs the current profile parent resolution.
                 final int resolvedUserId = mSecurityPolicy
                         .resolveCallingUserIdEnforcingPermissionsLocked(
-                        UserHandle.getCallingUserId());
+                                UserHandle.getCallingUserId());
                 if (resolvedUserId != mCurrentUserId) {
                     return false;
                 }
@@ -2311,9 +2366,12 @@
             final int resolvedWindowId;
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                // We treat calls from a profile as if made by its parent as profiles
+                // share the accessibility state of the parent. The call below
+                // performs the current profile parent resolution.
                 final int resolvedUserId = mSecurityPolicy
                         .resolveCallingUserIdEnforcingPermissionsLocked(
-                        UserHandle.getCallingUserId());
+                                UserHandle.getCallingUserId());
                 if (resolvedUserId != mCurrentUserId) {
                     return false;
                 }
@@ -2346,9 +2404,12 @@
 
         public boolean performGlobalAction(int action) {
             synchronized (mLock) {
+                // We treat calls from a profile as if made by its parent as profiles
+                // share the accessibility state of the parent. The call below
+                // performs the current profile parent resolution.
                 final int resolvedUserId = mSecurityPolicy
                         .resolveCallingUserIdEnforcingPermissionsLocked(
-                        UserHandle.getCallingUserId());
+                                UserHandle.getCallingUserId());
                 if (resolvedUserId != mCurrentUserId) {
                     return false;
                 }
@@ -3407,16 +3468,35 @@
                     & AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0;
         }
 
+        private int resolveProfileParentLocked(int userId) {
+            if (userId != mCurrentUserId) {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    UserInfo parent = mUserManager.getProfileParent(userId);
+                    if (parent != null) {
+                        return parent.getUserHandle().getIdentifier();
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+            return userId;
+        }
+
         public int resolveCallingUserIdEnforcingPermissionsLocked(int userId) {
             final int callingUid = Binder.getCallingUid();
             if (callingUid == 0
                     || callingUid == Process.SYSTEM_UID
                     || callingUid == Process.SHELL_UID) {
-                return mCurrentUserId;
+                if (userId == UserHandle.USER_CURRENT
+                        || userId == UserHandle.USER_CURRENT_OR_SELF) {
+                    return mCurrentUserId;
+                }
+                return resolveProfileParentLocked(userId);
             }
             final int callingUserId = UserHandle.getUserId(callingUid);
             if (callingUserId == userId) {
-                return userId;
+                return resolveProfileParentLocked(userId);
             }
             if (!hasPermission(Manifest.permission.INTERACT_ACROSS_USERS)
                     && !hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) {
@@ -3618,17 +3698,8 @@
         private final Uri mEnhancedWebAccessibilityUri = Settings.Secure
                 .getUriFor(Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION);
 
-        private final Uri mDisplayContrastEnabledUri = Settings.Secure.getUriFor(
-                Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED);
-        private final Uri mDisplayContrastUri = Settings.Secure.getUriFor(
-                Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST);
-        private final Uri mDisplayBrightnessUri = Settings.Secure.getUriFor(
-                Settings.Secure.ACCESSIBILITY_DISPLAY_BRIGHTNESS);
-
         private final Uri mDisplayInversionEnabledUri = Settings.Secure.getUriFor(
                 Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
-        private final Uri mDisplayInversionUri = Settings.Secure.getUriFor(
-                Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION);
 
         private final Uri mDisplayDaltonizerEnabledUri = Settings.Secure.getUriFor(
                 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED);
@@ -3654,16 +3725,8 @@
             contentResolver.registerContentObserver(mEnhancedWebAccessibilityUri,
                     false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(
-                    mDisplayContrastEnabledUri, false, this, UserHandle.USER_ALL);
-            contentResolver.registerContentObserver(
-                    mDisplayContrastUri, false, this, UserHandle.USER_ALL);
-            contentResolver.registerContentObserver(
-                    mDisplayBrightnessUri, false, this, UserHandle.USER_ALL);
-            contentResolver.registerContentObserver(
                     mDisplayInversionEnabledUri, false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(
-                    mDisplayInversionUri, false, this, UserHandle.USER_ALL);
-            contentResolver.registerContentObserver(
                     mDisplayDaltonizerEnabledUri, false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(
                     mDisplayDaltonizerUri, false, this, UserHandle.USER_ALL);
@@ -3673,8 +3736,10 @@
         public void onChange(boolean selfChange, Uri uri) {
             if (mAccessibilityEnabledUri.equals(uri)) {
                 synchronized (mLock) {
-                    // We will update when the automation service dies.
+                    // Profiles share the accessibility state of the parent. Therefore,
+                    // we are checking for changes only the parent settings.
                     UserState userState = getCurrentUserStateLocked();
+                    // We will update when the automation service dies.
                     if (userState.mUiAutomationService == null) {
                         if (readAccessibilityEnabledSettingLocked(userState)) {
                             onUserStateChangedLocked(userState);
@@ -3683,8 +3748,10 @@
                 }
             } else if (mTouchExplorationEnabledUri.equals(uri)) {
                 synchronized (mLock) {
-                    // We will update when the automation service dies.
+                    // Profiles share the accessibility state of the parent. Therefore,
+                    // we are checking for changes only the parent settings.
                     UserState userState = getCurrentUserStateLocked();
+                    // We will update when the automation service dies.
                     if (userState.mUiAutomationService == null) {
                         if (readTouchExplorationEnabledSettingLocked(userState)) {
                             onUserStateChangedLocked(userState);
@@ -3693,8 +3760,10 @@
                 }
             } else if (mDisplayMagnificationEnabledUri.equals(uri)) {
                 synchronized (mLock) {
-                    // We will update when the automation service dies.
+                    // Profiles share the accessibility state of the parent. Therefore,
+                    // we are checking for changes only the parent settings.
                     UserState userState = getCurrentUserStateLocked();
+                    // We will update when the automation service dies.
                     if (userState.mUiAutomationService == null) {
                         if (readDisplayMagnificationEnabledSettingLocked(userState)) {
                             onUserStateChangedLocked(userState);
@@ -3703,8 +3772,10 @@
                 }
             } else if (mEnabledAccessibilityServicesUri.equals(uri)) {
                 synchronized (mLock) {
-                    // We will update when the automation service dies.
+                    // Profiles share the accessibility state of the parent. Therefore,
+                    // we are checking for changes only the parent settings.
                     UserState userState = getCurrentUserStateLocked();
+                    // We will update when the automation service dies.
                     if (userState.mUiAutomationService == null) {
                         if (readEnabledAccessibilityServicesLocked(userState)) {
                             onUserStateChangedLocked(userState);
@@ -3713,8 +3784,10 @@
                 }
             } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) {
                 synchronized (mLock) {
-                    // We will update when the automation service dies.
+                    // Profiles share the accessibility state of the parent. Therefore,
+                    // we are checking for changes only the parent settings.
                     UserState userState = getCurrentUserStateLocked();
+                    // We will update when the automation service dies.
                     if (userState.mUiAutomationService == null) {
                         if (readTouchExplorationGrantedAccessibilityServicesLocked(userState)) {
                             onUserStateChangedLocked(userState);
@@ -3723,24 +3796,24 @@
                 }
             } else if (mEnhancedWebAccessibilityUri.equals(uri)) {
                 synchronized (mLock) {
-                    // We will update when the automation service dies.
+                    // Profiles share the accessibility state of the parent. Therefore,
+                    // we are checking for changes only the parent settings.
                     UserState userState = getCurrentUserStateLocked();
+                    // We will update when the automation service dies.
                     if (userState.mUiAutomationService == null) {
                         if (readEnhancedWebAccessibilityEnabledChangedLocked(userState)) {
                             onUserStateChangedLocked(userState);
                         }
                     }
                 }
-            } else if (mDisplayContrastEnabledUri.equals(uri)
-                    || mDisplayInversionEnabledUri.equals(uri)
+            } else if (mDisplayInversionEnabledUri.equals(uri)
                     || mDisplayDaltonizerEnabledUri.equals(uri)
-                    || mDisplayContrastUri.equals(uri)
-                    || mDisplayBrightnessUri.equals(uri)
-                    || mDisplayInversionUri.equals(uri)
                     || mDisplayDaltonizerUri.equals(uri)) {
                 synchronized (mLock) {
-                    // We will update when the automation service dies.
+                    // Profiles share the accessibility state of the parent. Therefore,
+                    // we are checking for changes only the parent settings.
                     UserState userState = getCurrentUserStateLocked();
+                    // We will update when the automation service dies.
                     if (userState.mUiAutomationService == null) {
                         if (readDisplayColorAdjustmentSettingsLocked(userState)) {
                             updateDisplayColorAdjustmentSettingsLocked(userState);
diff --git a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
index 52bdeda..394c196 100644
--- a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
+++ b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
@@ -41,22 +41,6 @@
              0,      0,      0, 1
     };
 
-    /** Matrix and offset used for standard display inversion. */
-    private static final float[] INVERSION_MATRIX_STANDARD = new float[] {
-        -1,  0,  0, 0,
-         0, -1,  0, 0,
-         0,  0, -1, 0,
-         1,  1,  1, 1
-    };
-
-    /** Matrix and offset used for hue-only display inversion. */
-    private static final float[] INVERSION_MATRIX_HUE_ONLY = new float[] {
-          0, .5f, .5f, 0,
-        .5f,   0, .5f, 0,
-        .5f, .5f,   0, 0,
-          0,   0,   0, 1
-    };
-
     /** Matrix and offset used for value-only display inversion. */
     private static final float[] INVERSION_MATRIX_VALUE_ONLY = new float[] {
            0, -.5f, -.5f, 0,
@@ -65,15 +49,6 @@
            1,    1,    1, 1
     };
 
-    /** Default contrast for display contrast enhancement. */
-    private static final float DEFAULT_DISPLAY_CONTRAST = 2;
-
-    /** Default brightness for display contrast enhancement. */
-    private static final float DEFAULT_DISPLAY_BRIGHTNESS = 0;
-
-    /** Default inversion mode for display color inversion. */
-    private static final int DEFAULT_DISPLAY_INVERSION = AccessibilityManager.INVERSION_STANDARD;
-
     /** Default inversion mode for display color correction. */
     private static final int DEFAULT_DISPLAY_DALTONIZER =
             AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY;
@@ -90,11 +65,6 @@
 
         if (!hasColorTransform) {
             hasColorTransform |= Settings.Secure.getIntForUser(
-                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED, 0, userId) == 1;
-        }
-
-        if (!hasColorTransform) {
-            hasColorTransform |= Settings.Secure.getIntForUser(
                 cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) == 1;
         }
 
@@ -115,21 +85,7 @@
         final boolean inversionEnabled = Settings.Secure.getIntForUser(
                 cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) == 1;
         if (inversionEnabled) {
-            final int inversionMode = Settings.Secure.getIntForUser(cr,
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION, DEFAULT_DISPLAY_INVERSION,
-                    userId);
-            final float[] inversionMatrix;
-            switch (inversionMode) {
-                case AccessibilityManager.INVERSION_HUE_ONLY:
-                    inversionMatrix = INVERSION_MATRIX_HUE_ONLY;
-                    break;
-                case AccessibilityManager.INVERSION_VALUE_ONLY:
-                    inversionMatrix = INVERSION_MATRIX_VALUE_ONLY;
-                    break;
-                default:
-                    inversionMatrix = INVERSION_MATRIX_STANDARD;
-            }
-
+            final float[] inversionMatrix = INVERSION_MATRIX_VALUE_ONLY;
             Matrix.multiplyMM(outputMatrix, 0, colorMatrix, 0, inversionMatrix, 0);
 
             colorMatrix = outputMatrix;
@@ -138,31 +94,6 @@
             hasColorTransform = true;
         }
 
-        final boolean contrastEnabled = Settings.Secure.getIntForUser(
-                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED, 0, userId) == 1;
-        if (contrastEnabled) {
-            final float contrast = Settings.Secure.getFloatForUser(cr,
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST, DEFAULT_DISPLAY_CONTRAST,
-                    userId);
-            final float brightness = Settings.Secure.getFloatForUser(cr,
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_BRIGHTNESS, DEFAULT_DISPLAY_BRIGHTNESS,
-                    userId);
-            final float off = brightness * contrast - 0.5f * contrast + 0.5f;
-            final float[] contrastMatrix = {
-                    contrast, 0, 0, 0,
-                    0, contrast, 0, 0,
-                    0, 0, contrast, 0,
-                    off, off, off, 1
-            };
-
-            Matrix.multiplyMM(outputMatrix, 0, colorMatrix, 0, contrastMatrix, 0);
-
-            colorMatrix = outputMatrix;
-            outputMatrix = colorMatrix;
-
-            hasColorTransform = true;
-        }
-
         final boolean daltonizerEnabled = Settings.Secure.getIntForUser(
                 cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0;
         if (daltonizerEnabled) {
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
index 77d5076..2fa23c9 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
@@ -125,8 +125,10 @@
             // Register for the boot completed broadcast, so we can send the
             // ENABLE broacasts. If we try to send them now, they time out,
             // because the system isn't ready to handle them yet.
+            IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
+            filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
             mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
-                    new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
+                    filter, null, null);
 
             // Register for configuration changes so we can update the names
             // of the widgets when the locale changes.
@@ -135,7 +137,6 @@
 
             // Register for broadcasts about package install, etc., so we can
             // update the provider list.
-            IntentFilter filter = new IntentFilter();
             filter.addAction(Intent.ACTION_PACKAGE_ADDED);
             filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
             filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 0d6f548..e2a8ca2 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -212,6 +212,7 @@
         filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         registerForAirplaneMode(filter);
+        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
         mContext.registerReceiver(mReceiver, filter);
         loadStoredNameAndAddress();
         if (isBluetoothPersistedStateOn()) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 45cdb65..0708e55 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -20,15 +20,26 @@
 import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
+import static android.net.ConnectivityManager.NetworkCallbacks;
 import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
 import static android.net.ConnectivityManager.TYPE_DUMMY;
 import static android.net.ConnectivityManager.TYPE_ETHERNET;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
+import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
+import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
+import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
+import static android.net.ConnectivityManager.TYPE_MOBILE_IMS;
+import static android.net.ConnectivityManager.TYPE_MOBILE_CBS;
+import static android.net.ConnectivityManager.TYPE_MOBILE_IA;
+import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
+import static android.net.ConnectivityManager.TYPE_NONE;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.ConnectivityManager.TYPE_WIMAX;
 import static android.net.ConnectivityManager.TYPE_PROXY;
 import static android.net.ConnectivityManager.getNetworkTypeName;
 import static android.net.ConnectivityManager.isNetworkTypeValid;
+import static android.net.ConnectivityServiceProtocol.NetworkFactoryProtocol;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
 
@@ -65,20 +76,23 @@
 import android.net.LinkProperties.CompareResult;
 import android.net.LinkQualityInfo;
 import android.net.MobileDataStateTracker;
+import android.net.Network;
+import android.net.NetworkAgent;
+import android.net.NetworkCapabilities;
 import android.net.NetworkConfig;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
 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.ProxyDataTracker;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
 import android.net.RouteInfo;
 import android.net.SamplingDataTracker;
 import android.net.Uri;
-import android.net.wifi.WifiStateTracker;
 import android.net.wimax.WimaxManagerConstants;
 import android.os.AsyncTask;
 import android.os.Binder;
@@ -118,11 +132,14 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.XmlUtils;
 import com.android.server.am.BatteryStatsService;
 import com.android.server.connectivity.DataConnectionStats;
 import com.android.server.connectivity.Nat464Xlat;
+import com.android.server.connectivity.NetworkAgentInfo;
+import com.android.server.connectivity.NetworkMonitor;
 import com.android.server.connectivity.PacManager;
 import com.android.server.connectivity.Tethering;
 import com.android.server.connectivity.Vpn;
@@ -165,6 +182,8 @@
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLSession;
 
+import static android.net.ConnectivityManager.INVALID_NET_ID;
+
 /**
  * @hide
  */
@@ -172,7 +191,7 @@
     private static final String TAG = "ConnectivityService";
 
     private static final boolean DBG = true;
-    private static final boolean VDBG = false;
+    private static final boolean VDBG = true; // STOPSHIP
 
     private static final boolean LOGD_RULES = false;
 
@@ -238,6 +257,17 @@
      */
     private NetworkStateTracker mNetTrackers[];
 
+    /**
+     * Holds references to all NetworkAgentInfos claiming to support the legacy
+     * NetworkType.  We used to have a static set of of NetworkStateTrackers
+     * for each network type.  This is the new model.
+     * Supports synchronous inspection of state.
+     * These are built out at startup such that an unsupported network
+     * doesn't get an ArrayList instance, making this a tristate:
+     * unsupported, supported but not active and active.
+     */
+    private ArrayList<NetworkAgentInfo> mNetworkAgentInfoForType[];
+
     /* Handles captive portal check on a network */
     private CaptivePortalTracker mCaptivePortalTracker;
 
@@ -299,12 +329,6 @@
     private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED = 2;
 
     /**
-     * used internally to change our network preference setting
-     * arg1 = networkType to prefer
-     */
-    private static final int EVENT_SET_NETWORK_PREFERENCE = 3;
-
-    /**
      * used internally to synchronize inet condition reports
      * arg1 = networkType
      * arg2 = condition (0 bad, 100 good)
@@ -360,7 +384,7 @@
     private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 14;
 
     /**
-     * user internally to indicate that data sampling interval is up
+     * used internally to indicate that data sampling interval is up
      */
     private static final int EVENT_SAMPLE_INTERVAL_ELAPSED = 15;
 
@@ -369,10 +393,48 @@
      */
     private static final int EVENT_PROXY_HAS_CHANGED = 16;
 
+    /**
+     * used internally when registering NetworkFactories
+     * obj = Messenger
+     */
+    private static final int EVENT_REGISTER_NETWORK_FACTORY = 17;
+
+    /**
+     * used internally when registering NetworkAgents
+     * obj = Messenger
+     */
+    private static final int EVENT_REGISTER_NETWORK_AGENT = 18;
+
+    /**
+     * used to add a network request
+     * includes a NetworkRequestInfo
+     */
+    private static final int EVENT_REGISTER_NETWORK_REQUEST = 19;
+
+    /**
+     * indicates a timeout period is over - check if we had a network yet or not
+     * and if not, call the timeout calback (but leave the request live until they
+     * cancel it.
+     * includes a NetworkRequestInfo
+     */
+    private static final int EVENT_TIMEOUT_NETWORK_REQUEST = 20;
+
+    /**
+     * used to add a network listener - no request
+     * includes a NetworkRequestInfo
+     */
+    private static final int EVENT_REGISTER_NETWORK_LISTENER = 21;
+
+    /**
+     * used to remove a network request, either a listener or a real request
+     * includes a NetworkRequest
+     */
+    private static final int EVENT_RELEASE_NETWORK_REQUEST = 22;
+
     /** Handler used for internal events. */
-    private InternalHandler mHandler;
+    final private InternalHandler mHandler;
     /** Handler used for incoming {@link NetworkStateTracker} events. */
-    private NetworkStateTrackerHandler mTrackerHandler;
+    final private NetworkStateTrackerHandler mTrackerHandler;
 
     // list of DeathRecipients used to make sure features are turned off when
     // a process dies
@@ -406,12 +468,12 @@
     private ArrayList mInetLog;
 
     // track the current default http proxy - tell the world if we get a new one (real change)
-    private ProxyProperties mDefaultProxy = null;
+    private ProxyInfo mDefaultProxy = null;
     private Object mProxyLock = new Object();
     private boolean mDefaultProxyDisabled = false;
 
     // track the global proxy.
-    private ProxyProperties mGlobalProxy = null;
+    private ProxyInfo mGlobalProxy = null;
 
     private PacManager mPacManager = null;
 
@@ -442,6 +504,10 @@
 
     TelephonyManager mTelephonyManager;
 
+    private final static int MIN_NET_ID = 10; // some reserved marks
+    private final static int MAX_NET_ID = 65535;
+    private int mNextNetId = MIN_NET_ID;
+
     public ConnectivityService(Context context, INetworkManagementService netd,
             INetworkStatsService statsService, INetworkPolicyManager policyManager) {
         // Currently, omitting a NetworkFactory will create one internally
@@ -454,6 +520,14 @@
             NetworkFactory netFactory) {
         if (DBG) log("ConnectivityService starting up");
 
+        NetworkCapabilities netCap = new NetworkCapabilities();
+        netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+        netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        mDefaultRequest = new NetworkRequest(netCap, true);
+        NetworkRequestInfo nri = new NetworkRequestInfo(null, mDefaultRequest, new Binder(),
+                NetworkRequestInfo.REQUEST);
+        mNetworkRequests.put(mDefaultRequest, nri);
+
         HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread");
         handlerThread.start();
         mHandler = new InternalHandler(handlerThread.getLooper());
@@ -505,6 +579,9 @@
         mNetTransitionWakeLockTimeout = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_networkTransitionTimeout);
 
+        mNetworkAgentInfoForType = (ArrayList<NetworkAgentInfo>[])
+                new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1];
+
         mNetTrackers = new NetworkStateTracker[
                 ConnectivityManager.MAX_NETWORK_TYPE+1];
         mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1];
@@ -559,6 +636,8 @@
                             "radio " + n.radio + " in network type " + n.type);
                     continue;
                 }
+                mNetworkAgentInfoForType[n.type] = new ArrayList<NetworkAgentInfo>();
+
                 mNetConfigs[n.type] = n;
                 mNetworksDefined++;
             } catch(Exception e) {
@@ -601,21 +680,6 @@
             }
         }
 
-        // Update mNetworkPreference according to user mannually first then overlay config.xml
-        mNetworkPreference = getPersistedNetworkPreference();
-        if (mNetworkPreference == -1) {
-            for (int n : mPriorityList) {
-                if (mNetConfigs[n].isDefault() && ConnectivityManager.isNetworkTypeValid(n)) {
-                    mNetworkPreference = n;
-                    break;
-                }
-            }
-            if (mNetworkPreference == -1) {
-                throw new IllegalStateException(
-                        "You should set at least one default Network in config.xml!");
-            }
-        }
-
         mNetRequestersPids =
                 (List<Integer> [])new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
         for (int i : mPriorityList) {
@@ -706,9 +770,19 @@
         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
     }
 
+    private synchronized int nextNetId() {
+        int netId = mNextNetId;
+        if (++mNextNetId > MAX_NET_ID) mNextNetId = MIN_NET_ID;
+        return netId;
+    }
+
     /**
      * Factory that creates {@link NetworkStateTracker} instances using given
      * {@link NetworkConfig}.
+     *
+     * TODO - this is obsolete and will be deleted.  It's replaced by the
+     * registerNetworkFactory call and protocol.
+     * @Deprecated in favor of registerNetworkFactory dynamic bindings
      */
     public interface NetworkFactory {
         public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config);
@@ -726,10 +800,6 @@
         @Override
         public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config) {
             switch (config.radio) {
-                case TYPE_WIFI:
-                    return new WifiStateTracker(targetNetworkType, config.name);
-                case TYPE_MOBILE:
-                    return new MobileDataStateTracker(targetNetworkType, config.name);
                 case TYPE_DUMMY:
                     return new DummyDataStateTracker(targetNetworkType, config.name);
                 case TYPE_BLUETOOTH:
@@ -830,41 +900,6 @@
         return wimaxStateTracker;
     }
 
-    /**
-     * Sets the preferred network.
-     * @param preference the new preference
-     */
-    public void setNetworkPreference(int preference) {
-        enforceChangePermission();
-
-        mHandler.sendMessage(
-                mHandler.obtainMessage(EVENT_SET_NETWORK_PREFERENCE, preference, 0));
-    }
-
-    public int getNetworkPreference() {
-        enforceAccessPermission();
-        int preference;
-        synchronized(this) {
-            preference = mNetworkPreference;
-        }
-        return preference;
-    }
-
-    private void handleSetNetworkPreference(int preference) {
-        if (ConnectivityManager.isNetworkTypeValid(preference) &&
-                mNetConfigs[preference] != null &&
-                mNetConfigs[preference].isDefault()) {
-            if (mNetworkPreference != preference) {
-                final ContentResolver cr = mContext.getContentResolver();
-                Settings.Global.putInt(cr, Settings.Global.NETWORK_PREFERENCE, preference);
-                synchronized(this) {
-                    mNetworkPreference = preference;
-                }
-                enforcePreference();
-            }
-        }
-    }
-
     private int getConnectivityChangeDelay() {
         final ContentResolver cr = mContext.getContentResolver();
 
@@ -876,41 +911,6 @@
                 defaultDelay);
     }
 
-    private int getPersistedNetworkPreference() {
-        final ContentResolver cr = mContext.getContentResolver();
-
-        final int networkPrefSetting = Settings.Global
-                .getInt(cr, Settings.Global.NETWORK_PREFERENCE, -1);
-
-        return networkPrefSetting;
-    }
-
-    /**
-     * Make the state of network connectivity conform to the preference settings
-     * In this method, we only tear down a non-preferred network. Establishing
-     * a connection to the preferred network is taken care of when we handle
-     * the disconnect event from the non-preferred network
-     * (see {@link #handleDisconnect(NetworkInfo)}).
-     */
-    private void enforcePreference() {
-        if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected())
-            return;
-
-        if (!mNetTrackers[mNetworkPreference].isAvailable())
-            return;
-
-        for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) {
-            if (t != mNetworkPreference && mNetTrackers[t] != null &&
-                    mNetTrackers[t].getNetworkInfo().isConnected()) {
-                if (DBG) {
-                    log("tearing down " + mNetTrackers[t].getNetworkInfo() +
-                            " in enforcePreference");
-                }
-                teardown(mNetTrackers[t]);
-            }
-        }
-    }
-
     private boolean teardown(NetworkStateTracker netTracker) {
         if (netTracker.teardown()) {
             netTracker.setTeardownRequested(true);
@@ -924,11 +924,12 @@
      * Check if UID should be blocked from using the network represented by the
      * given {@link NetworkStateTracker}.
      */
-    private boolean isNetworkBlocked(NetworkStateTracker tracker, int uid) {
-        final String iface = tracker.getLinkProperties().getInterfaceName();
-
+    private boolean isNetworkBlocked(int networkType, int uid) {
         final boolean networkCostly;
         final int uidRules;
+
+        LinkProperties lp = getLinkPropertiesForType(networkType);
+        final String iface = (lp == null ? "" : lp.getInterfaceName());
         synchronized (mRulesLock) {
             networkCostly = mMeteredIfaces.contains(iface);
             uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
@@ -945,11 +946,11 @@
     /**
      * Return a filtered {@link NetworkInfo}, potentially marked
      * {@link DetailedState#BLOCKED} based on
-     * {@link #isNetworkBlocked(NetworkStateTracker, int)}.
+     * {@link #isNetworkBlocked}.
      */
-    private NetworkInfo getFilteredNetworkInfo(NetworkStateTracker tracker, int uid) {
-        NetworkInfo info = tracker.getNetworkInfo();
-        if (isNetworkBlocked(tracker, uid)) {
+    private NetworkInfo getFilteredNetworkInfo(int networkType, int uid) {
+        NetworkInfo info = getNetworkInfoForType(networkType);
+        if (isNetworkBlocked(networkType, uid)) {
             // network is blocked; clone and override state
             info = new NetworkInfo(info);
             info.setDetailedState(DetailedState.BLOCKED, null, null);
@@ -974,6 +975,15 @@
         return getNetworkInfo(mActiveDefaultNetwork, uid);
     }
 
+    // only called when the default request is satisfied
+    private void updateActiveDefaultNetwork(NetworkAgentInfo nai) {
+        if (nai != null) {
+            mActiveDefaultNetwork = nai.networkInfo.getType();
+        } else {
+            mActiveDefaultNetwork = TYPE_NONE;
+        }
+    }
+
     /**
      * Find the first Provisioning network.
      *
@@ -1016,10 +1026,7 @@
     public NetworkInfo getActiveNetworkInfoUnfiltered() {
         enforceAccessPermission();
         if (isNetworkTypeValid(mActiveDefaultNetwork)) {
-            final NetworkStateTracker tracker = mNetTrackers[mActiveDefaultNetwork];
-            if (tracker != null) {
-                return tracker.getNetworkInfo();
-            }
+            return getNetworkInfoForType(mActiveDefaultNetwork);
         }
         return null;
     }
@@ -1040,9 +1047,8 @@
     private NetworkInfo getNetworkInfo(int networkType, int uid) {
         NetworkInfo info = null;
         if (isNetworkTypeValid(networkType)) {
-            final NetworkStateTracker tracker = mNetTrackers[networkType];
-            if (tracker != null) {
-                info = getFilteredNetworkInfo(tracker, uid);
+            if (getNetworkInfoForType(networkType) != null) {
+                info = getFilteredNetworkInfo(networkType, uid);
             }
         }
         return info;
@@ -1054,9 +1060,10 @@
         final int uid = Binder.getCallingUid();
         final ArrayList<NetworkInfo> result = Lists.newArrayList();
         synchronized (mRulesLock) {
-            for (NetworkStateTracker tracker : mNetTrackers) {
-                if (tracker != null) {
-                    result.add(getFilteredNetworkInfo(tracker, uid));
+            for (int networkType = 0; networkType <= ConnectivityManager.MAX_NETWORK_TYPE;
+                    networkType++) {
+                if (getNetworkInfoForType(networkType) != null) {
+                    result.add(getFilteredNetworkInfo(networkType, uid));
                 }
             }
         }
@@ -1066,7 +1073,7 @@
     @Override
     public boolean isNetworkSupported(int networkType) {
         enforceAccessPermission();
-        return (isNetworkTypeValid(networkType) && (mNetTrackers[networkType] != null));
+        return (isNetworkTypeValid(networkType) && (getNetworkInfoForType(networkType) != null));
     }
 
     /**
@@ -1079,32 +1086,48 @@
      */
     @Override
     public LinkProperties getActiveLinkProperties() {
-        return getLinkProperties(mActiveDefaultNetwork);
+        return getLinkPropertiesForType(mActiveDefaultNetwork);
     }
 
     @Override
-    public LinkProperties getLinkProperties(int networkType) {
+    public LinkProperties getLinkPropertiesForType(int networkType) {
         enforceAccessPermission();
         if (isNetworkTypeValid(networkType)) {
-            final NetworkStateTracker tracker = mNetTrackers[networkType];
-            if (tracker != null) {
-                return tracker.getLinkProperties();
-            }
+            return getLinkPropertiesForTypeInternal(networkType);
         }
         return null;
     }
 
+    // TODO - this should be ALL networks
+    @Override
+    public LinkProperties getLinkProperties(Network network) {
+        enforceAccessPermission();
+        NetworkAgentInfo nai = mNetworkForNetId.get(network.netId);
+        if (nai != null) return new LinkProperties(nai.linkProperties);
+        return null;
+    }
+
+    @Override
+    public NetworkCapabilities getNetworkCapabilities(Network network) {
+        enforceAccessPermission();
+        NetworkAgentInfo nai = mNetworkForNetId.get(network.netId);
+        if (nai != null) return new NetworkCapabilities(nai.networkCapabilities);
+        return null;
+    }
+
     @Override
     public NetworkState[] getAllNetworkState() {
         enforceAccessPermission();
         final int uid = Binder.getCallingUid();
         final ArrayList<NetworkState> result = Lists.newArrayList();
         synchronized (mRulesLock) {
-            for (NetworkStateTracker tracker : mNetTrackers) {
-                if (tracker != null) {
-                    final NetworkInfo info = getFilteredNetworkInfo(tracker, uid);
-                    result.add(new NetworkState(
-                            info, tracker.getLinkProperties(), tracker.getLinkCapabilities()));
+            for (int networkType = 0; networkType <= ConnectivityManager.MAX_NETWORK_TYPE;
+                    networkType++) {
+                if (getNetworkInfoForType(networkType) != null) {
+                    final NetworkInfo info = getFilteredNetworkInfo(networkType, uid);
+                    final LinkProperties lp = getLinkPropertiesForTypeInternal(networkType);
+                    final NetworkCapabilities netcap = getNetworkCapabilitiesForType(networkType);
+                    result.add(new NetworkState(info, lp, netcap));
                 }
             }
         }
@@ -1113,10 +1136,11 @@
 
     private NetworkState getNetworkStateUnchecked(int networkType) {
         if (isNetworkTypeValid(networkType)) {
-            final NetworkStateTracker tracker = mNetTrackers[networkType];
-            if (tracker != null) {
-                return new NetworkState(tracker.getNetworkInfo(), tracker.getLinkProperties(),
-                        tracker.getLinkCapabilities());
+            NetworkInfo info = getNetworkInfoForType(networkType);
+            if (info != null) {
+                return new NetworkState(info,
+                        getLinkPropertiesForTypeInternal(networkType),
+                        getNetworkCapabilitiesForType(networkType));
             }
         }
         return null;
@@ -1163,24 +1187,6 @@
         return false;
     }
 
-    public boolean setRadios(boolean turnOn) {
-        boolean result = true;
-        enforceChangePermission();
-        for (NetworkStateTracker t : mNetTrackers) {
-            if (t != null) result = t.setRadio(turnOn) && result;
-        }
-        return result;
-    }
-
-    public boolean setRadio(int netType, boolean turnOn) {
-        enforceChangePermission();
-        if (!ConnectivityManager.isNetworkTypeValid(netType)) {
-            return false;
-        }
-        NetworkStateTracker tracker = mNetTrackers[netType];
-        return tracker != null && tracker.setRadio(turnOn);
-    }
-
     private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() {
         @Override
         public void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos) {
@@ -1662,7 +1668,7 @@
         final long token = Binder.clearCallingIdentity();
         try {
             LinkProperties lp = tracker.getLinkProperties();
-            boolean ok = addRouteToAddress(lp, addr, exempt);
+            boolean ok = addRouteToAddress(lp, addr, exempt, tracker.getNetwork().netId);
             if (DBG) log("requestRouteToHostAddress ok=" + ok);
             return ok;
         } finally {
@@ -1671,24 +1677,25 @@
     }
 
     private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable,
-            boolean exempt) {
-        return modifyRoute(p, r, 0, ADD, toDefaultTable, exempt);
+            boolean exempt, int netId) {
+        return modifyRoute(p, r, 0, ADD, toDefaultTable, exempt, netId);
     }
 
-    private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
-        return modifyRoute(p, r, 0, REMOVE, toDefaultTable, UNEXEMPT);
+    private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable, int netId) {
+        return modifyRoute(p, r, 0, REMOVE, toDefaultTable, UNEXEMPT, netId);
     }
 
-    private boolean addRouteToAddress(LinkProperties lp, InetAddress addr, boolean exempt) {
-        return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE, exempt);
+    private boolean addRouteToAddress(LinkProperties lp, InetAddress addr, boolean exempt,
+                                      int netId) {
+        return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE, exempt, netId);
     }
 
-    private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr) {
-        return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE, UNEXEMPT);
+    private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr, int netId) {
+        return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE, UNEXEMPT, netId);
     }
 
     private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd,
-            boolean toDefaultTable, boolean exempt) {
+            boolean toDefaultTable, boolean exempt, int netId) {
         RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), addr);
         if (bestRoute == null) {
             bestRoute = RouteInfo.makeHostRoute(addr, lp.getInterfaceName());
@@ -1703,11 +1710,11 @@
                 bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway(), iface);
             }
         }
-        return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable, exempt);
+        return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable, exempt, netId);
     }
 
     private boolean modifyRoute(LinkProperties lp, RouteInfo r, int cycleCount, boolean doAdd,
-            boolean toDefaultTable, boolean exempt) {
+            boolean toDefaultTable, boolean exempt, int netId) {
         if ((lp == null) || (r == null)) {
             if (DBG) log("modifyRoute got unexpected null: " + lp + ", " + r);
             return false;
@@ -1736,7 +1743,7 @@
                                                         bestRoute.getGateway(),
                                                         ifaceName);
                 }
-                modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable, exempt);
+                modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable, exempt, netId);
             }
         }
         if (doAdd) {
@@ -1746,7 +1753,7 @@
                     synchronized (mRoutesLock) {
                         // only track default table - only one apps can effect
                         mAddedRoutes.add(r);
-                        mNetd.addRoute(ifaceName, r);
+                        mNetd.addRoute(netId, r);
                         if (exempt) {
                             LinkAddress dest = r.getDestination();
                             if (!mExemptAddresses.contains(dest)) {
@@ -1756,7 +1763,7 @@
                         }
                     }
                 } else {
-                    mNetd.addSecondaryRoute(ifaceName, r);
+                    mNetd.addRoute(netId, r);
                 }
             } catch (Exception e) {
                 // never crash - catch them all
@@ -1772,7 +1779,7 @@
                     if (mAddedRoutes.contains(r) == false) {
                         if (VDBG) log("Removing " + r + " for interface " + ifaceName);
                         try {
-                            mNetd.removeRoute(ifaceName, r);
+                            mNetd.removeRoute(netId, r);
                             LinkAddress dest = r.getDestination();
                             if (mExemptAddresses.contains(dest)) {
                                 mNetd.clearHostExemption(dest);
@@ -1790,7 +1797,7 @@
             } else {
                 if (VDBG) log("Removing " + r + " for interface " + ifaceName);
                 try {
-                    mNetd.removeSecondaryRoute(ifaceName, r);
+                    mNetd.removeRoute(netId, r);
                 } catch (Exception e) {
                     // never crash - catch them all
                     if (VDBG) loge("Exception trying to remove a route: " + e);
@@ -1899,18 +1906,8 @@
     }
 
     private void handleSetMobileData(boolean enabled) {
-        if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
-            if (VDBG) {
-                log(mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled);
-            }
-            mNetTrackers[ConnectivityManager.TYPE_MOBILE].setUserDataEnable(enabled);
-        }
-        if (mNetTrackers[ConnectivityManager.TYPE_WIMAX] != null) {
-            if (VDBG) {
-                log(mNetTrackers[ConnectivityManager.TYPE_WIMAX].toString() + enabled);
-            }
-            mNetTrackers[ConnectivityManager.TYPE_WIMAX].setUserDataEnable(enabled);
-        }
+    // TODO - handle this - probably generalize passing in a transport type and send to the
+    // factories?
     }
 
     @Override
@@ -1923,12 +1920,13 @@
     }
 
     private void handleSetPolicyDataEnable(int networkType, boolean enabled) {
-        if (isNetworkTypeValid(networkType)) {
-            final NetworkStateTracker tracker = mNetTrackers[networkType];
-            if (tracker != null) {
-                tracker.setPolicyDataEnable(enabled);
-            }
-        }
+   // TODO - handle this passing to factories
+//        if (isNetworkTypeValid(networkType)) {
+//            final NetworkStateTracker tracker = mNetTrackers[networkType];
+//            if (tracker != null) {
+//                tracker.setPolicyDataEnable(enabled);
+//            }
+//        }
     }
 
     private void enforceAccessPermission() {
@@ -1984,11 +1982,13 @@
         int prevNetType = info.getType();
 
         mNetTrackers[prevNetType].setTeardownRequested(false);
+        int thisNetId = mNetTrackers[prevNetType].getNetwork().netId;
 
         // Remove idletimer previously setup in {@code handleConnect}
-        if (mNetConfigs[prevNetType].isDefault()) {
-            removeDataActivityTracking(prevNetType);
-        }
+// Already in place in new function. This is dead code.
+//        if (mNetConfigs[prevNetType].isDefault()) {
+//            removeDataActivityTracking(prevNetType);
+//        }
 
         /*
          * If the disconnected network is not the active one, then don't report
@@ -2055,7 +2055,8 @@
         }
 
         // do this before we broadcast the change
-        handleConnectivityChange(prevNetType, doReset);
+// Already done in new function. This is dead code.
+//        handleConnectivityChange(prevNetType, doReset);
 
         final Intent immediateIntent = new Intent(intent);
         immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
@@ -2069,6 +2070,13 @@
             sendConnectedBroadcastDelayed(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(),
                     getConnectivityChangeDelay());
         }
+        try {
+//            mNetd.removeNetwork(thisNetId);
+        } catch (Exception e) {
+            loge("Exception removing network: " + e);
+        } finally {
+            mNetTrackers[prevNetType].setNetId(INVALID_NET_ID);
+        }
     }
 
     private void tryFailover(int prevNetType) {
@@ -2083,6 +2091,11 @@
                     log("tryFailover: set mActiveDefaultNetwork=-1, prevNetType=" + prevNetType);
                 }
                 mActiveDefaultNetwork = -1;
+                try {
+                    mNetd.clearDefaultNetId();
+                } catch (Exception e) {
+                    loge("Exception clearing default network :" + e);
+                }
             }
 
             // don't signal a reconnect for anything lower or equal priority than our
@@ -2183,67 +2196,6 @@
         }
     }
 
-    /**
-     * Called when an attempt to fail over to another network has failed.
-     * @param info the {@link NetworkInfo} for the failed network
-     */
-    private void handleConnectionFailure(NetworkInfo info) {
-        mNetTrackers[info.getType()].setTeardownRequested(false);
-
-        String reason = info.getReason();
-        String extraInfo = info.getExtraInfo();
-
-        String reasonText;
-        if (reason == null) {
-            reasonText = ".";
-        } else {
-            reasonText = " (" + reason + ").";
-        }
-        loge("Attempt to connect to " + info.getTypeName() + " failed" + reasonText);
-
-        Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
-        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info));
-        intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
-        if (getActiveNetworkInfo() == null) {
-            intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
-        }
-        if (reason != null) {
-            intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
-        }
-        if (extraInfo != null) {
-            intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
-        }
-        if (info.isFailover()) {
-            intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
-            info.setFailover(false);
-        }
-
-        if (mNetConfigs[info.getType()].isDefault()) {
-            tryFailover(info.getType());
-            if (mActiveDefaultNetwork != -1) {
-                NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
-                intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
-            } else {
-                mDefaultInetConditionPublished = 0;
-                intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
-            }
-        }
-
-        intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
-
-        final Intent immediateIntent = new Intent(intent);
-        immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
-        sendStickyBroadcast(immediateIntent);
-        sendStickyBroadcast(intent);
-        /*
-         * If the failover network is already connected, then immediately send
-         * out a followup broadcast indicating successful failover
-         */
-        if (mActiveDefaultNetwork != -1) {
-            sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo());
-        }
-    }
-
     private void sendStickyBroadcast(Intent intent) {
         synchronized(this) {
             if (!mSystemReady) {
@@ -2336,17 +2288,23 @@
         if (mNetConfigs[newNetType].isDefault()) {
             if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != newNetType) {
                 if (isNewNetTypePreferredOverCurrentNetType(newNetType)) {
-                    // tear down the other
-                    NetworkStateTracker otherNet =
-                            mNetTrackers[mActiveDefaultNetwork];
-                    if (DBG) {
-                        log("Policy requires " + otherNet.getNetworkInfo().getTypeName() +
-                            " teardown");
-                    }
-                    if (!teardown(otherNet)) {
-                        loge("Network declined teardown request");
-                        teardown(thisNet);
-                        return;
+                   String teardownPolicy = SystemProperties.get("net.teardownPolicy");
+                   if (TextUtils.equals(teardownPolicy, "keep") == false) {
+                        // tear down the other
+                        NetworkStateTracker otherNet =
+                                mNetTrackers[mActiveDefaultNetwork];
+                        if (DBG) {
+                            log("Policy requires " + otherNet.getNetworkInfo().getTypeName() +
+                                " teardown");
+                        }
+                        if (!teardown(otherNet)) {
+                            loge("Network declined teardown request");
+                            teardown(thisNet);
+                            return;
+                        }
+                    } else {
+                        //TODO - remove
+                        loge("network teardown skipped due to net.teardownPolicy setting");
                     }
                 } else {
                        // don't accept this one
@@ -2358,7 +2316,17 @@
                         return;
                 }
             }
-            setupDataActivityTracking(newNetType);
+            int thisNetId = nextNetId();
+            thisNet.setNetId(thisNetId);
+            try {
+//                mNetd.createNetwork(thisNetId, thisIface);
+            } catch (Exception e) {
+                loge("Exception creating network :" + e);
+                teardown(thisNet);
+                return;
+            }
+// Already in place in new function. This is dead code.
+//            setupDataActivityTracking(newNetType);
             synchronized (ConnectivityService.this) {
                 // have a new default network, release the transition wakelock in a second
                 // if it's held.  The second pause is to allow apps to reconnect over the
@@ -2371,6 +2339,11 @@
                 }
             }
             mActiveDefaultNetwork = newNetType;
+            try {
+                mNetd.setDefaultNetId(thisNetId);
+            } catch (Exception e) {
+                loge("Exception setting default network :" + e);
+            }
             // this will cause us to come up initially as unconnected and switching
             // to connected after our normal pause unless somebody reports us as reall
             // disconnected
@@ -2380,10 +2353,21 @@
             // Don't do this - if we never sign in stay, grey
             //reportNetworkCondition(mActiveDefaultNetwork, 100);
             updateNetworkSettings(thisNet);
+        } else {
+            int thisNetId = nextNetId();
+            thisNet.setNetId(thisNetId);
+            try {
+//                mNetd.createNetwork(thisNetId, thisIface);
+            } catch (Exception e) {
+                loge("Exception creating network :" + e);
+                teardown(thisNet);
+                return;
+            }
         }
         thisNet.setTeardownRequested(false);
-        updateMtuSizeSettings(thisNet);
-        handleConnectivityChange(newNetType, false);
+// Already in place in new function. This is dead code.
+//        updateMtuSizeSettings(thisNet);
+//        handleConnectivityChange(newNetType, false);
         sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
 
         // notify battery stats service about this network
@@ -2401,37 +2385,39 @@
     public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) {
         enforceConnectivityInternalPermission();
         if (DBG) log("captivePortalCheckCompleted: ni=" + info + " captive=" + isCaptivePortal);
-        mNetTrackers[info.getType()].captivePortalCheckCompleted(isCaptivePortal);
+//        mNetTrackers[info.getType()].captivePortalCheckCompleted(isCaptivePortal);
     }
 
     /**
-     * Setup data activity tracking for the given network interface.
+     * Setup data activity tracking for the given network.
      *
      * Every {@code setupDataActivityTracking} should be paired with a
      * {@link #removeDataActivityTracking} for cleanup.
      */
-    private void setupDataActivityTracking(int type) {
-        final NetworkStateTracker thisNet = mNetTrackers[type];
-        final String iface = thisNet.getLinkProperties().getInterfaceName();
+    private void setupDataActivityTracking(NetworkAgentInfo networkAgent) {
+        final String iface = networkAgent.linkProperties.getInterfaceName();
 
         final int timeout;
+        int type = ConnectivityManager.TYPE_NONE;
 
-        if (ConnectivityManager.isNetworkTypeMobile(type)) {
+        if (networkAgent.networkCapabilities.hasTransport(
+                NetworkCapabilities.TRANSPORT_CELLULAR)) {
             timeout = Settings.Global.getInt(mContext.getContentResolver(),
                                              Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
                                              5);
-            // Canonicalize mobile network type
             type = ConnectivityManager.TYPE_MOBILE;
-        } else if (ConnectivityManager.TYPE_WIFI == type) {
+        } else if (networkAgent.networkCapabilities.hasTransport(
+                NetworkCapabilities.TRANSPORT_WIFI)) {
             timeout = Settings.Global.getInt(mContext.getContentResolver(),
                                              Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI,
                                              0);
+            type = ConnectivityManager.TYPE_WIFI;
         } else {
             // do not track any other networks
             timeout = 0;
         }
 
-        if (timeout > 0 && iface != null) {
+        if (timeout > 0 && iface != null && type != ConnectivityManager.TYPE_NONE) {
             try {
                 mNetd.addIdleTimer(iface, timeout, type);
             } catch (Exception e) {
@@ -2444,12 +2430,12 @@
     /**
      * Remove data activity tracking when network disconnects.
      */
-    private void removeDataActivityTracking(int type) {
-        final NetworkStateTracker net = mNetTrackers[type];
-        final String iface = net.getLinkProperties().getInterfaceName();
+    private void removeDataActivityTracking(NetworkAgentInfo networkAgent) {
+        final String iface = networkAgent.linkProperties.getInterfaceName();
+        final NetworkCapabilities caps = networkAgent.networkCapabilities;
 
-        if (iface != null && (ConnectivityManager.isNetworkTypeMobile(type) ||
-                              ConnectivityManager.TYPE_WIFI == type)) {
+        if (iface != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
+                              caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))) {
             try {
                 // the call fails silently if no idletimer setup for this interface
                 mNetd.removeIdleTimer(iface);
@@ -2464,8 +2450,10 @@
      * concerned with making sure that the list of DNS servers is set up
      * according to which networks are connected, and ensuring that the
      * right routing table entries exist.
+     *
+     * TODO - delete when we're sure all this functionallity is captured.
      */
-    private void handleConnectivityChange(int netType, boolean doReset) {
+    private void handleConnectivityChange(int netType, LinkProperties curLp, boolean doReset) {
         int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
         boolean exempt = ConnectivityManager.isNetworkTypeExempt(netType);
         if (VDBG) {
@@ -2479,7 +2467,6 @@
          */
         handleDnsConfigurationChange(netType);
 
-        LinkProperties curLp = mCurrentLinkProperties[netType];
         LinkProperties newLp = null;
 
         if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
@@ -2536,7 +2523,8 @@
             }
         }
         mCurrentLinkProperties[netType] = newLp;
-        boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault(), exempt);
+        boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault(), exempt,
+                                        mNetTrackers[netType].getNetwork().netId);
 
         if (resetMask != 0 || resetDns) {
             if (VDBG) log("handleConnectivityChange: resetting");
@@ -2558,40 +2546,20 @@
                                 }
                             }
                         }
-                        if (resetDns) {
-                            flushVmDnsCache();
-                            if (VDBG) log("resetting DNS cache for " + iface);
-                            try {
-                                mNetd.flushInterfaceDnsCache(iface);
-                            } catch (Exception e) {
-                                // never crash - catch them all
-                                if (DBG) loge("Exception resetting dns cache: " + e);
-                            }
-                        }
                     } else {
                         loge("Can't reset connection for type "+netType);
                     }
                 }
-            }
-        }
-
-        // Update 464xlat state.
-        NetworkStateTracker tracker = mNetTrackers[netType];
-        if (mClat.requiresClat(netType, tracker)) {
-
-            // If the connection was previously using clat, but is not using it now, stop the clat
-            // daemon. Normally, this happens automatically when the connection disconnects, but if
-            // the disconnect is not reported, or if the connection's LinkProperties changed for
-            // some other reason (e.g., handoff changes the IP addresses on the link), it would
-            // still be running. If it's not running, then stopping it is a no-op.
-            if (Nat464Xlat.isRunningClat(curLp) && !Nat464Xlat.isRunningClat(newLp)) {
-                mClat.stopClat();
-            }
-            // If the link requires clat to be running, then start the daemon now.
-            if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
-                mClat.startClat(tracker);
-            } else {
-                mClat.stopClat();
+                if (resetDns) {
+                    flushVmDnsCache();
+                    if (VDBG) log("resetting DNS cache for type " + netType);
+                    try {
+                        mNetd.flushNetworkDnsCache(mNetTrackers[netType].getNetwork().netId);
+                    } catch (Exception e) {
+                        // never crash - catch them all
+                        if (DBG) loge("Exception resetting dns cache: " + e);
+                    }
+                }
             }
         }
 
@@ -2615,7 +2583,7 @@
      * returns a boolean indicating the routes changed
      */
     private boolean updateRoutes(LinkProperties newLp, LinkProperties curLp,
-            boolean isLinkDefault, boolean exempt) {
+            boolean isLinkDefault, boolean exempt, int netId) {
         Collection<RouteInfo> routesToAdd = null;
         CompareResult<InetAddress> dnsDiff = new CompareResult<InetAddress>();
         CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();
@@ -2633,45 +2601,20 @@
         for (RouteInfo r : routeDiff.removed) {
             if (isLinkDefault || ! r.isDefaultRoute()) {
                 if (VDBG) log("updateRoutes: default remove route r=" + r);
-                removeRoute(curLp, r, TO_DEFAULT_TABLE);
+                removeRoute(curLp, r, TO_DEFAULT_TABLE, netId);
             }
             if (isLinkDefault == false) {
                 // remove from a secondary route table
-                removeRoute(curLp, r, TO_SECONDARY_TABLE);
-            }
-        }
-
-        if (!isLinkDefault) {
-            // handle DNS routes
-            if (routesChanged) {
-                // routes changed - remove all old dns entries and add new
-                if (curLp != null) {
-                    for (InetAddress oldDns : curLp.getDnses()) {
-                        removeRouteToAddress(curLp, oldDns);
-                    }
-                }
-                if (newLp != null) {
-                    for (InetAddress newDns : newLp.getDnses()) {
-                        addRouteToAddress(newLp, newDns, exempt);
-                    }
-                }
-            } else {
-                // no change in routes, check for change in dns themselves
-                for (InetAddress oldDns : dnsDiff.removed) {
-                    removeRouteToAddress(curLp, oldDns);
-                }
-                for (InetAddress newDns : dnsDiff.added) {
-                    addRouteToAddress(newLp, newDns, exempt);
-                }
+                removeRoute(curLp, r, TO_SECONDARY_TABLE, netId);
             }
         }
 
         for (RouteInfo r :  routeDiff.added) {
             if (isLinkDefault || ! r.isDefaultRoute()) {
-                addRoute(newLp, r, TO_DEFAULT_TABLE, exempt);
+                addRoute(newLp, r, TO_DEFAULT_TABLE, exempt, netId);
             } else {
                 // add to a secondary route table
-                addRoute(newLp, r, TO_SECONDARY_TABLE, UNEXEMPT);
+                addRoute(newLp, r, TO_SECONDARY_TABLE, UNEXEMPT, netId);
 
                 // many radios add a default route even when we don't want one.
                 // remove the default route unless somebody else has asked for it
@@ -2680,7 +2623,7 @@
                     if (!TextUtils.isEmpty(ifaceName) && !mAddedRoutes.contains(r)) {
                         if (VDBG) log("Removing " + r + " for interface " + ifaceName);
                         try {
-                            mNetd.removeRoute(ifaceName, r);
+                            mNetd.removeRoute(netId, r);
                         } catch (Exception e) {
                             // never crash - catch them all
                             if (DBG) loge("Exception trying to remove a route: " + e);
@@ -2693,26 +2636,30 @@
         return routesChanged;
     }
 
-   /**
+    /**
      * Reads the network specific MTU size from reources.
      * and set it on it's iface.
      */
-   private void updateMtuSizeSettings(NetworkStateTracker nt) {
-       final String iface = nt.getLinkProperties().getInterfaceName();
-       final int mtu = nt.getLinkProperties().getMtu();
+    private void updateMtu(LinkProperties newLp, LinkProperties oldLp) {
+        final String iface = newLp.getInterfaceName();
+        final int mtu = newLp.getMtu();
+        if (oldLp != null && newLp.isIdenticalMtu(oldLp)) {
+            if (VDBG) log("identical MTU - not setting");
+            return;
+        }
 
-       if (mtu < 68 || mtu > 10000) {
-           loge("Unexpected mtu value: " + mtu + ", " + nt);
-           return;
-       }
+        if (mtu < 68 || mtu > 10000) {
+            loge("Unexpected mtu value: " + mtu + ", " + iface);
+            return;
+        }
 
-       try {
-           if (VDBG) log("Setting MTU size: " + iface + ", " + mtu);
-           mNetd.setMtu(iface, mtu);
-       } catch (Exception e) {
-           Slog.e(TAG, "exception in setMtu()" + e);
-       }
-   }
+        try {
+            if (VDBG) log("Setting MTU size: " + iface + ", " + mtu);
+            mNetd.setMtu(iface, mtu);
+        } catch (Exception e) {
+            Slog.e(TAG, "exception in setMtu()" + e);
+        }
+    }
 
     /**
      * Reads the network specific TCP buffer sizes from SystemProperties
@@ -2797,7 +2744,8 @@
                 if (p == null) continue;
                 if (mNetRequestersPids[i].contains(myPid)) {
                     try {
-                        mNetd.setDnsInterfaceForPid(p.getInterfaceName(), pid);
+                        // TODO: Reimplement this via local variable in bionic.
+                        // mNetd.setDnsNetworkForPid(nt.getNetwork().netId, pid);
                     } catch (Exception e) {
                         Slog.e(TAG, "exception reasseses pid dns: " + e);
                     }
@@ -2807,7 +2755,8 @@
         }
         // nothing found - delete
         try {
-            mNetd.clearDnsInterfaceForPid(pid);
+            // TODO: Reimplement this via local variable in bionic.
+            // mNetd.clearDnsNetworkForPid(pid);
         } catch (Exception e) {
             Slog.e(TAG, "exception clear interface from pid: " + e);
         }
@@ -2832,8 +2781,8 @@
     }
 
     // Caller must grab mDnsLock.
-    private void updateDnsLocked(String network, String iface,
-            Collection<InetAddress> dnses, String domains, boolean defaultDns) {
+    private void updateDnsLocked(String network, int netId,
+            Collection<InetAddress> dnses, String domains) {
         int last = 0;
         if (dnses.size() == 0 && mDefaultDns != null) {
             dnses = new ArrayList();
@@ -2844,10 +2793,7 @@
         }
 
         try {
-            mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains);
-            if (defaultDns) {
-                mNetd.setDefaultInterfaceForDns(iface);
-            }
+            mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses), domains);
 
             for (InetAddress dns : dnses) {
                 ++last;
@@ -2872,14 +2818,15 @@
             LinkProperties p = nt.getLinkProperties();
             if (p == null) return;
             Collection<InetAddress> dnses = p.getDnses();
+            int netId = nt.getNetwork().netId;
             if (mNetConfigs[netType].isDefault()) {
                 String network = nt.getNetworkInfo().getTypeName();
                 synchronized (mDnsLock) {
-                    updateDnsLocked(network, p.getInterfaceName(), dnses, p.getDomains(), true);
+                    updateDnsLocked(network, netId, dnses, p.getDomains());
                 }
             } else {
                 try {
-                    mNetd.setDnsServersForInterface(p.getInterfaceName(),
+                    mNetd.setDnsServersForNetwork(netId,
                             NetworkUtils.makeStrings(dnses), p.getDomains());
                 } catch (Exception e) {
                     if (DBG) loge("exception setting dns servers: " + e);
@@ -2888,7 +2835,8 @@
                 List<Integer> pids = mNetRequestersPids[netType];
                 for (Integer pid : pids) {
                     try {
-                        mNetd.setDnsInterfaceForPid(p.getInterfaceName(), pid);
+                        // TODO: Reimplement this via local variable in bionic.
+                        // mNetd.setDnsNetworkForPid(netId, pid);
                     } catch (Exception e) {
                         Slog.e(TAG, "exception setting interface for pid: " + e);
                     }
@@ -2930,44 +2878,39 @@
             return;
         }
 
-        // TODO: add locking to get atomic snapshot
-        pw.println();
-        for (int i = 0; i < mNetTrackers.length; i++) {
-            final NetworkStateTracker nst = mNetTrackers[i];
-            if (nst != null) {
-                pw.println("NetworkStateTracker for " + getNetworkTypeName(i) + ":");
-                pw.increaseIndent();
-                if (nst.getNetworkInfo().isConnected()) {
-                    pw.println("Active network: " + nst.getNetworkInfo().
-                            getTypeName());
-                }
-                pw.println(nst.getNetworkInfo());
-                pw.println(nst.getLinkProperties());
-                pw.println(nst);
-                pw.println();
-                pw.decreaseIndent();
-            }
+        NetworkAgentInfo defaultNai = mNetworkForRequestId.get(mDefaultRequest.requestId);
+        pw.print("Active default network: ");
+        if (defaultNai == null) {
+            pw.println("none");
+        } else {
+            pw.println(defaultNai.network.netId);
         }
-
-        pw.print("Active default network: "); pw.println(getNetworkTypeName(mActiveDefaultNetwork));
         pw.println();
 
-        pw.println("Network Requester Pids:");
+        pw.println("Current Networks:");
         pw.increaseIndent();
-        for (int net : mPriorityList) {
-            String pidString = net + ": ";
-            for (Integer pid : mNetRequestersPids[net]) {
-                pidString = pidString + pid.toString() + ", ";
+        for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+            pw.println(nai.toString());
+            pw.increaseIndent();
+            pw.println("Requests:");
+            pw.increaseIndent();
+            for (int i = 0; i < nai.networkRequests.size(); i++) {
+                pw.println(nai.networkRequests.valueAt(i).toString());
             }
-            pw.println(pidString);
+            pw.decreaseIndent();
+            pw.println("Lingered:");
+            pw.increaseIndent();
+            for (NetworkRequest nr : nai.networkLingered) pw.println(nr.toString());
+            pw.decreaseIndent();
+            pw.decreaseIndent();
         }
-        pw.println();
         pw.decreaseIndent();
+        pw.println();
 
-        pw.println("FeatureUsers:");
+        pw.println("Network Requests:");
         pw.increaseIndent();
-        for (Object requester : mFeatureUsers) {
-            pw.println(requester.toString());
+        for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+            pw.println(nri.toString());
         }
         pw.println();
         pw.decreaseIndent();
@@ -3002,6 +2945,59 @@
         public void handleMessage(Message msg) {
             NetworkInfo info;
             switch (msg.what) {
+                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
+                    handleAsyncChannelHalfConnect(msg);
+                    break;
+                }
+                case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
+                    NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
+                    if (nai != null) nai.asyncChannel.disconnect();
+                    break;
+                }
+                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
+                    handleAsyncChannelDisconnected(msg);
+                    break;
+                }
+                case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
+                    NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
+                    if (nai == null) {
+                        loge("EVENT_NETWORK_CAPABILITIES_CHANGED from unknown NetworkAgent");
+                    } else {
+                        updateCapabilities(nai, (NetworkCapabilities)msg.obj);
+                    }
+                    break;
+                }
+                case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED: {
+                    NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
+                    if (nai == null) {
+                        loge("NetworkAgent not found for EVENT_NETWORK_PROPERTIES_CHANGED");
+                    } else {
+                        LinkProperties oldLp = nai.linkProperties;
+                        nai.linkProperties = (LinkProperties)msg.obj;
+                        updateLinkProperties(nai, oldLp);
+                    }
+                    break;
+                }
+                case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: {
+                    NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
+                    if (nai == null) {
+                        loge("EVENT_NETWORK_INFO_CHANGED from unknown NetworkAgent");
+                        break;
+                    }
+                    info = (NetworkInfo) msg.obj;
+                    updateNetworkInfo(nai, info);
+                    break;
+                }
+                case NetworkMonitor.EVENT_NETWORK_VALIDATED: {
+                    NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj;
+                    handleConnectionValidated(nai);
+                    break;
+                }
+                case NetworkMonitor.EVENT_NETWORK_LINGER_COMPLETE: {
+                    NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj;
+                    handleLingerComplete(nai);
+                    break;
+                }
                 case NetworkStateTracker.EVENT_STATE_CHANGED: {
                     info = (NetworkInfo) msg.obj;
                     NetworkInfo.State state = info.getState();
@@ -3034,10 +3030,7 @@
                     EventLogTags.writeConnectivityStateChanged(
                             info.getType(), info.getSubtype(), info.getDetailedState().ordinal());
 
-                    if (info.getDetailedState() ==
-                            NetworkInfo.DetailedState.FAILED) {
-                        handleConnectionFailure(info);
-                    } else if (info.isConnectedToProvisioningNetwork()) {
+                    if (info.isConnectedToProvisioningNetwork()) {
                         /**
                          * TODO: Create ConnectivityManager.TYPE_MOBILE_PROVISIONING
                          * for now its an in between network, its a network that
@@ -3048,7 +3041,7 @@
                          * to the link that may have incorrectly setup by the lower
                          * levels.
                          */
-                        LinkProperties lp = getLinkProperties(info.getType());
+                        LinkProperties lp = getLinkPropertiesForTypeInternal(info.getType());
                         if (DBG) {
                             log("EVENT_STATE_CHANGED: connected to provisioning network, lp=" + lp);
                         }
@@ -3058,21 +3051,13 @@
                         // connection will fail until the provisioning network
                         // is enabled.
                         for (RouteInfo r : lp.getRoutes()) {
-                            removeRoute(lp, r, TO_DEFAULT_TABLE);
+                            removeRoute(lp, r, TO_DEFAULT_TABLE,
+                                        mNetTrackers[info.getType()].getNetwork().netId);
                         }
                     } else if (state == NetworkInfo.State.DISCONNECTED) {
-                        handleDisconnect(info);
                     } else if (state == NetworkInfo.State.SUSPENDED) {
-                        // TODO: need to think this over.
-                        // the logic here is, handle SUSPENDED the same as
-                        // DISCONNECTED. The only difference being we are
-                        // broadcasting an intent with NetworkInfo that's
-                        // suspended. This allows the applications an
-                        // opportunity to handle DISCONNECTED and SUSPENDED
-                        // differently, or not.
-                        handleDisconnect(info);
                     } else if (state == NetworkInfo.State.CONNECTED) {
-                        handleConnect(info);
+                    //    handleConnect(info);
                     }
                     if (mLockdownTracker != null) {
                         mLockdownTracker.onNetworkInfoChanged(info);
@@ -3084,7 +3069,8 @@
                     // TODO: Temporary allowing network configuration
                     //       change not resetting sockets.
                     //       @see bug/4455071
-                    handleConnectivityChange(info.getType(), false);
+                    handleConnectivityChange(info.getType(), mCurrentLinkProperties[info.getType()],
+                            false);
                     break;
                 }
                 case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: {
@@ -3097,6 +3083,173 @@
         }
     }
 
+    private void handleAsyncChannelHalfConnect(Message msg) {
+        AsyncChannel ac = (AsyncChannel) msg.obj;
+        if (mNetworkFactories.contains(ac)) {
+            if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
+                if (VDBG) log("NetworkFactory connected");
+                // A network factory has connected.  Send it all current NetworkRequests.
+                for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+                    NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
+                    ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK,
+                            (nai != null ? nai.currentScore : 0), 0, nri.request);
+                }
+            } else {
+                loge("Error connecting NetworkFactory");
+                mNetworkFactories.remove(ac);
+            }
+        } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) {
+            if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
+                if (VDBG) log("NetworkAgent connected");
+                // A network agent has requested a connection.  Establish the connection.
+                mNetworkAgentInfos.get(msg.replyTo).asyncChannel.
+                        sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+            } else {
+                loge("Error connecting NetworkAgent");
+                NetworkAgentInfo nai = mNetworkAgentInfos.remove(msg.replyTo);
+                try {
+                    mNetworkAgentInfoForType[nai.networkInfo.getType()].remove(nai);
+                } catch (NullPointerException e) {}
+                if (nai != null) {
+                    mNetworkForNetId.remove(nai.network.netId);
+                }
+            }
+        }
+    }
+    private void handleAsyncChannelDisconnected(Message msg) {
+        NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
+        if (nai != null) {
+            if (DBG) {
+                log(nai.name() + " got DISCONNECTED, was satisfying " + nai.networkRequests.size());
+            }
+            // A network agent has disconnected.
+            // Tell netd to clean up the configuration for this network
+            // (routing rules, DNS, etc).
+            try {
+                mNetd.removeNetwork(nai.network.netId);
+            } catch (Exception e) {
+                loge("Exception removing network: " + e);
+            }
+            notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
+            nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
+            mNetworkAgentInfos.remove(msg.replyTo);
+            updateClat(null, nai.linkProperties, nai);
+            try {
+                mNetworkAgentInfoForType[nai.networkInfo.getType()].remove(nai);
+            } catch (NullPointerException e) {}
+
+            mNetworkForNetId.remove(nai.network.netId);
+            // Since we've lost the network, go through all the requests that
+            // it was satisfying and see if any other factory can satisfy them.
+            final ArrayList<NetworkAgentInfo> toActivate = new ArrayList<NetworkAgentInfo>();
+            for (int i = 0; i < nai.networkRequests.size(); i++) {
+                NetworkRequest request = nai.networkRequests.valueAt(i);
+                NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId);
+                if (VDBG) {
+                    log(" checking request " + request + ", currentNetwork = " +
+                            currentNetwork != null ? currentNetwork.name() : "null");
+                }
+                if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
+                    mNetworkForRequestId.remove(request.requestId);
+                    sendUpdatedScoreToFactories(request, 0);
+                    NetworkAgentInfo alternative = null;
+                    for (Map.Entry entry : mNetworkAgentInfos.entrySet()) {
+                        NetworkAgentInfo existing = (NetworkAgentInfo)entry.getValue();
+                        if (existing.networkInfo.isConnected() &&
+                                request.networkCapabilities.satisfiedByNetworkCapabilities(
+                                existing.networkCapabilities) &&
+                                (alternative == null ||
+                                 alternative.currentScore < existing.currentScore)) {
+                            alternative = existing;
+                        }
+                    }
+                    if (alternative != null && !toActivate.contains(alternative)) {
+                        toActivate.add(alternative);
+                    }
+                }
+            }
+            if (nai.networkRequests.get(mDefaultRequest.requestId) != null) {
+                removeDataActivityTracking(nai);
+                mActiveDefaultNetwork = ConnectivityManager.TYPE_NONE;
+            }
+            for (NetworkAgentInfo networkToActivate : toActivate) {
+                networkToActivate.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
+            }
+        }
+    }
+
+    private void handleRegisterNetworkRequest(Message msg) {
+        final NetworkRequestInfo nri = (NetworkRequestInfo) (msg.obj);
+        final NetworkCapabilities newCap = nri.request.networkCapabilities;
+        int score = 0;
+
+        // Check for the best currently alive network that satisfies this request
+        NetworkAgentInfo bestNetwork = null;
+        for (NetworkAgentInfo network : mNetworkAgentInfos.values()) {
+            if (VDBG) log("handleRegisterNetworkRequest checking " + network.name());
+            if (newCap.satisfiedByNetworkCapabilities(network.networkCapabilities)) {
+                if (VDBG) log("apparently satisfied.  currentScore=" + network.currentScore);
+                if ((bestNetwork == null) || bestNetwork.currentScore < network.currentScore) {
+                    bestNetwork = network;
+                }
+            }
+        }
+        if (bestNetwork != null) {
+            if (VDBG) log("using " + bestNetwork.name());
+            bestNetwork.networkRequests.put(nri.request.requestId, nri.request);
+            notifyNetworkCallback(bestNetwork, nri);
+            score = bestNetwork.currentScore;
+        }
+        mNetworkRequests.put(nri.request, nri);
+        if (msg.what == EVENT_REGISTER_NETWORK_REQUEST) {
+            if (DBG) log("sending new NetworkRequest to factories");
+            for (AsyncChannel ac : mNetworkFactories) {
+                ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request);
+            }
+        }
+    }
+
+    private void handleReleaseNetworkRequest(NetworkRequest request) {
+        if (DBG) log("releasing NetworkRequest " + request);
+        NetworkRequestInfo nri = mNetworkRequests.remove(request);
+        if (nri != null) {
+            // tell the network currently servicing this that it's no longer interested
+            NetworkAgentInfo affectedNetwork = mNetworkForRequestId.get(nri.request.requestId);
+            if (affectedNetwork != null) {
+                affectedNetwork.networkRequests.remove(nri.request.requestId);
+                if (VDBG) {
+                    log(" Removing from current network " + affectedNetwork.name() + ", leaving " +
+                            affectedNetwork.networkRequests.size() + " requests.");
+                }
+            }
+
+            if (nri.isRequest) {
+                for (AsyncChannel factory : mNetworkFactories) {
+                    factory.sendMessage(NetworkFactoryProtocol.CMD_CANCEL_REQUEST, nri.request);
+                }
+
+                if (affectedNetwork != null) {
+                    // check if this network still has live requests - otherwise, tear down
+                    // TODO - probably push this to the NF/NA
+                    boolean keep = false;
+                    for (int i = 0; i < affectedNetwork.networkRequests.size(); i++) {
+                        NetworkRequest r = affectedNetwork.networkRequests.valueAt(i);
+                        if (mNetworkRequests.get(r).isRequest) {
+                            keep = true;
+                            break;
+                        }
+                    }
+                    if (keep == false) {
+                        if (DBG) log("no live requests for " + affectedNetwork.name() +
+                                "; disconnecting");
+                        affectedNetwork.asyncChannel.disconnect();
+                    }
+                }
+            }
+            callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED);
+        }
+    }
+
     private class InternalHandler extends Handler {
         public InternalHandler(Looper looper) {
             super(looper);
@@ -3137,11 +3290,6 @@
                     handleInetConditionHoldEnd(netType, sequence);
                     break;
                 }
-                case EVENT_SET_NETWORK_PREFERENCE: {
-                    int preference = msg.arg1;
-                    handleSetNetworkPreference(preference);
-                    break;
-                }
                 case EVENT_SET_MOBILE_DATA: {
                     boolean enabled = (msg.arg1 == ENABLED);
                     handleSetMobileData(enabled);
@@ -3192,7 +3340,24 @@
                     break;
                 }
                 case EVENT_PROXY_HAS_CHANGED: {
-                    handleApplyDefaultProxy((ProxyProperties)msg.obj);
+                    handleApplyDefaultProxy((ProxyInfo)msg.obj);
+                    break;
+                }
+                case EVENT_REGISTER_NETWORK_FACTORY: {
+                    handleRegisterNetworkFactory((Messenger)msg.obj);
+                    break;
+                }
+                case EVENT_REGISTER_NETWORK_AGENT: {
+                    handleRegisterNetworkAgent((NetworkAgentInfo)msg.obj);
+                    break;
+                }
+                case EVENT_REGISTER_NETWORK_REQUEST:
+                case EVENT_REGISTER_NETWORK_LISTENER: {
+                    handleRegisterNetworkRequest(msg);
+                    break;
+                }
+                case EVENT_RELEASE_NETWORK_REQUEST: {
+                    handleReleaseNetworkRequest((NetworkRequest) msg.obj);
                     break;
                 }
             }
@@ -3341,6 +3506,10 @@
             EVENT_INET_CONDITION_CHANGE, networkType, percentage));
     }
 
+    public void reportBadNetwork(Network network) {
+        //TODO
+    }
+
     private void handleInetConditionChange(int netType, int condition) {
         if (mActiveDefaultNetwork == -1) {
             if (DBG) log("handleInetConditionChange: no active default network - ignore");
@@ -3400,7 +3569,7 @@
         //    if (DBG) log("no change in condition - aborting");
         //    return;
         //}
-        NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
+        NetworkInfo networkInfo = getNetworkInfoForType(mActiveDefaultNetwork);
         if (networkInfo.isConnected() == false) {
             if (DBG) log("handleInetConditionHoldEnd: default network not connected - ignoring");
             return;
@@ -3410,19 +3579,19 @@
         return;
     }
 
-    public ProxyProperties getProxy() {
+    public ProxyInfo getProxy() {
         // this information is already available as a world read/writable jvm property
         // so this API change wouldn't have a benifit.  It also breaks the passing
         // of proxy info to all the JVMs.
         // enforceAccessPermission();
         synchronized (mProxyLock) {
-            ProxyProperties ret = mGlobalProxy;
+            ProxyInfo ret = mGlobalProxy;
             if ((ret == null) && !mDefaultProxyDisabled) ret = mDefaultProxy;
             return ret;
         }
     }
 
-    public void setGlobalProxy(ProxyProperties proxyProperties) {
+    public void setGlobalProxy(ProxyInfo proxyProperties) {
         enforceConnectivityInternalPermission();
 
         synchronized (mProxyLock) {
@@ -3435,18 +3604,18 @@
             String exclList = "";
             String pacFileUrl = "";
             if (proxyProperties != null && (!TextUtils.isEmpty(proxyProperties.getHost()) ||
-                    !TextUtils.isEmpty(proxyProperties.getPacFileUrl()))) {
+                    (proxyProperties.getPacFileUrl() != null))) {
                 if (!proxyProperties.isValid()) {
                     if (DBG)
                         log("Invalid proxy properties, ignoring: " + proxyProperties.toString());
                     return;
                 }
-                mGlobalProxy = new ProxyProperties(proxyProperties);
+                mGlobalProxy = new ProxyInfo(proxyProperties);
                 host = mGlobalProxy.getHost();
                 port = mGlobalProxy.getPort();
-                exclList = mGlobalProxy.getExclusionList();
+                exclList = mGlobalProxy.getExclusionListAsString();
                 if (proxyProperties.getPacFileUrl() != null) {
-                    pacFileUrl = proxyProperties.getPacFileUrl();
+                    pacFileUrl = proxyProperties.getPacFileUrl().toString();
                 }
             } else {
                 mGlobalProxy = null;
@@ -3478,11 +3647,11 @@
                 Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
         String pacFileUrl = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC);
         if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) {
-            ProxyProperties proxyProperties;
+            ProxyInfo proxyProperties;
             if (!TextUtils.isEmpty(pacFileUrl)) {
-                proxyProperties = new ProxyProperties(pacFileUrl);
+                proxyProperties = new ProxyInfo(pacFileUrl);
             } else {
-                proxyProperties = new ProxyProperties(host, port, exclList);
+                proxyProperties = new ProxyInfo(host, port, exclList);
             }
             if (!proxyProperties.isValid()) {
                 if (DBG) log("Invalid proxy properties, ignoring: " + proxyProperties.toString());
@@ -3495,7 +3664,7 @@
         }
     }
 
-    public ProxyProperties getGlobalProxy() {
+    public ProxyInfo getGlobalProxy() {
         // this information is already available as a world read/writable jvm property
         // so this API change wouldn't have a benifit.  It also breaks the passing
         // of proxy info to all the JVMs.
@@ -3505,9 +3674,9 @@
         }
     }
 
-    private void handleApplyDefaultProxy(ProxyProperties proxy) {
+    private void handleApplyDefaultProxy(ProxyInfo proxy) {
         if (proxy != null && TextUtils.isEmpty(proxy.getHost())
-                && TextUtils.isEmpty(proxy.getPacFileUrl())) {
+                && (proxy.getPacFileUrl() == null)) {
             proxy = null;
         }
         synchronized (mProxyLock) {
@@ -3517,6 +3686,18 @@
                 if (DBG) log("Invalid proxy properties, ignoring: " + proxy.toString());
                 return;
             }
+
+            // This call could be coming from the PacManager, containing the port of the local
+            // proxy.  If this new proxy matches the global proxy then copy this proxy to the
+            // global (to get the correct local port), and send a broadcast.
+            // TODO: Switch PacManager to have its own message to send back rather than
+            // reusing EVENT_HAS_CHANGED_PROXY and this call to handleApplyDefaultProxy.
+            if ((mGlobalProxy != null) && (proxy != null) && (proxy.getPacFileUrl() != null)
+                    && proxy.getPacFileUrl().equals(mGlobalProxy.getPacFileUrl())) {
+                mGlobalProxy = proxy;
+                sendProxyBroadcast(mGlobalProxy);
+                return;
+            }
             mDefaultProxy = proxy;
 
             if (mGlobalProxy != null) return;
@@ -3544,13 +3725,13 @@
                     return;
                 }
             }
-            ProxyProperties p = new ProxyProperties(data[0], proxyPort, "");
+            ProxyInfo p = new ProxyInfo(data[0], proxyPort, "");
             setGlobalProxy(p);
         }
     }
 
-    private void sendProxyBroadcast(ProxyProperties proxy) {
-        if (proxy == null) proxy = new ProxyProperties("", 0, "");
+    private void sendProxyBroadcast(ProxyInfo proxy) {
+        if (proxy == null) proxy = new ProxyInfo("", 0, "");
         if (mPacManager.setCurrentProxyScriptUrl(proxy)) return;
         if (DBG) log("sending Proxy Broadcast for " + proxy);
         Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
@@ -3809,7 +3990,8 @@
 
             // Apply DNS changes.
             synchronized (mDnsLock) {
-                updateDnsLocked("VPN", iface, addresses, domains, false);
+                // TODO: Re-enable this when the netId of the VPN is known.
+                // updateDnsLocked("VPN", netId, addresses, domains);
             }
 
             // Temporarily disable the default proxy (not global).
@@ -3877,21 +4059,21 @@
 
         public void addUidForwarding(String interfaze, int uidStart, int uidEnd,
                 boolean forwardDns) {
-            try {
-                mNetd.setUidRangeRoute(interfaze,uidStart, uidEnd);
-                if (forwardDns) mNetd.setDnsInterfaceForUidRange(interfaze, uidStart, uidEnd);
-            } catch (RemoteException e) {
-            }
+            // TODO: Re-enable this when the netId of the VPN is known.
+            // try {
+            //     mNetd.setUidRangeRoute(netId, uidStart, uidEnd, forwardDns);
+            // } catch (RemoteException e) {
+            // }
 
         }
 
         public void clearUidForwarding(String interfaze, int uidStart, int uidEnd,
                 boolean forwardDns) {
-            try {
-                mNetd.clearUidRangeRoute(interfaze, uidStart, uidEnd);
-                if (forwardDns) mNetd.clearDnsInterfaceForUidRange(interfaze, uidStart, uidEnd);
-            } catch (RemoteException e) {
-            }
+            // TODO: Re-enable this when the netId of the VPN is known.
+            // try {
+            //     mNetd.clearUidRangeRoute(interfaze, uidStart, uidEnd);
+            // } catch (RemoteException e) {
+            // }
 
         }
     }
@@ -4152,7 +4334,10 @@
             CheckMp.Params params =
                     new CheckMp.Params(checkMp.getDefaultUrl(), timeOutMs, cb);
             if (DBG) log("checkMobileProvisioning: params=" + params);
-            checkMp.execute(params);
+            // TODO: Reenable when calls to the now defunct
+            //       MobileDataStateTracker.isProvisioningNetwork() are removed.
+            //       This code should be moved to the Telephony code.
+            // checkMp.execute(params);
         } finally {
             Binder.restoreCallingIdentity(token);
             if (DBG) log("checkMobileProvisioning: X");
@@ -4395,7 +4580,7 @@
                         log("isMobileOk: addresses=" + inetAddressesToString(addresses));
 
                         // Get the type of addresses supported by this link
-                        LinkProperties lp = mCs.getLinkProperties(
+                        LinkProperties lp = mCs.getLinkPropertiesForTypeInternal(
                                 ConnectivityManager.TYPE_MOBILE_HIPRI);
                         boolean linkHasIpv4 = lp.hasIPv4Address();
                         boolean linkHasIpv6 = lp.hasIPv6Address();
@@ -4640,11 +4825,11 @@
         // otherwise launch browser with the intent directly.
         if (mIsProvisioningNetwork.get()) {
             if (DBG) log("handleMobileProvisioningAction: on prov network enable then launch");
-            mIsStartingProvisioning.set(true);
-            MobileDataStateTracker mdst = (MobileDataStateTracker)
-                    mNetTrackers[ConnectivityManager.TYPE_MOBILE];
-            mdst.setEnableFailFastMobileData(DctConstants.ENABLED);
-            mdst.enableMobileProvisioning(url);
+//            mIsStartingProvisioning.set(true);
+//            MobileDataStateTracker mdst = (MobileDataStateTracker)
+//                    mNetTrackers[ConnectivityManager.TYPE_MOBILE];
+//            mdst.setEnableFailFastMobileData(DctConstants.ENABLED);
+//            mdst.enableMobileProvisioning(url);
         } else {
             if (DBG) log("handleMobileProvisioningAction: not prov network");
             // Check for  apps that can handle provisioning first
@@ -4940,7 +5125,7 @@
     @Override
     public LinkQualityInfo getLinkQualityInfo(int networkType) {
         enforceAccessPermission();
-        if (isNetworkTypeValid(networkType)) {
+        if (isNetworkTypeValid(networkType) && mNetTrackers[networkType] != null) {
             return mNetTrackers[networkType].getLinkQualityInfo();
         } else {
             return null;
@@ -4950,7 +5135,8 @@
     @Override
     public LinkQualityInfo getActiveLinkQualityInfo() {
         enforceAccessPermission();
-        if (isNetworkTypeValid(mActiveDefaultNetwork)) {
+        if (isNetworkTypeValid(mActiveDefaultNetwork) &&
+                mNetTrackers[mActiveDefaultNetwork] != null) {
             return mNetTrackers[mActiveDefaultNetwork].getLinkQualityInfo();
         } else {
             return null;
@@ -5023,4 +5209,615 @@
         long wakeupTime = SystemClock.elapsedRealtime() + timeoutInMilliseconds;
         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeupTime, intent);
     }
+
+    private final ArrayList<AsyncChannel> mNetworkFactories = new ArrayList<AsyncChannel>();
+    private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests =
+            new HashMap<NetworkRequest, NetworkRequestInfo>();
+
+
+    private class NetworkRequestInfo implements IBinder.DeathRecipient {
+        static final boolean REQUEST = true;
+        static final boolean LISTEN = false;
+
+        final NetworkRequest request;
+        IBinder mBinder;
+        final int mPid;
+        final int mUid;
+        final Messenger messenger;
+        final boolean isRequest;
+
+        NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder, boolean isRequest) {
+            super();
+            messenger = m;
+            request = r;
+            mBinder = binder;
+            mPid = getCallingPid();
+            mUid = getCallingUid();
+            this.isRequest = isRequest;
+
+            try {
+                mBinder.linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                binderDied();
+            }
+        }
+
+        void unlinkDeathRecipient() {
+            mBinder.unlinkToDeath(this, 0);
+        }
+
+        public void binderDied() {
+            log("ConnectivityService NetworkRequestInfo binderDied(" +
+                    request + ", " + mBinder + ")");
+            releaseNetworkRequest(request);
+        }
+    }
+
+    @Override
+    public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
+            Messenger messenger, int timeoutSec, IBinder binder) {
+        if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+                == false) {
+            enforceConnectivityInternalPermission();
+        } else {
+            enforceChangePermission();
+        }
+
+        if (timeoutSec < 0 || timeoutSec > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_SEC) {
+            throw new IllegalArgumentException("Bad timeout specified");
+        }
+        NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
+                networkCapabilities));
+        if (DBG) log("requestNetwork for " + networkRequest);
+        NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
+                NetworkRequestInfo.REQUEST);
+
+        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri));
+        if (timeoutSec > 0) {
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NETWORK_REQUEST,
+                    nri), timeoutSec * 1000);
+        }
+        return networkRequest;
+    }
+
+    @Override
+    public NetworkRequest pendingRequestForNetwork(NetworkCapabilities networkCapabilities,
+            PendingIntent operation) {
+        // TODO
+        return null;
+    }
+
+    @Override
+    public NetworkRequest listenForNetwork(NetworkCapabilities networkCapabilities,
+            Messenger messenger, IBinder binder) {
+        enforceAccessPermission();
+
+        NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
+                networkCapabilities));
+        if (DBG) log("listenForNetwork for " + networkRequest);
+        NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
+                NetworkRequestInfo.LISTEN);
+
+        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
+        return networkRequest;
+    }
+
+    @Override
+    public void pendingListenForNetwork(NetworkCapabilities networkCapabilities,
+            PendingIntent operation) {
+    }
+
+    @Override
+    public void releaseNetworkRequest(NetworkRequest networkRequest) {
+        mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST,
+                networkRequest));
+    }
+
+    @Override
+    public void registerNetworkFactory(Messenger messenger) {
+        enforceConnectivityInternalPermission();
+        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, messenger));
+    }
+
+    private void handleRegisterNetworkFactory(Messenger messenger) {
+        if (VDBG) log("Got NetworkFactory Messenger");
+        AsyncChannel ac = new AsyncChannel();
+        mNetworkFactories.add(ac);
+        ac.connect(mContext, mTrackerHandler, messenger);
+        for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+            if (nri.isRequest) {
+                int score = 0;
+                NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
+                if (currentNetwork != null) score = currentNetwork.currentScore;
+                ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request);
+            }
+        }
+    }
+
+    /**
+     * NetworkAgentInfo supporting a request by requestId.
+     * These have already been vetted (their Capabilities satisfy the request)
+     * and the are the highest scored network available.
+     * the are keyed off the Requests requestId.
+     */
+    private final SparseArray<NetworkAgentInfo> mNetworkForRequestId =
+            new SparseArray<NetworkAgentInfo>();
+
+    private final SparseArray<NetworkAgentInfo> mNetworkForNetId =
+            new SparseArray<NetworkAgentInfo>();
+
+    // NetworkAgentInfo keyed off its connecting messenger
+    // TODO - eval if we can reduce the number of lists/hashmaps/sparsearrays
+    private final HashMap<Messenger, NetworkAgentInfo> mNetworkAgentInfos =
+            new HashMap<Messenger, NetworkAgentInfo>();
+
+    private final NetworkRequest mDefaultRequest;
+
+    public void registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
+            LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
+            int currentScore) {
+        enforceConnectivityInternalPermission();
+
+        NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), nextNetId(),
+            new NetworkInfo(networkInfo), new LinkProperties(linkProperties),
+            new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler);
+
+        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
+    }
+
+    private void handleRegisterNetworkAgent(NetworkAgentInfo na) {
+        if (VDBG) log("Got NetworkAgent Messenger");
+        mNetworkAgentInfos.put(na.messenger, na);
+        try {
+            mNetworkAgentInfoForType[na.networkInfo.getType()].add(na);
+        } catch (NullPointerException e) {
+            loge("registered NetworkAgent for unsupported type: " + na);
+        }
+        mNetworkForNetId.put(na.network.netId, na);
+        na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger);
+        NetworkInfo networkInfo = na.networkInfo;
+        na.networkInfo = null;
+        updateNetworkInfo(na, networkInfo);
+    }
+
+    private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties oldLp) {
+        LinkProperties newLp = networkAgent.linkProperties;
+        int netId = networkAgent.network.netId;
+
+        updateInterfaces(newLp, oldLp, netId);
+        updateMtu(newLp, oldLp);
+        // TODO - figure out what to do for clat
+//        for (LinkProperties lp : newLp.getStackedLinks()) {
+//            updateMtu(lp, null);
+//        }
+        updateRoutes(newLp, oldLp, netId);
+        updateDnses(newLp, oldLp, netId);
+        updateClat(newLp, oldLp, networkAgent);
+    }
+
+    private void updateClat(LinkProperties newLp, LinkProperties oldLp, NetworkAgentInfo na) {
+        // Update 464xlat state.
+        if (mClat.requiresClat(na)) {
+
+            // If the connection was previously using clat, but is not using it now, stop the clat
+            // daemon. Normally, this happens automatically when the connection disconnects, but if
+            // the disconnect is not reported, or if the connection's LinkProperties changed for
+            // some other reason (e.g., handoff changes the IP addresses on the link), it would
+            // still be running. If it's not running, then stopping it is a no-op.
+            if (Nat464Xlat.isRunningClat(oldLp) && !Nat464Xlat.isRunningClat(newLp)) {
+                mClat.stopClat();
+            }
+            // If the link requires clat to be running, then start the daemon now.
+            if (newLp != null && na.networkInfo.isConnected()) {
+                mClat.startClat(na);
+            } else {
+                mClat.stopClat();
+            }
+        }
+    }
+
+    private void updateInterfaces(LinkProperties newLp, LinkProperties oldLp, int netId) {
+        CompareResult<String> interfaceDiff = new CompareResult<String>();
+        if (oldLp != null) {
+            interfaceDiff = oldLp.compareAllInterfaceNames(newLp);
+        } else if (newLp != null) {
+            interfaceDiff.added = newLp.getAllInterfaceNames();
+        }
+        for (String iface : interfaceDiff.added) {
+            try {
+                mNetd.addInterfaceToNetwork(iface, netId);
+            } catch (Exception e) {
+                loge("Exception adding interface: " + e);
+            }
+        }
+        for (String iface : interfaceDiff.removed) {
+            try {
+                mNetd.removeInterfaceFromNetwork(iface, netId);
+            } catch (Exception e) {
+                loge("Exception removing interface: " + e);
+            }
+        }
+    }
+
+    private void updateRoutes(LinkProperties newLp, LinkProperties oldLp, int netId) {
+        CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();
+        if (oldLp != null) {
+            routeDiff = oldLp.compareAllRoutes(newLp);
+        } else if (newLp != null) {
+            routeDiff.added = newLp.getAllRoutes();
+        }
+
+        // add routes before removing old in case it helps with continuous connectivity
+
+        // do this twice, adding non-nexthop routes first, then routes they are dependent on
+        for (RouteInfo route : routeDiff.added) {
+            if (route.hasGateway()) continue;
+            try {
+                mNetd.addRoute(netId, route);
+            } catch (Exception e) {
+                loge("Exception in addRoute for non-gateway: " + e);
+            }
+        }
+        for (RouteInfo route : routeDiff.added) {
+            if (route.hasGateway() == false) continue;
+            try {
+                mNetd.addRoute(netId, route);
+            } catch (Exception e) {
+                loge("Exception in addRoute for gateway: " + e);
+            }
+        }
+
+        for (RouteInfo route : routeDiff.removed) {
+            try {
+                mNetd.removeRoute(netId, route);
+            } catch (Exception e) {
+                loge("Exception in removeRoute: " + e);
+            }
+        }
+    }
+    private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId) {
+        if (oldLp == null || (newLp.isIdenticalDnses(oldLp) == false)) {
+            Collection<InetAddress> dnses = newLp.getDnses();
+            if (dnses.size() == 0 && mDefaultDns != null) {
+                dnses = new ArrayList();
+                dnses.add(mDefaultDns);
+                if (DBG) {
+                    loge("no dns provided for netId " + netId + ", so using defaults");
+                }
+            }
+            try {
+                mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses),
+                    newLp.getDomains());
+            } catch (Exception e) {
+                loge("Exception in setDnsServersForNetwork: " + e);
+            }
+            // TODO - setprop "net.dnsX"
+        }
+    }
+
+    private void updateCapabilities(NetworkAgentInfo networkAgent,
+            NetworkCapabilities networkCapabilities) {
+        // TODO - what else here?  Verify still satisfies everybody?
+        // Check if satisfies somebody new?  call callbacks?
+        networkAgent.networkCapabilities = networkCapabilities;
+    }
+
+    private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) {
+        if (VDBG) log("sending new Min Network Score(" + score + "): " + networkRequest.toString());
+        for (AsyncChannel ac : mNetworkFactories) {
+            ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, networkRequest);
+        }
+    }
+
+    private void callCallbackForRequest(NetworkRequestInfo nri,
+            NetworkAgentInfo networkAgent, int notificationType) {
+        if (nri.messenger == null) return;  // Default request has no msgr
+        Object o;
+        int a1 = 0;
+        int a2 = 0;
+        switch (notificationType) {
+            case ConnectivityManager.CALLBACK_LOSING:
+                a1 = 30; // TODO - read this from NetworkMonitor
+                // fall through
+            case ConnectivityManager.CALLBACK_PRECHECK:
+            case ConnectivityManager.CALLBACK_AVAILABLE:
+            case ConnectivityManager.CALLBACK_LOST:
+            case ConnectivityManager.CALLBACK_CAP_CHANGED:
+            case ConnectivityManager.CALLBACK_IP_CHANGED: {
+                o = new NetworkRequest(nri.request);
+                a2 = networkAgent.network.netId;
+                break;
+            }
+            case ConnectivityManager.CALLBACK_UNAVAIL:
+            case ConnectivityManager.CALLBACK_RELEASED: {
+                o = new NetworkRequest(nri.request);
+                break;
+            }
+            default: {
+                loge("Unknown notificationType " + notificationType);
+                return;
+            }
+        }
+        Message msg = Message.obtain();
+        msg.arg1 = a1;
+        msg.arg2 = a2;
+        msg.obj = o;
+        msg.what = notificationType;
+        try {
+            if (VDBG) log("sending notification " + notificationType + " for " + nri.request);
+            nri.messenger.send(msg);
+        } catch (RemoteException e) {
+            // may occur naturally in the race of binder death.
+            loge("RemoteException caught trying to send a callback msg for " + nri.request);
+        }
+    }
+
+    private void handleLingerComplete(NetworkAgentInfo oldNetwork) {
+        if (oldNetwork == null) {
+            loge("Unknown NetworkAgentInfo in handleLingerComplete");
+            return;
+        }
+        if (DBG) log("handleLingerComplete for " + oldNetwork.name());
+        if (DBG) {
+            if (oldNetwork.networkRequests.size() != 0) {
+                loge("Dead network still had " + oldNetwork.networkRequests.size() + " requests");
+            }
+        }
+        oldNetwork.asyncChannel.disconnect();
+    }
+
+    private void handleConnectionValidated(NetworkAgentInfo newNetwork) {
+        if (newNetwork == null) {
+            loge("Unknown NetworkAgentInfo in handleConnectionValidated");
+            return;
+        }
+        boolean keep = false;
+        boolean isNewDefault = false;
+        if (DBG) log("handleConnectionValidated for "+newNetwork.name());
+        // check if any NetworkRequest wants this NetworkAgent
+        // first check if it satisfies the NetworkCapabilities
+        ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<NetworkAgentInfo>();
+        if (VDBG) log(" new Network has: " + newNetwork.networkCapabilities);
+        for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+            if (VDBG) log("  checking if request is satisfied: " + nri.request);
+            if (nri.request.networkCapabilities.satisfiedByNetworkCapabilities(
+                    newNetwork.networkCapabilities)) {
+                // next check if it's better than any current network we're using for
+                // this request
+                NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
+                if (VDBG) {
+                    log("currentScore = " +
+                            (currentNetwork != null ? currentNetwork.currentScore : 0) +
+                            ", newScore = " + newNetwork.currentScore);
+                }
+                if (currentNetwork == null ||
+                        currentNetwork.currentScore < newNetwork.currentScore) {
+                    if (currentNetwork != null) {
+                        if (VDBG) log("   accepting network in place of " + currentNetwork.name());
+                        currentNetwork.networkRequests.remove(nri.request.requestId);
+                        currentNetwork.networkLingered.add(nri.request);
+                        affectedNetworks.add(currentNetwork);
+                    } else {
+                        if (VDBG) log("   accepting network in place of null");
+                    }
+                    mNetworkForRequestId.put(nri.request.requestId, newNetwork);
+                    newNetwork.networkRequests.put(nri.request.requestId, nri.request);
+                    keep = true;
+                    // TODO - this could get expensive if we have alot of requests for this
+                    // network.  Think about if there is a way to reduce this.  Push
+                    // netid->request mapping to each factory?
+                    sendUpdatedScoreToFactories(nri.request, newNetwork.currentScore);
+                    if (mDefaultRequest.requestId == nri.request.requestId) {
+                        isNewDefault = true;
+                        updateActiveDefaultNetwork(newNetwork);
+                    }
+                }
+            }
+        }
+        for (NetworkAgentInfo nai : affectedNetworks) {
+            boolean teardown = true;
+            for (int i = 0; i < nai.networkRequests.size(); i++) {
+                NetworkRequest nr = nai.networkRequests.valueAt(i);
+                try {
+                if (mNetworkRequests.get(nr).isRequest) {
+                    teardown = false;
+                }
+                } catch (Exception e) {
+                    loge("Request " + nr + " not found in mNetworkRequests.");
+                    loge("  it came from request list  of " + nai.name());
+                }
+            }
+            if (teardown) {
+                nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_LINGER);
+                notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING);
+            } else {
+                // not going to linger, so kill the list of linger networks..  only
+                // notify them of linger if it happens as the result of gaining another,
+                // but if they transition and old network stays up, don't tell them of linger
+                // or very delayed loss
+                nai.networkLingered.clear();
+                if (VDBG) log("Lingered for " + nai.name() + " cleared");
+            }
+        }
+        if (keep) {
+            if (isNewDefault) {
+                if (VDBG) log("Switching to new default network: " + newNetwork);
+                setupDataActivityTracking(newNetwork);
+                try {
+                    mNetd.setDefaultNetId(newNetwork.network.netId);
+                } catch (Exception e) {
+                    loge("Exception setting default network :" + e);
+                }
+                if (newNetwork.equals(mNetworkForRequestId.get(mDefaultRequest.requestId))) {
+                    handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
+                }
+                synchronized (ConnectivityService.this) {
+                    // have a new default network, release the transition wakelock in
+                    // a second if it's held.  The second pause is to allow apps
+                    // to reconnect over the new network
+                    if (mNetTransitionWakeLock.isHeld()) {
+                        mHandler.sendMessageDelayed(mHandler.obtainMessage(
+                                EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
+                                mNetTransitionWakeLockSerialNumber, 0),
+                                1000);
+                    }
+                }
+
+                // this will cause us to come up initially as unconnected and switching
+                // to connected after our normal pause unless somebody reports us as
+                // really disconnected
+                mDefaultInetConditionPublished = 0;
+                mDefaultConnectionSequence++;
+                mInetConditionChangeInFlight = false;
+                // TODO - read the tcp buffer size config string from somewhere
+                // updateNetworkSettings();
+            }
+            // notify battery stats service about this network
+//            try {
+                // TODO
+                //BatteryStatsService.getService().noteNetworkInterfaceType(iface, netType);
+//            } catch (RemoteException e) { }
+            notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_AVAILABLE);
+        } else {
+            if (DBG && newNetwork.networkRequests.size() != 0) {
+                loge("tearing down network with live requests:");
+                for (int i=0; i < newNetwork.networkRequests.size(); i++) {
+                    loge("  " + newNetwork.networkRequests.valueAt(i));
+                }
+            }
+            if (VDBG) log("Validated network turns out to be unwanted.  Tear it down.");
+            newNetwork.asyncChannel.disconnect();
+        }
+    }
+
+
+    private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {
+        NetworkInfo.State state = newInfo.getState();
+        NetworkInfo oldInfo = networkAgent.networkInfo;
+        networkAgent.networkInfo = newInfo;
+
+        if (oldInfo != null && oldInfo.getState() == state) {
+            if (VDBG) log("ignoring duplicate network state non-change");
+            return;
+        }
+        if (DBG) {
+            log(networkAgent.name() + " EVENT_NETWORK_INFO_CHANGED, going from " +
+                    (oldInfo == null ? "null" : oldInfo.getState()) +
+                    " to " + state);
+        }
+
+        if (state == NetworkInfo.State.CONNECTED) {
+            // TODO - check if we want it (optimization)
+            try {
+                mNetd.createNetwork(networkAgent.network.netId);
+            } catch (Exception e) {
+                loge("Error creating Network " + networkAgent.network.netId);
+            }
+            updateLinkProperties(networkAgent, null);
+            notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK);
+            networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
+        } else if (state == NetworkInfo.State.DISCONNECTED ||
+                state == NetworkInfo.State.SUSPENDED) {
+            networkAgent.asyncChannel.disconnect();
+        }
+    }
+
+    // notify only this one new request of the current state
+    protected void notifyNetworkCallback(NetworkAgentInfo nai, NetworkRequestInfo nri) {
+        int notifyType = ConnectivityManager.CALLBACK_AVAILABLE;
+        // TODO - read state from monitor to decide what to send.
+//        if (nai.networkMonitor.isLingering()) {
+//            notifyType = NetworkCallbacks.LOSING;
+//        } else if (nai.networkMonitor.isEvaluating()) {
+//            notifyType = NetworkCallbacks.callCallbackForRequest(request, nai, notifyType);
+//        }
+        if (nri.request.needsBroadcasts) {
+        // TODO
+//            sendNetworkBroadcast(nai, notifyType);
+        }
+        callCallbackForRequest(nri, nai, notifyType);
+    }
+
+    protected void notifyNetworkCallbacks(NetworkAgentInfo networkAgent, int notifyType) {
+        if (VDBG) log("notifyType " + notifyType + " for " + networkAgent.name());
+        boolean needsBroadcasts = false;
+        for (int i = 0; i < networkAgent.networkRequests.size(); i++) {
+            NetworkRequest nr = networkAgent.networkRequests.valueAt(i);
+            NetworkRequestInfo nri = mNetworkRequests.get(nr);
+            if (VDBG) log(" sending notification for " + nr);
+            if (nr.needsBroadcasts) needsBroadcasts = true;
+            callCallbackForRequest(nri, networkAgent, notifyType);
+        }
+        if (needsBroadcasts) {
+            if (notifyType == ConnectivityManager.CALLBACK_AVAILABLE) {
+                sendConnectedBroadcastDelayed(networkAgent.networkInfo,
+                        getConnectivityChangeDelay());
+            } else if (notifyType == ConnectivityManager.CALLBACK_LOST) {
+                NetworkInfo info = new NetworkInfo(networkAgent.networkInfo);
+                Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
+                intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
+                intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
+                if (info.isFailover()) {
+                    intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
+                    networkAgent.networkInfo.setFailover(false);
+                }
+                if (info.getReason() != null) {
+                    intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
+                }
+                if (info.getExtraInfo() != null) {
+                    intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo());
+                }
+                NetworkAgentInfo newDefaultAgent = null;
+                if (networkAgent.networkRequests.get(mDefaultRequest.requestId) != null) {
+                    newDefaultAgent = mNetworkForRequestId.get(mDefaultRequest.requestId);
+                    if (newDefaultAgent != null) {
+                        intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO,
+                                newDefaultAgent.networkInfo);
+                    } else {
+                        intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
+                    }
+                }
+                intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION,
+                        mDefaultInetConditionPublished);
+                final Intent immediateIntent = new Intent(intent);
+                immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
+                sendStickyBroadcast(immediateIntent);
+                sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay());
+                if (newDefaultAgent != null) {
+                    sendConnectedBroadcastDelayed(newDefaultAgent.networkInfo,
+                            getConnectivityChangeDelay());
+                }
+            }
+        }
+    }
+
+    private LinkProperties getLinkPropertiesForTypeInternal(int networkType) {
+        ArrayList<NetworkAgentInfo> list = mNetworkAgentInfoForType[networkType];
+        if (list == null) return null;
+        try {
+            return new LinkProperties(list.get(0).linkProperties);
+        } catch (IndexOutOfBoundsException e) {
+            return new LinkProperties();
+        }
+    }
+
+    private NetworkInfo getNetworkInfoForType(int networkType) {
+        ArrayList<NetworkAgentInfo> list = mNetworkAgentInfoForType[networkType];
+        if (list == null) return null;
+        try {
+            return new NetworkInfo(list.get(0).networkInfo);
+        } catch (IndexOutOfBoundsException e) {
+            return new NetworkInfo(networkType, 0, "Unknown", "");
+        }
+    }
+
+    private NetworkCapabilities getNetworkCapabilitiesForType(int networkType) {
+        ArrayList<NetworkAgentInfo> list = mNetworkAgentInfoForType[networkType];
+        if (list == null) return null;
+        try {
+            return new NetworkCapabilities(list.get(0).networkCapabilities);
+        } catch (IndexOutOfBoundsException e) {
+            return new NetworkCapabilities();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 5083d44..6fab37c2 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -65,6 +65,8 @@
 27501 notification_panel_hidden
 # when notifications are newly displayed on screen, or disappear from screen
 27510 notification_visibility_changed (newlyVisibleKeys|3),(noLongerVisibleKeys|3)
+# when a notification has been clicked
+27520 notification_clicked (key|3)
 
 # ---------------------------
 # Watchdog.java
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 6fc3e77..0b9570d 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -1464,6 +1464,7 @@
 
     private boolean needsToShowImeSwitchOngoingNotification() {
         if (!mShowOngoingImeSwitcherForPhones) return false;
+        if (mSwitchingDialog != null) return false;
         if (isScreenLocked()) return false;
         synchronized (mMethodMap) {
             List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked();
@@ -1532,14 +1533,17 @@
                 }
                 mImeWindowVis = vis;
                 mBackDisposition = backDisposition;
-                if (mStatusBar != null) {
-                    mStatusBar.setImeWindowStatus(token, vis, backDisposition);
-                }
                 final boolean iconVisibility = ((vis & (InputMethodService.IME_ACTIVE)) != 0)
                         && (mWindowManagerService.isHardKeyboardAvailable()
                                 || (vis & (InputMethodService.IME_VISIBLE)) != 0);
+                final boolean needsToShowImeSwitcher = iconVisibility
+                        && needsToShowImeSwitchOngoingNotification();
+                if (mStatusBar != null) {
+                    mStatusBar.setImeWindowStatus(token, vis, backDisposition,
+                            needsToShowImeSwitcher);
+                }
                 final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
-                if (imi != null && iconVisibility && needsToShowImeSwitchOngoingNotification()) {
+                if (imi != null && needsToShowImeSwitcher) {
                     // Used to load label
                     final CharSequence title = mRes.getText(
                             com.android.internal.R.string.select_input_method);
@@ -1548,7 +1552,8 @@
 
                     mImeSwitcherNotification.setLatestEventInfo(
                             mContext, title, summary, mImeSwitchPendingIntent);
-                    if (mNotificationManager != null) {
+                    if ((mNotificationManager != null)
+                            && !mWindowManagerService.hasNavigationBar()) {
                         if (DEBUG) {
                             Slog.d(TAG, "--- show notification: label =  " + summary);
                         }
@@ -2808,6 +2813,7 @@
             mSwitchingDialog.getWindow().getAttributes().privateFlags |=
                     WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
             mSwitchingDialog.getWindow().getAttributes().setTitle("Select input method");
+            updateImeWindowStatusLocked();
             mSwitchingDialog.show();
         }
     }
@@ -2865,6 +2871,7 @@
             mSwitchingDialog = null;
         }
 
+        updateImeWindowStatusLocked();
         mDialogBuilder = null;
         mIms = null;
     }
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 62deec2..e54e5d0 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -426,29 +426,33 @@
             Slog.e(TAG,  "no geocoder provider found");
         }
 
-        // bind to fused provider
-        FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
-        FusedProxy fusedProxy = FusedProxy.createAndBind(
-                mContext,
-                mLocationHandler,
-                flpHardwareProvider.getLocationHardware(),
-                com.android.internal.R.bool.config_enableFusedLocationOverlay,
-                com.android.internal.R.string.config_fusedLocationProviderPackageName,
-                com.android.internal.R.array.config_locationProviderPackageNames);
-        if(fusedProxy == null) {
-            Slog.e(TAG, "No FusedProvider found.");
-        }
+        // bind to fused provider if supported
+        if (FlpHardwareProvider.getInstance(mContext).isSupported()) {
+          FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
+          FusedProxy fusedProxy = FusedProxy.createAndBind(
+                  mContext,
+                  mLocationHandler,
+                  flpHardwareProvider.getLocationHardware(),
+                  com.android.internal.R.bool.config_enableFusedLocationOverlay,
+                  com.android.internal.R.string.config_fusedLocationProviderPackageName,
+                  com.android.internal.R.array.config_locationProviderPackageNames);
+          if(fusedProxy == null) {
+              Slog.e(TAG, "Unable to bind FusedProxy.");
+          }
 
-        // bind to geofence provider
-        GeofenceProxy provider = GeofenceProxy.createAndBind(mContext,
-                com.android.internal.R.bool.config_enableGeofenceOverlay,
-                com.android.internal.R.string.config_geofenceProviderPackageName,
-                com.android.internal.R.array.config_locationProviderPackageNames,
-                mLocationHandler,
-                gpsProvider.getGpsGeofenceProxy(),
-                flpHardwareProvider.getGeofenceHardware());
-        if (provider == null) {
-            Slog.e(TAG,  "no geofence provider found");
+          // bind to geofence provider
+          GeofenceProxy provider = GeofenceProxy.createAndBind(mContext,
+                  com.android.internal.R.bool.config_enableGeofenceOverlay,
+                  com.android.internal.R.string.config_geofenceProviderPackageName,
+                  com.android.internal.R.array.config_locationProviderPackageNames,
+                  mLocationHandler,
+                  gpsProvider.getGpsGeofenceProxy(),
+                  flpHardwareProvider.getGeofenceHardware());
+          if (provider == null) {
+              Slog.e(TAG,  "Unable to bind FLP Geofence proxy.");
+          }
+        } else {
+          Slog.e(TAG, "FLP HAL not supported.");
         }
 
         String[] testProviderStrings = resources.getStringArray(
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 7ec9b82..d5f045e 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -201,8 +201,8 @@
     public static final String[] CRYPTO_TYPES
         = { "password", "default", "pattern", "pin" };
 
-    private Context mContext;
-    private NativeDaemonConnector mConnector;
+    private final Context mContext;
+    private final NativeDaemonConnector mConnector;
 
     private final Object mVolumesLock = new Object();
 
diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java
index 0d1e122..96f9ab0 100644
--- a/services/core/java/com/android/server/NativeDaemonConnector.java
+++ b/services/core/java/com/android/server/NativeDaemonConnector.java
@@ -50,6 +50,8 @@
 final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdog.Monitor {
     private static final boolean LOGD = false;
 
+    private final static boolean VDBG = false;
+
     private final String TAG;
 
     private String mSocket;
@@ -409,7 +411,7 @@
                 loge("timed-out waiting for response to " + logCmd);
                 throw new NativeDaemonFailureException(logCmd, event);
             }
-            log("RMV <- {" + event + "}");
+            if (VDBG) log("RMV <- {" + event + "}");
             events.add(event);
         } while (event.isClassContinue());
 
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 7ce45f7..cf91782 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import static android.Manifest.permission.CHANGE_NETWORK_STATE;
 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
 import static android.Manifest.permission.DUMP;
 import static android.Manifest.permission.SHUTDOWN;
@@ -867,46 +868,25 @@
     }
 
     @Override
-    public void addRoute(String interfaceName, RouteInfo route) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        modifyRoute(interfaceName, ADD, route, DEFAULT);
+    public void addRoute(int netId, RouteInfo route) {
+        modifyRoute(netId, ADD, route);
     }
 
     @Override
-    public void removeRoute(String interfaceName, RouteInfo route) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        modifyRoute(interfaceName, REMOVE, route, DEFAULT);
+    public void removeRoute(int netId, RouteInfo route) {
+        modifyRoute(netId, REMOVE, route);
     }
 
-    @Override
-    public void addSecondaryRoute(String interfaceName, RouteInfo route) {
+    private void modifyRoute(int netId, String action, RouteInfo route) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        modifyRoute(interfaceName, ADD, route, SECONDARY);
-    }
 
-    @Override
-    public void removeSecondaryRoute(String interfaceName, RouteInfo route) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        modifyRoute(interfaceName, REMOVE, route, SECONDARY);
-    }
+        final Command cmd = new Command("network", "route", action, netId);
 
-    private void modifyRoute(String interfaceName, String action, RouteInfo route, String type) {
-        final Command cmd = new Command("interface", "route", action, interfaceName, type);
-
-        // create triplet: dest-ip-addr prefixlength gateway-ip-addr
+        // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
         final LinkAddress la = route.getDestination();
-        cmd.appendArg(la.getAddress().getHostAddress());
-        cmd.appendArg(la.getNetworkPrefixLength());
-
-        if (route.getGateway() == null) {
-            if (la.getAddress() instanceof Inet4Address) {
-                cmd.appendArg("0.0.0.0");
-            } else {
-                cmd.appendArg("::0");
-            }
-        } else {
-            cmd.appendArg(route.getGateway().getHostAddress());
-        }
+        cmd.appendArg(route.getInterface());
+        cmd.appendArg(la.getAddress().getHostAddress() + "/" + la.getNetworkPrefixLength());
+        cmd.appendArg(route.getGateway().getHostAddress());
 
         try {
             mConnector.execute(cmd);
@@ -1624,20 +1604,10 @@
     }
 
     @Override
-    public void setDefaultInterfaceForDns(String iface) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        try {
-            mConnector.execute("resolver", "setdefaultif", iface);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-    }
-
-    @Override
-    public void setDnsServersForInterface(String iface, String[] servers, String domains) {
+    public void setDnsServersForNetwork(int netId, String[] servers, String domains) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
-        final Command cmd = new Command("resolver", "setifdns", iface,
+        final Command cmd = new Command("resolver", "setnetdns", netId,
                 (domains == null ? "" : domains));
 
         for (String s : servers) {
@@ -1655,11 +1625,11 @@
     }
 
     @Override
-    public void setUidRangeRoute(String iface, int uid_start, int uid_end) {
+    public void setUidRangeRoute(String iface, int uid_start, int uid_end, boolean forward_dns) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
         try {
             mConnector.execute("interface", "fwmark",
-                    "uid", "add", iface, uid_start, uid_end);
+                    "uid", "add", iface, uid_start, uid_end, forward_dns ? 1 : 0);
         } catch (NativeDaemonConnectorException e) {
             throw e.rethrowAsParcelableException();
         }
@@ -1670,7 +1640,7 @@
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
         try {
             mConnector.execute("interface", "fwmark",
-                    "uid", "remove", iface, uid_start, uid_end);
+                    "uid", "remove", iface, uid_start, uid_end, 0);
         } catch (NativeDaemonConnectorException e) {
             throw e.rethrowAsParcelableException();
         }
@@ -1767,51 +1737,10 @@
     }
 
     @Override
-    public void setDnsInterfaceForUidRange(String iface, int uid_start, int uid_end) {
+    public void flushNetworkDnsCache(int netId) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
         try {
-            mConnector.execute("resolver", "setifaceforuidrange", iface, uid_start, uid_end);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-    }
-
-    @Override
-    public void clearDnsInterfaceForUidRange(String iface, int uid_start, int uid_end) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        try {
-            mConnector.execute("resolver", "clearifaceforuidrange", iface, uid_start, uid_end);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-    }
-
-    @Override
-    public void clearDnsInterfaceMaps() {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        try {
-            mConnector.execute("resolver", "clearifacemapping");
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-    }
-
-
-    @Override
-    public void flushDefaultDnsCache() {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        try {
-            mConnector.execute("resolver", "flushdefaultif");
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-    }
-
-    @Override
-    public void flushInterfaceDnsCache(String iface) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        try {
-            mConnector.execute("resolver", "flushif", iface);
+            mConnector.execute("resolver", "flushnet", netId);
         } catch (NativeDaemonConnectorException e) {
             throw e.rethrowAsParcelableException();
         }
@@ -1890,28 +1819,6 @@
     }
 
     @Override
-    public void setDnsInterfaceForPid(String iface, int pid) throws IllegalStateException {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        try {
-            mConnector.execute("resolver", "setifaceforpid", iface, pid);
-        } catch (NativeDaemonConnectorException e) {
-            throw new IllegalStateException(
-                    "Error communicating with native deamon to set interface for pid" + iface, e);
-        }
-    }
-
-    @Override
-    public void clearDnsInterfaceForPid(int pid) throws IllegalStateException {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        try {
-            mConnector.execute("resolver", "clearifaceforpid", pid);
-        } catch (NativeDaemonConnectorException e) {
-            throw new IllegalStateException(
-                    "Error communicating with native deamon to clear interface for pid " + pid, e);
-        }
-    }
-
-    @Override
     public void startClatd(String interfaceName) throws IllegalStateException {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
@@ -2029,4 +1936,133 @@
 
         pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
     }
+
+    @Override
+    public void createNetwork(int netId) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+        try {
+            mConnector.execute("network", "create", netId);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void removeNetwork(int netId) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+        try {
+            mConnector.execute("network", "destroy", netId);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void addInterfaceToNetwork(String iface, int netId) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+        try {
+            mConnector.execute("network", "addiface", netId, iface);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void removeInterfaceFromNetwork(String iface, int netId) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+        try {
+            mConnector.execute("network", "removeiface", netId, iface);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void addLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid) {
+        modifyLegacyRouteForNetId(netId, routeInfo, uid, ADD);
+    }
+
+    @Override
+    public void removeLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid) {
+        modifyLegacyRouteForNetId(netId, routeInfo, uid, REMOVE);
+    }
+
+    private void modifyLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid, String action) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+        final Command cmd = new Command("network", "legacy", uid, "route", action, netId);
+
+        // create quadlet: dest-ip-addr prefixlength gateway-ip-addr iface
+        final LinkAddress la = routeInfo.getDestination();
+        cmd.appendArg(la.getAddress().getHostAddress());
+        cmd.appendArg(la.getNetworkPrefixLength());
+        cmd.appendArg(routeInfo.getGateway().getHostAddress());
+        cmd.appendArg(routeInfo.getInterface());
+
+        try {
+            mConnector.execute(cmd);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void setDefaultNetId(int netId) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+        try {
+            mConnector.execute("network", "default", "set", netId);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void clearDefaultNetId() {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+        try {
+            mConnector.execute("network", "default", "clear");
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void setPermission(boolean internal, boolean changeNetState, int[] uids) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+        final Command cmd = new Command("network", "permission", "user", "set");
+        if (internal) cmd.appendArg(CONNECTIVITY_INTERNAL);
+        if (changeNetState) cmd.appendArg(CHANGE_NETWORK_STATE);
+        for (int i=0; i<uids.length; i++) {
+            cmd.appendArg(uids[i]);
+        }
+
+        try {
+            mConnector.execute(cmd);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void clearPermission(int[] uids) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+        final Command cmd = new Command("network", "permission", "user", "clear");
+        for (int i=0; i<uids.length; i++) {
+            cmd.appendArg(uids[i]);
+        }
+
+        try {
+            mConnector.execute(cmd);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 8a30e50..512ebc6 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -20,19 +20,24 @@
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
+import android.net.INetworkScoreCache;
 import android.net.INetworkScoreService;
-import android.net.NetworkKey;
 import android.net.NetworkScorerAppManager;
-import android.net.RssiCurve;
 import android.net.ScoredNetwork;
+import android.os.RemoteException;
 import android.text.TextUtils;
+import android.util.Log;
 
 import com.android.internal.R;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Backing service for {@link android.net.NetworkScoreManager}.
@@ -46,12 +51,11 @@
 
     private final Context mContext;
 
-    // TODO: Delete this temporary class once we have a real place for scores.
-    private final Map<NetworkKey, RssiCurve> mScoredNetworks;
+    private final Map<Integer, INetworkScoreCache> mScoreCaches;
 
     public NetworkScoreService(Context context) {
         mContext = context;
-        mScoredNetworks = new HashMap<>();
+        mScoreCaches = new HashMap<>();
     }
 
     /** Called when the system is ready to run third-party code but before it actually does so. */
@@ -76,10 +80,31 @@
                     " is not the active scorer.");
         }
 
-        // TODO: Propagate these scores down to the network subsystem layer instead of just holding
-        // them in memory.
+        // Separate networks by type.
+        Map<Integer, List<ScoredNetwork>> networksByType = new HashMap<>();
         for (ScoredNetwork network : networks) {
-            mScoredNetworks.put(network.networkKey, network.rssiCurve);
+            List<ScoredNetwork> networkList = networksByType.get(network.networkKey.type);
+            if (networkList == null) {
+                networkList = new ArrayList<>();
+                networksByType.put(network.networkKey.type, networkList);
+            }
+            networkList.add(network);
+        }
+
+        // Pass the scores of each type down to the appropriate network scorer.
+        for (Map.Entry<Integer, List<ScoredNetwork>> entry : networksByType.entrySet()) {
+            INetworkScoreCache scoreCache = mScoreCaches.get(entry.getKey());
+            if (scoreCache != null) {
+                try {
+                    scoreCache.updateScores(entry.getValue());
+                } catch (RemoteException e) {
+                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                        Log.v(TAG, "Unable to update scores of type " + entry.getKey(), e);
+                    }
+                }
+            } else if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "No scorer registered for type " + entry.getKey() + ", discarding");
+            }
         }
 
         return true;
@@ -112,8 +137,29 @@
 
     /** Clear scores. Callers are responsible for checking permissions as appropriate. */
     private void clearInternal() {
-        // TODO: Propagate the flush down to the network subsystem layer.
-        mScoredNetworks.clear();
+        Set<INetworkScoreCache> cachesToClear = getScoreCaches();
+
+        for (INetworkScoreCache scoreCache : cachesToClear) {
+            try {
+                scoreCache.clearScores();
+            } catch (RemoteException e) {
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "Unable to clear scores", e);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
+        mContext.enforceCallingOrSelfPermission(permission.BROADCAST_SCORE_NETWORKS, TAG);
+        synchronized (mScoreCaches) {
+            if (mScoreCaches.containsKey(networkType)) {
+                throw new IllegalArgumentException(
+                        "Score cache already registered for type " + networkType);
+            }
+            mScoreCaches.put(networkType, scoreCache);
+        }
     }
 
     @Override
@@ -125,12 +171,29 @@
             return;
         }
         writer.println("Current scorer: " + currentScorer);
-        if (mScoredNetworks.isEmpty()) {
-            writer.println("No networks scored.");
-        } else {
-            for (Map.Entry<NetworkKey, RssiCurve> entry : mScoredNetworks.entrySet()) {
-                writer.println(entry.getKey() + ": " + entry.getValue());
+        writer.flush();
+
+        for (INetworkScoreCache scoreCache : getScoreCaches()) {
+            try {
+                scoreCache.asBinder().dump(fd, args);
+            } catch (RemoteException e) {
+                writer.println("Unable to dump score cache");
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "Unable to dump score cache", e);
+                }
             }
         }
     }
+
+    /**
+     * Returns a set of all score caches that are currently active.
+     *
+     * <p>May be used to perform an action on all score caches without potentially strange behavior
+     * if a new scorer is registered during that action's execution.
+     */
+    private Set<INetworkScoreCache> getScoreCaches() {
+        synchronized (mScoreCaches) {
+            return new HashSet<>(mScoreCaches.values());
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/RecognitionManagerService.java b/services/core/java/com/android/server/RecognitionManagerService.java
index c2e749d..60d38ae 100644
--- a/services/core/java/com/android/server/RecognitionManagerService.java
+++ b/services/core/java/com/android/server/RecognitionManagerService.java
@@ -78,8 +78,10 @@
         mMonitor = new MyPackageMonitor();
         mMonitor.register(context, null, UserHandle.ALL, true);
         mIPm = AppGlobals.getPackageManager();
+        IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
+        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
         mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
-                new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
+                filter, null, null);
     }
 
     public void systemReady() {
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index d4565b6..cfaf016 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -22,8 +22,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
-import android.net.LinkCapabilities;
 import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -120,7 +120,7 @@
 
     private LinkProperties mDataConnectionLinkProperties;
 
-    private LinkCapabilities mDataConnectionLinkCapabilities;
+    private NetworkCapabilities mDataConnectionNetworkCapabilities;
 
     private Bundle mCellLocation = new Bundle();
 
@@ -553,7 +553,7 @@
 
     public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
             String reason, String apn, String apnType, LinkProperties linkProperties,
-            LinkCapabilities linkCapabilities, int networkType, boolean roaming) {
+            NetworkCapabilities networkCapabilities, int networkType, boolean roaming) {
         if (!checkNotifyPermission("notifyDataConnection()" )) {
             return;
         }
@@ -587,7 +587,7 @@
             mDataConnectionPossible = isDataConnectivityPossible;
             mDataConnectionReason = reason;
             mDataConnectionLinkProperties = linkProperties;
-            mDataConnectionLinkCapabilities = linkCapabilities;
+            mDataConnectionNetworkCapabilities = networkCapabilities;
             if (mDataConnectionNetworkType != networkType) {
                 mDataConnectionNetworkType = networkType;
                 // need to tell registered listeners about the new network type
@@ -624,7 +624,7 @@
             handleRemoveListLocked();
         }
         broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
-                apnType, linkProperties, linkCapabilities, roaming);
+                apnType, linkProperties, networkCapabilities, roaming);
         broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn, reason,
                 linkProperties, "");
     }
@@ -794,7 +794,8 @@
             pw.println("  mDataConnectionReason=" + mDataConnectionReason);
             pw.println("  mDataConnectionApn=" + mDataConnectionApn);
             pw.println("  mDataConnectionLinkProperties=" + mDataConnectionLinkProperties);
-            pw.println("  mDataConnectionLinkCapabilities=" + mDataConnectionLinkCapabilities);
+            pw.println("  mDataConnectionNetworkCapabilities=" +
+                    mDataConnectionNetworkCapabilities);
             pw.println("  mCellLocation=" + mCellLocation);
             pw.println("  mCellInfo=" + mCellInfo);
             pw.println("  mDcRtInfo=" + mDcRtInfo);
@@ -862,7 +863,7 @@
     private void broadcastDataConnectionStateChanged(int state,
             boolean isDataConnectivityPossible,
             String reason, String apn, String apnType, LinkProperties linkProperties,
-            LinkCapabilities linkCapabilities, boolean roaming) {
+            NetworkCapabilities networkCapabilities, boolean roaming) {
         // Note: not reporting to the battery stats service here, because the
         // status bar takes care of that after taking into account all of the
         // required info.
@@ -882,8 +883,8 @@
                 intent.putExtra(PhoneConstants.DATA_IFACE_NAME_KEY, iface);
             }
         }
-        if (linkCapabilities != null) {
-            intent.putExtra(PhoneConstants.DATA_LINK_CAPABILITIES_KEY, linkCapabilities);
+        if (networkCapabilities != null) {
+            intent.putExtra(PhoneConstants.DATA_NETWORK_CAPABILITIES_KEY, networkCapabilities);
         }
         if (roaming) intent.putExtra(PhoneConstants.DATA_NETWORK_ROAMING_KEY, true);
 
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 132ca00..82c13e0 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -41,6 +41,7 @@
 import android.provider.Settings.SettingNotFoundException;
 import android.util.Slog;
 import android.view.InputDevice;
+import android.media.AudioManager;
 
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IBatteryStats;
@@ -73,6 +74,8 @@
     private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
 
     private int mCurVibUid = -1;
+    private boolean mLowPowerMode;
+    private SettingsObserver mSettingObserver;
 
     native static boolean vibratorExists();
     native static void vibratorOn(long milliseconds);
@@ -159,15 +162,15 @@
 
     public void systemReady() {
         mIm = (InputManager)mContext.getSystemService(Context.INPUT_SERVICE);
+        mSettingObserver = new SettingsObserver(mH);
 
         mContext.getContentResolver().registerContentObserver(
-                Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES), true,
-                new ContentObserver(mH) {
-                    @Override
-                    public void onChange(boolean selfChange) {
-                        updateInputDeviceVibrators();
-                    }
-                }, UserHandle.USER_ALL);
+                Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
+                true, mSettingObserver, UserHandle.USER_ALL);
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE), false,
+                mSettingObserver, UserHandle.USER_ALL);
 
         mContext.registerReceiver(new BroadcastReceiver() {
             @Override
@@ -179,6 +182,17 @@
         updateInputDeviceVibrators();
     }
 
+    private final class SettingsObserver extends ContentObserver {
+        public SettingsObserver(Handler handler) {
+            super(handler);
+        }
+
+        @Override
+        public void onChange(boolean SelfChange) {
+            updateInputDeviceVibrators();
+        }
+    }
+
     public boolean hasVibrator() {
         return doVibratorExists();
     }
@@ -346,6 +360,10 @@
     // Lock held on mVibrations
     private void startVibrationLocked(final Vibration vib) {
         try {
+            if (mLowPowerMode && vib.mStreamHint != AudioManager.STREAM_RING) {
+                return;
+            }
+
             int mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
                     vib.mStreamHint, vib.mUid, vib.mOpPkg);
             if (mode == AppOpsManager.MODE_ALLOWED) {
@@ -425,6 +443,9 @@
                 } catch (SettingNotFoundException snfe) {
                 }
 
+                mLowPowerMode = Settings.Global.getInt(mContext.getContentResolver(),
+                         Settings.Global.LOW_POWER_MODE, 0) != 0;
+
                 if (mVibrateInputDevicesSetting) {
                     if (!mInputDeviceListenerRegistered) {
                         mInputDeviceListenerRegistered = true;
diff --git a/services/core/java/com/android/server/WiredAccessoryManager.java b/services/core/java/com/android/server/WiredAccessoryManager.java
index 415fcc1..c32beda 100644
--- a/services/core/java/com/android/server/WiredAccessoryManager.java
+++ b/services/core/java/com/android/server/WiredAccessoryManager.java
@@ -70,6 +70,7 @@
     private static final String NAME_HDMI = "hdmi";
 
     private static final int MSG_NEW_DEVICE_STATE = 1;
+    private static final int MSG_SYSTEM_READY = 2;
 
     private final Object mLock = new Object();
 
@@ -96,17 +97,9 @@
                 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
 
         mObserver = new WiredAccessoryObserver();
-
-        context.registerReceiver(new BroadcastReceiver() {
-                    @Override
-                    public void onReceive(Context ctx, Intent intent) {
-                        bootCompleted();
-                    }
-                },
-                new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
     }
 
-    private void bootCompleted() {
+    private void onSystemReady() {
         if (mUseDevInputEventForAudioJack) {
             int switchValues = 0;
             if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_HEADPHONE_INSERT) == 1) {
@@ -157,6 +150,16 @@
         }
     }
 
+    @Override
+    public void systemReady() {
+        synchronized (mLock) {
+            mWakeLock.acquire();
+
+            Message msg = mHandler.obtainMessage(MSG_SYSTEM_READY, 0, 0, null);
+            mHandler.sendMessage(msg);
+        }
+    }
+
     /**
      * Compare the existing headset state with the new state and pass along accordingly. Note
      * that this only supports a single headset at a time. Inserting both a usb and jacked headset
@@ -218,6 +221,11 @@
                 case MSG_NEW_DEVICE_STATE:
                     setDevicesState(msg.arg1, msg.arg2, (String)msg.obj);
                     mWakeLock.release();
+                    break;
+                case MSG_SYSTEM_READY:
+                    onSystemReady();
+                    mWakeLock.release();
+                    break;
             }
         }
     };
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index f587ccc..b2aaf74 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -34,6 +34,7 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentValues;
@@ -857,7 +858,7 @@
         checkManageAccountsPermission();
         UserHandle user = Binder.getCallingUserHandle();
         UserAccounts accounts = getUserAccountsForCaller();
-        if (!canUserModifyAccounts(Binder.getCallingUid())) {
+        if (!canUserModifyAccounts(Binder.getCallingUid(), account.type)) {
             try {
                 response.onError(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
                         "User cannot modify accounts");
@@ -1512,7 +1513,7 @@
         checkManageAccountsPermission();
 
         // Is user disallowed from modifying accounts?
-        if (!canUserModifyAccounts(Binder.getCallingUid())) {
+        if (!canUserModifyAccounts(Binder.getCallingUid(), accountType)) {
             try {
                 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
                         "User is not allowed to add an account!");
@@ -2758,7 +2759,7 @@
                 Manifest.permission.USE_CREDENTIALS);
     }
 
-    private boolean canUserModifyAccounts(int callingUid) {
+    private boolean canUserModifyAccounts(int callingUid, String accountType) {
         if (callingUid != Process.myUid()) {
             if (getUserManager().getUserRestrictions(
                     new UserHandle(UserHandle.getUserId(callingUid)))
@@ -2766,6 +2767,15 @@
                 return false;
             }
         }
+
+        DevicePolicyManager dpm = (DevicePolicyManager) mContext
+                .getSystemService(Context.DEVICE_POLICY_SERVICE);
+        String[] typesArray = dpm.getAccountTypesWithManagementDisabled();
+        for (String forbiddenType : typesArray) {
+            if (forbiddenType.equals(accountType)) {
+                return false;
+            }
+        }
         return true;
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0c91907..4ed68767 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -32,9 +32,11 @@
 import android.app.AppOpsManager;
 import android.app.IActivityContainer;
 import android.app.IActivityContainerCallback;
+import android.app.IAppTask;
 import android.appwidget.AppWidgetManager;
 import android.graphics.Rect;
 import android.os.BatteryStats;
+import android.os.PersistableBundle;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.ArrayMap;
 
@@ -95,7 +97,6 @@
 import android.app.IProcessObserver;
 import android.app.IServiceConnection;
 import android.app.IStopUserCallback;
-import android.app.IThumbnailReceiver;
 import android.app.IUiAutomationConnection;
 import android.app.IUserSwitchObserver;
 import android.app.Instrumentation;
@@ -137,7 +138,7 @@
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.net.Proxy;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -703,13 +704,6 @@
     String mBackupAppName = null;
     BackupRecord mBackupTarget = null;
 
-    /**
-     * List of PendingThumbnailsRecord objects of clients who are still
-     * waiting to receive all of the thumbnails for a task.
-     */
-    final ArrayList<PendingThumbnailsRecord> mPendingThumbnails =
-            new ArrayList<PendingThumbnailsRecord>();
-
     final ProviderMap mProviderMap;
 
     /**
@@ -729,6 +723,8 @@
     private static final String TAG_URI_GRANTS = "uri-grants";
     private static final String TAG_URI_GRANT = "uri-grant";
     private static final String ATTR_USER_HANDLE = "userHandle";
+    private static final String ATTR_SOURCE_USER_ID = "sourceUserId";
+    private static final String ATTR_TARGET_USER_ID = "targetUserId";
     private static final String ATTR_SOURCE_PKG = "sourcePkg";
     private static final String ATTR_TARGET_PKG = "targetPkg";
     private static final String ATTR_URI = "uri";
@@ -746,10 +742,12 @@
             mGrantedUriPermissions = new SparseArray<ArrayMap<GrantUri, UriPermission>>();
 
     public static class GrantUri {
+        public final int sourceUserId;
         public final Uri uri;
-        public final boolean prefix;
+        public boolean prefix;
 
-        public GrantUri(Uri uri, boolean prefix) {
+        public GrantUri(int sourceUserId, Uri uri, boolean prefix) {
+            this.sourceUserId = sourceUserId;
             this.uri = uri;
             this.prefix = prefix;
         }
@@ -763,18 +761,28 @@
         public boolean equals(Object o) {
             if (o instanceof GrantUri) {
                 GrantUri other = (GrantUri) o;
-                return uri.equals(other.uri) && prefix == other.prefix;
+                return uri.equals(other.uri) && (sourceUserId == other.sourceUserId)
+                        && prefix == other.prefix;
             }
             return false;
         }
 
         @Override
         public String toString() {
-            if (prefix) {
-                return uri.toString() + " [prefix]";
-            } else {
-                return uri.toString();
-            }
+            String result = Integer.toString(sourceUserId) + " @ " + uri.toString();
+            if (prefix) result += " [prefix]";
+            return result;
+        }
+
+        public String toSafeString() {
+            String result = Integer.toString(sourceUserId) + " @ " + uri.toSafeString();
+            if (prefix) result += " [prefix]";
+            return result;
+        }
+
+        public static GrantUri resolve(int defaultSourceUserHandle, Uri uri) {
+            return new GrantUri(ContentProvider.getUserIdFromUri(uri, defaultSourceUserHandle),
+                    ContentProvider.getUriWithoutUserId(uri), false);
         }
     }
 
@@ -991,7 +999,7 @@
 
     /**
      * This is set if we had to do a delayed dexopt of an app before launching
-     * it, to increasing the ANR timeouts in that case.
+     * it, to increase the ANR timeouts in that case.
      */
     boolean mDidDexOpt;
 
@@ -1017,11 +1025,11 @@
 
     static class ProcessChangeItem {
         static final int CHANGE_ACTIVITIES = 1<<0;
-        static final int CHANGE_IMPORTANCE= 1<<1;
+        static final int CHANGE_PROCESS_STATE = 1<<1;
         int changes;
         int uid;
         int pid;
-        int importance;
+        int processState;
         boolean foregroundActivities;
     }
 
@@ -1331,15 +1339,15 @@
                 }
             } break;
             case UPDATE_HTTP_PROXY_MSG: {
-                ProxyProperties proxy = (ProxyProperties)msg.obj;
+                ProxyInfo proxy = (ProxyInfo)msg.obj;
                 String host = "";
                 String port = "";
                 String exclList = "";
-                String pacFileUrl = null;
+                Uri pacFileUrl = Uri.EMPTY;
                 if (proxy != null) {
                     host = proxy.getHost();
                     port = Integer.toString(proxy.getPort());
-                    exclList = proxy.getExclusionList();
+                    exclList = proxy.getExclusionListAsString();
                     pacFileUrl = proxy.getPacFileUrl();
                 }
                 synchronized (ActivityManagerService.this) {
@@ -1858,6 +1866,12 @@
 
         @Override
         public boolean onPackageChanged(String packageName, int uid, String[] components) {
+            onPackageModified(packageName);
+            return true;
+        }
+
+        @Override
+        public void onPackageModified(String packageName) {
             final PackageManager pm = mContext.getPackageManager();
             final ArrayList<Pair<Intent, Integer>> recentTaskIntents =
                     new ArrayList<Pair<Intent, Integer>>();
@@ -1893,7 +1907,6 @@
                     removeTaskByIdLocked(tasksToRemove.get(i), 0);
                 }
             }
-            return true;
         }
 
         @Override
@@ -3200,11 +3213,10 @@
                             observer.onForegroundActivitiesChanged(item.pid, item.uid,
                                     item.foregroundActivities);
                         }
-                        if ((item.changes&ProcessChangeItem.CHANGE_IMPORTANCE) != 0) {
-                            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "IMPORTANCE CHANGED pid="
-                                    + item.pid + " uid=" + item.uid + ": " + item.importance);
-                            observer.onImportanceChanged(item.pid, item.uid,
-                                    item.importance);
+                        if ((item.changes&ProcessChangeItem.CHANGE_PROCESS_STATE) != 0) {
+                            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "PROCSTATE CHANGED pid="
+                                    + item.pid + " uid=" + item.uid + ": " + item.processState);
+                            observer.onProcessStateChanged(item.pid, item.uid, item.processState);
                         }
                     }
                 } catch (RemoteException e) {
@@ -5431,43 +5443,36 @@
     }
 
     @Override
-    public final void activityPaused(IBinder token) {
+    public final void activityPaused(IBinder token, PersistableBundle persistentState) {
         final long origId = Binder.clearCallingIdentity();
         synchronized(this) {
             ActivityStack stack = ActivityRecord.getStackLocked(token);
             if (stack != null) {
-                stack.activityPausedLocked(token, false);
+                stack.activityPausedLocked(token, false, persistentState);
             }
         }
         Binder.restoreCallingIdentity(origId);
     }
 
     @Override
-    public final void activityStopped(IBinder token, Bundle icicle, Bitmap thumbnail,
-            CharSequence description) {
-        if (localLOGV) Slog.v(
-            TAG, "Activity stopped: token=" + token);
+    public final void activityStopped(IBinder token, Bundle icicle,
+            PersistableBundle persistentState, CharSequence description) {
+        if (localLOGV) Slog.v(TAG, "Activity stopped: token=" + token);
 
         // Refuse possible leaked file descriptors
         if (icicle != null && icicle.hasFileDescriptors()) {
             throw new IllegalArgumentException("File descriptors passed in Bundle");
         }
 
-        ActivityRecord r = null;
-
         final long origId = Binder.clearCallingIdentity();
 
         synchronized (this) {
-            r = ActivityRecord.isInStackLocked(token);
+            ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r != null) {
-                r.task.stack.activityStoppedLocked(r, icicle, thumbnail, description);
+                r.task.stack.activityStoppedLocked(r, icicle, persistentState, description);
             }
         }
 
-        if (r != null) {
-            sendPendingThumbnail(r, null, null, null, false);
-        }
-
         trimApplications();
 
         Binder.restoreCallingIdentity(origId);
@@ -6001,9 +6006,9 @@
      * in {@link ContentProvider}.
      */
     private final boolean checkHoldingPermissionsLocked(
-            IPackageManager pm, ProviderInfo pi, Uri uri, int uid, final int modeFlags) {
+            IPackageManager pm, ProviderInfo pi, GrantUri grantUri, int uid, final int modeFlags) {
         if (DEBUG_URI_PERMISSION) Slog.v(TAG,
-                "checkHoldingPermissionsLocked: uri=" + uri + " uid=" + uid);
+                "checkHoldingPermissionsLocked: uri=" + grantUri + " uid=" + uid);
 
         if (pi.applicationInfo.uid == uid) {
             return true;
@@ -6032,7 +6037,7 @@
             // check if target holds any <path-permission> that match uri
             final PathPermission[] pps = pi.pathPermissions;
             if (pps != null) {
-                final String path = uri.getPath();
+                final String path = grantUri.uri.getPath();
                 int i = pps.length;
                 while (i > 0 && (!readMet || !writeMet)) {
                     i--;
@@ -6097,32 +6102,33 @@
         return pi;
     }
 
-    private UriPermission findUriPermissionLocked(int targetUid, GrantUri uri) {
+    private UriPermission findUriPermissionLocked(int targetUid, GrantUri grantUri) {
         final ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
         if (targetUris != null) {
-            return targetUris.get(uri);
+            return targetUris.get(grantUri);
         }
         return null;
     }
 
     private UriPermission findOrCreateUriPermissionLocked(String sourcePkg,
-            String targetPkg, int targetUid, GrantUri uri) {
+            String targetPkg, int targetUid, GrantUri grantUri) {
         ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
         if (targetUris == null) {
             targetUris = Maps.newArrayMap();
             mGrantedUriPermissions.put(targetUid, targetUris);
         }
 
-        UriPermission perm = targetUris.get(uri);
+        UriPermission perm = targetUris.get(grantUri);
         if (perm == null) {
-            perm = new UriPermission(sourcePkg, targetPkg, targetUid, uri);
-            targetUris.put(uri, perm);
+            perm = new UriPermission(sourcePkg, targetPkg, targetUid, grantUri);
+            targetUris.put(grantUri, perm);
         }
 
         return perm;
     }
 
-    private final boolean checkUriPermissionLocked(Uri uri, int uid, final int modeFlags) {
+    private final boolean checkUriPermissionLocked(GrantUri grantUri, int uid,
+            final int modeFlags) {
         final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
         final int minStrength = persistable ? UriPermission.STRENGTH_PERSISTABLE
                 : UriPermission.STRENGTH_OWNED;
@@ -6136,7 +6142,7 @@
         if (perms == null) return false;
 
         // First look for exact match
-        final UriPermission exactPerm = perms.get(new GrantUri(uri, false));
+        final UriPermission exactPerm = perms.get(grantUri);
         if (exactPerm != null && exactPerm.getStrength(modeFlags) >= minStrength) {
             return true;
         }
@@ -6145,7 +6151,7 @@
         final int N = perms.size();
         for (int i = 0; i < N; i++) {
             final UriPermission perm = perms.valueAt(i);
-            if (perm.uri.prefix && uri.isPathPrefixMatch(perm.uri.uri)
+            if (perm.uri.prefix && grantUri.uri.isPathPrefixMatch(perm.uri.uri)
                     && perm.getStrength(modeFlags) >= minStrength) {
                 return true;
             }
@@ -6155,7 +6161,8 @@
     }
 
     @Override
-    public int checkUriPermission(Uri uri, int pid, int uid, final int modeFlags) {
+    public int checkUriPermission(Uri uri, int pid, int uid,
+            final int modeFlags, int userId) {
         enforceNotIsolatedCaller("checkUriPermission");
 
         // Another redirected-binder-call permissions check as in
@@ -6171,7 +6178,7 @@
             return PackageManager.PERMISSION_GRANTED;
         }
         synchronized (this) {
-            return checkUriPermissionLocked(uri, uid, modeFlags)
+            return checkUriPermissionLocked(new GrantUri(userId, uri, false), uid, modeFlags)
                     ? PackageManager.PERMISSION_GRANTED
                     : PackageManager.PERMISSION_DENIED;
         }
@@ -6186,30 +6193,31 @@
      * If you already know the uid of the target, you can supply it in
      * lastTargetUid else set that to -1.
      */
-    int checkGrantUriPermissionLocked(int callingUid, String targetPkg,
-            Uri uri, final int modeFlags, int lastTargetUid) {
+    int checkGrantUriPermissionLocked(int callingUid, String targetPkg, GrantUri grantUri,
+            final int modeFlags, int lastTargetUid) {
         if (!Intent.isAccessUriMode(modeFlags)) {
             return -1;
         }
 
         if (targetPkg != null) {
             if (DEBUG_URI_PERMISSION) Slog.v(TAG,
-                    "Checking grant " + targetPkg + " permission to " + uri);
+                    "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(uri.getScheme())) {
+        if (!ContentResolver.SCHEME_CONTENT.equals(grantUri.uri.getScheme())) {
             if (DEBUG_URI_PERMISSION) Slog.v(TAG, 
-                    "Can't grant URI permission for non-content URI: " + uri);
+                    "Can't grant URI permission for non-content URI: " + grantUri);
             return -1;
         }
 
-        final String authority = uri.getAuthority();
-        final ProviderInfo pi = getProviderInfoLocked(authority, UserHandle.getUserId(callingUid));
+        final String authority = grantUri.uri.getAuthority();
+        final ProviderInfo pi = getProviderInfoLocked(authority, grantUri.sourceUserId);
         if (pi == null) {
-            Slog.w(TAG, "No content provider found for permission check: " + uri.toSafeString());
+            Slog.w(TAG, "No content provider found for permission check: " +
+                    grantUri.uri.toSafeString());
             return -1;
         }
 
@@ -6229,10 +6237,10 @@
 
         if (targetUid >= 0) {
             // First...  does the target actually need this permission?
-            if (checkHoldingPermissionsLocked(pm, pi, uri, targetUid, modeFlags)) {
+            if (checkHoldingPermissionsLocked(pm, pi, grantUri, targetUid, modeFlags)) {
                 // No need to grant the target this permission.
                 if (DEBUG_URI_PERMISSION) Slog.v(TAG,
-                        "Target " + targetPkg + " already has full permission to " + uri);
+                        "Target " + targetPkg + " already has full permission to " + grantUri);
                 return -1;
             }
         } else {
@@ -6258,14 +6266,14 @@
             throw new SecurityException("Provider " + pi.packageName
                     + "/" + pi.name
                     + " does not allow granting of Uri permissions (uri "
-                    + uri + ")");
+                    + grantUri + ")");
         }
         if (pi.uriPermissionPatterns != null) {
             final int N = pi.uriPermissionPatterns.length;
             boolean allowed = false;
             for (int i=0; i<N; i++) {
                 if (pi.uriPermissionPatterns[i] != null
-                        && pi.uriPermissionPatterns[i].match(uri.getPath())) {
+                        && pi.uriPermissionPatterns[i].match(grantUri.uri.getPath())) {
                     allowed = true;
                     break;
                 }
@@ -6274,35 +6282,35 @@
                 throw new SecurityException("Provider " + pi.packageName
                         + "/" + pi.name
                         + " does not allow granting of permission to path of Uri "
-                        + uri);
+                        + grantUri);
             }
         }
 
         // Third...  does the caller itself have permission to access
         // this uri?
-        if (callingUid != Process.myUid()) {
-            if (!checkHoldingPermissionsLocked(pm, pi, uri, callingUid, modeFlags)) {
+        if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
+            if (!checkHoldingPermissionsLocked(pm, pi, grantUri, callingUid, modeFlags)) {
                 // Require they hold a strong enough Uri permission
-                if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
+                if (!checkUriPermissionLocked(grantUri, callingUid, modeFlags)) {
                     throw new SecurityException("Uid " + callingUid
-                            + " does not have permission to uri " + uri);
+                            + " does not have permission to uri " + grantUri);
                 }
             }
         }
-
         return targetUid;
     }
 
     @Override
-    public int checkGrantUriPermission(int callingUid, String targetPkg,
-            Uri uri, final int modeFlags) {
+    public int checkGrantUriPermission(int callingUid, String targetPkg, Uri uri,
+            final int modeFlags, int userId) {
         enforceNotIsolatedCaller("checkGrantUriPermission");
         synchronized(this) {
-            return checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags, -1);
+            return checkGrantUriPermissionLocked(callingUid, targetPkg,
+                    new GrantUri(userId, uri, false), modeFlags, -1);
         }
     }
 
-    void grantUriPermissionUncheckedLocked(int targetUid, String targetPkg, Uri uri,
+    void grantUriPermissionUncheckedLocked(int targetUid, String targetPkg, GrantUri grantUri,
             final int modeFlags, UriPermissionOwner owner) {
         if (!Intent.isAccessUriMode(modeFlags)) {
             return;
@@ -6313,36 +6321,40 @@
         // the target.
 
         if (DEBUG_URI_PERMISSION) Slog.v(TAG, 
-                "Granting " + targetPkg + "/" + targetUid + " permission to " + uri);
+                "Granting " + targetPkg + "/" + targetUid + " permission to " + grantUri);
 
-        final String authority = uri.getAuthority();
-        final ProviderInfo pi = getProviderInfoLocked(authority, UserHandle.getUserId(targetUid));
+        final String authority = grantUri.uri.getAuthority();
+        final ProviderInfo pi = getProviderInfoLocked(authority, grantUri.sourceUserId);
         if (pi == null) {
-            Slog.w(TAG, "No content provider found for grant: " + uri.toSafeString());
+            Slog.w(TAG, "No content provider found for grant: " + grantUri.toSafeString());
             return;
         }
 
-        final boolean prefix = (modeFlags & Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) != 0;
+        if ((modeFlags & Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) != 0) {
+            grantUri.prefix = true;
+        }
         final UriPermission perm = findOrCreateUriPermissionLocked(
-                pi.packageName, targetPkg, targetUid, new GrantUri(uri, prefix));
+                pi.packageName, targetPkg, targetUid, grantUri);
         perm.grantModes(modeFlags, owner);
     }
 
-    void grantUriPermissionLocked(int callingUid, String targetPkg, Uri uri,
+    void grantUriPermissionLocked(int callingUid, String targetPkg, GrantUri grantUri,
             final int modeFlags, UriPermissionOwner owner) {
         if (targetPkg == null) {
             throw new NullPointerException("targetPkg");
         }
 
-        int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags, -1);
+        int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, modeFlags,
+                -1);
         if (targetUid < 0) {
             return;
         }
 
-        grantUriPermissionUncheckedLocked(targetUid, targetPkg, uri, modeFlags, owner);
+        grantUriPermissionUncheckedLocked(targetUid, targetPkg, grantUri, modeFlags,
+                owner);
     }
 
-    static class NeededUriGrants extends ArrayList<Uri> {
+    static class NeededUriGrants extends ArrayList<GrantUri> {
         final String targetPkg;
         final int targetUid;
         final int flags;
@@ -6379,13 +6391,14 @@
         }
 
         if (data != null) {
-            int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, data,
-                mode, needed != null ? needed.targetUid : -1);
+            GrantUri grantUri = GrantUri.resolve(UserHandle.getUserId(callingUid), data);
+            int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, mode,
+                    needed != null ? needed.targetUid : -1);
             if (targetUid > 0) {
                 if (needed == null) {
                     needed = new NeededUriGrants(targetPkg, targetUid, mode);
                 }
-                needed.add(data);
+                needed.add(grantUri);
             }
         }
         if (clip != null) {
@@ -6393,13 +6406,14 @@
                 Uri uri = clip.getItemAt(i).getUri();
                 if (uri != null) {
                     int targetUid = -1;
-                    targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, uri,
-                            mode, needed != null ? needed.targetUid : -1);
+                    GrantUri grantUri = GrantUri.resolve(UserHandle.getUserId(callingUid), uri);
+                    targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, mode,
+                            needed != null ? needed.targetUid : -1);
                     if (targetUid > 0) {
                         if (needed == null) {
                             needed = new NeededUriGrants(targetPkg, targetUid, mode);
                         }
-                        needed.add(uri);
+                        needed.add(grantUri);
                     }
                 } else {
                     Intent clipIntent = clip.getItemAt(i).getIntent();
@@ -6424,8 +6438,9 @@
             UriPermissionOwner owner) {
         if (needed != null) {
             for (int i=0; i<needed.size(); i++) {
+                GrantUri grantUri = needed.get(i);
                 grantUriPermissionUncheckedLocked(needed.targetUid, needed.targetPkg,
-                        needed.get(i), needed.flags, owner);
+                        grantUri, needed.flags, owner);
             }
         }
     }
@@ -6442,20 +6457,21 @@
     }
 
     @Override
-    public void grantUriPermission(IApplicationThread caller, String targetPkg,
-            Uri uri, final int modeFlags) {
+    public void grantUriPermission(IApplicationThread caller, String targetPkg, Uri uri,
+            final int modeFlags, int userId) {
         enforceNotIsolatedCaller("grantUriPermission");
+        GrantUri grantUri = new GrantUri(userId, uri, false);
         synchronized(this) {
             final ProcessRecord r = getRecordForAppLocked(caller);
             if (r == null) {
                 throw new SecurityException("Unable to find app for caller "
                         + caller
-                        + " when granting permission to uri " + uri);
+                        + " when granting permission to uri " + grantUri);
             }
             if (targetPkg == null) {
                 throw new IllegalArgumentException("null target");
             }
-            if (uri == null) {
+            if (grantUri == null) {
                 throw new IllegalArgumentException("null uri");
             }
 
@@ -6464,7 +6480,7 @@
                     | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
                     | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
 
-            grantUriPermissionLocked(r.uid, targetPkg, uri, modeFlags, null);
+            grantUriPermissionLocked(r.uid, targetPkg, grantUri, modeFlags, null);
         }
     }
 
@@ -6484,24 +6500,25 @@
         }
     }
 
-    private void revokeUriPermissionLocked(int callingUid, Uri uri, final int modeFlags) {
-        if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Revoking all granted permissions to " + uri);
+    private void revokeUriPermissionLocked(int callingUid, GrantUri grantUri, final int modeFlags) {
+        if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Revoking all granted permissions to " + grantUri);
 
         final IPackageManager pm = AppGlobals.getPackageManager();
-        final String authority = uri.getAuthority();
-        final ProviderInfo pi = getProviderInfoLocked(authority, UserHandle.getUserId(callingUid));
+        final String authority = grantUri.uri.getAuthority();
+        final ProviderInfo pi = getProviderInfoLocked(authority, grantUri.sourceUserId);
         if (pi == null) {
-            Slog.w(TAG, "No content provider found for permission revoke: " + uri.toSafeString());
+            Slog.w(TAG, "No content provider found for permission revoke: "
+                    + grantUri.toSafeString());
             return;
         }
 
         // Does the caller have this permission on the URI?
-        if (!checkHoldingPermissionsLocked(pm, pi, uri, callingUid, modeFlags)) {
+        if (!checkHoldingPermissionsLocked(pm, pi, grantUri, callingUid, modeFlags)) {
             // Right now, if you are not the original owner of the permission,
             // you are not allowed to revoke it.
             //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
                 throw new SecurityException("Uid " + callingUid
-                        + " does not have permission to uri " + uri);
+                        + " does not have permission to uri " + grantUri);
             //}
         }
 
@@ -6515,7 +6532,8 @@
 
             for (Iterator<UriPermission> it = perms.values().iterator(); it.hasNext();) {
                 final UriPermission perm = it.next();
-                if (perm.uri.uri.isPathPrefixMatch(uri)) {
+                if (perm.uri.sourceUserId == grantUri.sourceUserId
+                        && perm.uri.uri.isPathPrefixMatch(grantUri.uri)) {
                     if (DEBUG_URI_PERMISSION)
                         Slog.v(TAG,
                                 "Revoking " + perm.targetUid + " permission to " + perm.uri);
@@ -6540,8 +6558,8 @@
     }
 
     @Override
-    public void revokeUriPermission(IApplicationThread caller, Uri uri,
-            final int modeFlags) {
+    public void revokeUriPermission(IApplicationThread caller, Uri uri, final int modeFlags,
+            int userId) {
         enforceNotIsolatedCaller("revokeUriPermission");
         synchronized(this) {
             final ProcessRecord r = getRecordForAppLocked(caller);
@@ -6561,14 +6579,14 @@
 
             final IPackageManager pm = AppGlobals.getPackageManager();
             final String authority = uri.getAuthority();
-            final ProviderInfo pi = getProviderInfoLocked(authority, r.userId);
+            final ProviderInfo pi = getProviderInfoLocked(authority, userId);
             if (pi == null) {
                 Slog.w(TAG, "No content provider found for permission revoke: "
                         + uri.toSafeString());
                 return;
             }
 
-            revokeUriPermissionLocked(r.uid, uri, modeFlags);
+            revokeUriPermissionLocked(r.uid, new GrantUri(userId, uri, false), modeFlags);
         }
     }
 
@@ -6638,8 +6656,8 @@
     }
 
     @Override
-    public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg,
-            Uri uri, final int modeFlags) {
+    public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg, Uri uri,
+            final int modeFlags, int userId) {
         synchronized(this) {
             UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
             if (owner == null) {
@@ -6659,12 +6677,13 @@
                 throw new IllegalArgumentException("null uri");
             }
 
-            grantUriPermissionLocked(fromUid, targetPkg, uri, modeFlags, owner);
+            grantUriPermissionLocked(fromUid, targetPkg, new GrantUri(userId, uri, false),
+                    modeFlags, owner);
         }
     }
 
     @Override
-    public void revokeUriPermissionFromOwner(IBinder token, Uri uri, int mode) {
+    public void revokeUriPermissionFromOwner(IBinder token, Uri uri, int mode, int userId) {
         synchronized(this) {
             UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
             if (owner == null) {
@@ -6674,7 +6693,7 @@
             if (uri == null) {
                 owner.removeUriPermissionsLocked(mode);
             } else {
-                owner.removeUriPermissionLocked(uri, mode);
+                owner.removeUriPermissionLocked(new GrantUri(userId, uri, false), mode);
             }
         }
     }
@@ -6713,7 +6732,8 @@
             out.startTag(null, TAG_URI_GRANTS);
             for (UriPermission.Snapshot perm : persist) {
                 out.startTag(null, TAG_URI_GRANT);
-                writeIntAttribute(out, ATTR_USER_HANDLE, perm.userHandle);
+                writeIntAttribute(out, ATTR_SOURCE_USER_ID, perm.uri.sourceUserId);
+                writeIntAttribute(out, ATTR_TARGET_USER_ID, perm.targetUserId);
                 out.attribute(null, ATTR_SOURCE_PKG, perm.sourcePkg);
                 out.attribute(null, ATTR_TARGET_PKG, perm.targetPkg);
                 out.attribute(null, ATTR_URI, String.valueOf(perm.uri.uri));
@@ -6749,7 +6769,18 @@
                 final String tag = in.getName();
                 if (type == START_TAG) {
                     if (TAG_URI_GRANT.equals(tag)) {
-                        final int userHandle = readIntAttribute(in, ATTR_USER_HANDLE);
+                        final int sourceUserId;
+                        final int targetUserId;
+                        final int userHandle = readIntAttribute(in,
+                                ATTR_USER_HANDLE, UserHandle.USER_NULL);
+                        if (userHandle != UserHandle.USER_NULL) {
+                            // For backwards compatibility.
+                            sourceUserId = userHandle;
+                            targetUserId = userHandle;
+                        } else {
+                            sourceUserId = readIntAttribute(in, ATTR_SOURCE_USER_ID);
+                            targetUserId = readIntAttribute(in, ATTR_TARGET_USER_ID);
+                        }
                         final String sourcePkg = in.getAttributeValue(null, ATTR_SOURCE_PKG);
                         final String targetPkg = in.getAttributeValue(null, ATTR_TARGET_PKG);
                         final Uri uri = Uri.parse(in.getAttributeValue(null, ATTR_URI));
@@ -6759,17 +6790,18 @@
 
                         // Sanity check that provider still belongs to source package
                         final ProviderInfo pi = getProviderInfoLocked(
-                                uri.getAuthority(), userHandle);
+                                uri.getAuthority(), sourceUserId);
                         if (pi != null && sourcePkg.equals(pi.packageName)) {
                             int targetUid = -1;
                             try {
                                 targetUid = AppGlobals.getPackageManager()
-                                        .getPackageUid(targetPkg, userHandle);
+                                        .getPackageUid(targetPkg, targetUserId);
                             } catch (RemoteException e) {
                             }
                             if (targetUid != -1) {
                                 final UriPermission perm = findOrCreateUriPermissionLocked(
-                                        sourcePkg, targetPkg, targetUid, new GrantUri(uri, prefix));
+                                        sourcePkg, targetPkg, targetUid,
+                                        new GrantUri(sourceUserId, uri, prefix));
                                 perm.initPersistedModes(modeFlags, createdTime);
                             }
                         } else {
@@ -6791,7 +6823,7 @@
     }
 
     @Override
-    public void takePersistableUriPermission(Uri uri, final int modeFlags) {
+    public void takePersistableUriPermission(Uri uri, final int modeFlags, int userId) {
         enforceNotIsolatedCaller("takePersistableUriPermission");
 
         Preconditions.checkFlagsArgument(modeFlags,
@@ -6800,9 +6832,12 @@
         synchronized (this) {
             final int callingUid = Binder.getCallingUid();
             boolean persistChanged = false;
+            GrantUri grantUri = new GrantUri(userId, uri, false);
 
-            UriPermission exactPerm = findUriPermissionLocked(callingUid, new GrantUri(uri, false));
-            UriPermission prefixPerm = findUriPermissionLocked(callingUid, new GrantUri(uri, true));
+            UriPermission exactPerm = findUriPermissionLocked(callingUid,
+                    new GrantUri(userId, uri, false));
+            UriPermission prefixPerm = findUriPermissionLocked(callingUid,
+                    new GrantUri(userId, uri, true));
 
             final boolean exactValid = (exactPerm != null)
                     && ((modeFlags & exactPerm.persistableModeFlags) == modeFlags);
@@ -6811,7 +6846,7 @@
 
             if (!(exactValid || prefixValid)) {
                 throw new SecurityException("No persistable permission grants found for UID "
-                        + callingUid + " and Uri " + uri.toSafeString());
+                        + callingUid + " and Uri " + grantUri.toSafeString());
             }
 
             if (exactValid) {
@@ -6830,7 +6865,7 @@
     }
 
     @Override
-    public void releasePersistableUriPermission(Uri uri, final int modeFlags) {
+    public void releasePersistableUriPermission(Uri uri, final int modeFlags, int userId) {
         enforceNotIsolatedCaller("releasePersistableUriPermission");
 
         Preconditions.checkFlagsArgument(modeFlags,
@@ -6840,8 +6875,10 @@
             final int callingUid = Binder.getCallingUid();
             boolean persistChanged = false;
 
-            UriPermission exactPerm = findUriPermissionLocked(callingUid, new GrantUri(uri, false));
-            UriPermission prefixPerm = findUriPermissionLocked(callingUid, new GrantUri(uri, true));
+            UriPermission exactPerm = findUriPermissionLocked(callingUid,
+                    new GrantUri(userId, uri, false));
+            UriPermission prefixPerm = findUriPermissionLocked(callingUid,
+                    new GrantUri(userId, uri, true));
             if (exactPerm == null && prefixPerm == null) {
                 throw new SecurityException("No permission grants found for UID " + callingUid
                         + " and Uri " + uri.toSafeString());
@@ -6983,66 +7020,51 @@
     // =========================================================
 
     @Override
-    public List<RunningTaskInfo> getTasks(int maxNum, int flags,
-                         IThumbnailReceiver receiver) {
-        ArrayList<RunningTaskInfo> list = new ArrayList<RunningTaskInfo>();
+    public List<IAppTask> getAppTasks() {
+        int callingUid = Binder.getCallingUid();
+        long ident = Binder.clearCallingIdentity();
+        synchronized(this) {
+            ArrayList<IAppTask> list = new ArrayList<IAppTask>();
+            try {
+                if (localLOGV) Slog.v(TAG, "getAppTasks");
 
-        PendingThumbnailsRecord pending = new PendingThumbnailsRecord(receiver);
-        ActivityRecord topRecord = null;
+                final int N = mRecentTasks.size();
+                for (int i = 0; i < N; i++) {
+                    TaskRecord tr = mRecentTasks.get(i);
+                    // Skip tasks that are not created by the caller
+                    if (tr.creatorUid == callingUid) {
+                        ActivityManager.RecentTaskInfo taskInfo =
+                                createRecentTaskInfoFromTaskRecord(tr);
+                        AppTaskImpl taskImpl = new AppTaskImpl(taskInfo.persistentId, callingUid);
+                        list.add(taskImpl);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+            return list;
+        }
+    }
+
+    @Override
+    public List<RunningTaskInfo> getTasks(int maxNum, int flags) {
+        final int callingUid = Binder.getCallingUid();
+        ArrayList<RunningTaskInfo> list = new ArrayList<RunningTaskInfo>();
 
         synchronized(this) {
             if (localLOGV) Slog.v(
-                TAG, "getTasks: max=" + maxNum + ", flags=" + flags
-                + ", receiver=" + receiver);
+                TAG, "getTasks: max=" + maxNum + ", flags=" + flags);
 
-            if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
-                    != PackageManager.PERMISSION_GRANTED) {
-                if (receiver != null) {
-                    // If the caller wants to wait for pending thumbnails,
-                    // it ain't gonna get them.
-                    try {
-                        receiver.finished();
-                    } catch (RemoteException ex) {
-                    }
-                }
-                String msg = "Permission Denial: getTasks() from pid="
-                        + Binder.getCallingPid()
-                        + ", uid=" + Binder.getCallingUid()
-                        + " requires " + android.Manifest.permission.GET_TASKS;
-                Slog.w(TAG, msg);
-                throw new SecurityException(msg);
+            final boolean allowed = checkCallingPermission(
+                    android.Manifest.permission.GET_TASKS)
+                    == PackageManager.PERMISSION_GRANTED;
+            if (!allowed) {
+                Slog.w(TAG, "getTasks: caller " + callingUid
+                        + " does not hold GET_TASKS; limiting output");
             }
 
             // TODO: Improve with MRU list from all ActivityStacks.
-            topRecord = mStackSupervisor.getTasksLocked(maxNum, receiver, pending, list);
-
-            if (!pending.pendingRecords.isEmpty()) {
-                mPendingThumbnails.add(pending);
-            }
-        }
-
-        if (localLOGV) Slog.v(TAG, "We have pending thumbnails: " + pending);
-
-        if (topRecord != null) {
-            if (localLOGV) Slog.v(TAG, "Requesting top thumbnail");
-            try {
-                IApplicationThread topThumbnail = topRecord.app.thread;
-                topThumbnail.requestThumbnail(topRecord.appToken);
-            } catch (Exception e) {
-                Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
-                sendPendingThumbnail(null, topRecord.appToken, null, null, true);
-            }
-        }
-
-        if (pending.pendingRecords.isEmpty() && receiver != null) {
-            // In this case all thumbnails were available and the client
-            // is being asked to be told when the remaining ones come in...
-            // which is unusually, since the top-most currently running
-            // activity should never have a canned thumbnail!  Oh well.
-            try {
-                receiver.finished();
-            } catch (RemoteException ex) {
-            }
+            mStackSupervisor.getTasksLocked(maxNum, list, callingUid, allowed);
         }
 
         return list;
@@ -7052,15 +7074,81 @@
         return mRecentTasks.get(0);
     }
 
+    /**
+     * Creates a new RecentTaskInfo from a TaskRecord.
+     */
+    private ActivityManager.RecentTaskInfo createRecentTaskInfoFromTaskRecord(TaskRecord tr) {
+        ActivityManager.RecentTaskInfo rti
+                = new ActivityManager.RecentTaskInfo();
+        rti.id = tr.numActivities > 0 ? tr.taskId : -1;
+        rti.persistentId = tr.taskId;
+        rti.baseIntent = new Intent(tr.getBaseIntent());
+        rti.origActivity = tr.origActivity;
+        rti.description = tr.lastDescription;
+        rti.stackId = tr.stack.mStackId;
+        rti.userId = tr.userId;
+
+        // Traverse upwards looking for any break between main task activities and
+        // utility activities.
+        final ArrayList<ActivityRecord> activities = tr.mActivities;
+        int activityNdx;
+        final int numActivities = activities.size();
+        for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
+             ++activityNdx) {
+            final ActivityRecord r = activities.get(activityNdx);
+            if (r.intent != null &&
+                    (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
+                            != 0) {
+                break;
+            }
+        }
+        if (activityNdx > 0) {
+            // Traverse downwards starting below break looking for set label, icon.
+            // Note that if there are activities in the task but none of them set the
+            // recent activity values, then we do not fall back to the last set
+            // values in the TaskRecord.
+            rti.activityValues = new ActivityManager.RecentsActivityValues();
+            for (--activityNdx; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                if (r.activityValues != null) {
+                    if (rti.activityValues.label == null) {
+                        rti.activityValues.label = r.activityValues.label;
+                        tr.lastActivityValues.label = r.activityValues.label;
+                    }
+                    if (rti.activityValues.icon == null) {
+                        rti.activityValues.icon = r.activityValues.icon;
+                        tr.lastActivityValues.icon = r.activityValues.icon;
+                    }
+                    if (rti.activityValues.colorPrimary == 0) {
+                        rti.activityValues.colorPrimary = r.activityValues.colorPrimary;
+                        tr.lastActivityValues.colorPrimary = r.activityValues.colorPrimary;
+                    }
+                }
+            }
+        } else {
+            // If there are no activity records in this task, then we use the last
+            // resolved values
+            rti.activityValues =
+                    new ActivityManager.RecentsActivityValues(tr.lastActivityValues);
+        }
+        return rti;
+    }
+
     @Override
     public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
             int flags, int userId) {
-        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
+        final int callingUid = Binder.getCallingUid();
+        userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
                 false, true, "getRecentTasks", null);
 
         synchronized (this) {
-            enforceCallingPermission(android.Manifest.permission.GET_TASKS,
-                    "getRecentTasks()");
+            final boolean allowed = checkCallingPermission(
+                    android.Manifest.permission.GET_TASKS)
+                    == PackageManager.PERMISSION_GRANTED;
+            if (!allowed) {
+                Slog.w(TAG, "getRecentTasks: caller " + callingUid
+                        + " does not hold GET_TASKS; limiting output");
+            }
             final boolean detailed = checkCallingPermission(
                     android.Manifest.permission.GET_DETAILED_TASKS)
                     == PackageManager.PERMISSION_GRANTED;
@@ -7095,43 +7183,18 @@
                         || (tr.intent == null)
                         || ((tr.intent.getFlags()
                                 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
-                    ActivityManager.RecentTaskInfo rti
-                            = new ActivityManager.RecentTaskInfo();
-                    rti.id = tr.numActivities > 0 ? tr.taskId : -1;
-                    rti.persistentId = tr.taskId;
-                    rti.baseIntent = new Intent(
-                            tr.intent != null ? tr.intent : tr.affinityIntent);
+                    if (!allowed) {
+                        // If the caller doesn't have the GET_TASKS permission, then only
+                        // allow them to see a small subset of tasks -- their own and home.
+                        if (!tr.isHomeTask() && tr.creatorUid != callingUid) {
+                            continue;
+                        }
+                    }
+
+                    ActivityManager.RecentTaskInfo rti = createRecentTaskInfoFromTaskRecord(tr);
                     if (!detailed) {
                         rti.baseIntent.replaceExtras((Bundle)null);
                     }
-                    rti.origActivity = tr.origActivity;
-                    rti.description = tr.lastDescription;
-                    rti.stackId = tr.stack.mStackId;
-                    rti.userId = tr.userId;
-
-                    // Traverse upwards looking for any break between main task activities and
-                    // utility activities.
-                    final ArrayList<ActivityRecord> activities = tr.mActivities;
-                    int activityNdx;
-                    final int numActivities = activities.size();
-                    for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
-                            ++activityNdx) {
-                        final ActivityRecord r = activities.get(activityNdx);
-                        if (r.intent != null &&
-                                (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
-                                        != 0) {
-                            break;
-                        }
-                    }
-                    // Traverse downwards starting below break looking for set label and icon.
-                    for (--activityNdx; activityNdx >= 0; --activityNdx) {
-                        final ActivityRecord r = activities.get(activityNdx);
-                        if (r.activityLabel != null || r.activityIcon != null) {
-                            rti.activityLabel = r.activityLabel;
-                            rti.activityIcon = r.activityIcon;
-                            break;
-                        }
-                    }
 
                     if ((flags&ActivityManager.RECENT_IGNORE_UNAVAILABLE) != 0) {
                         // Check whether this activity is currently available.
@@ -7198,13 +7261,11 @@
     }
 
     @Override
-    public void setActivityLabelAndIcon(IBinder token, CharSequence activityLabel,
-            Bitmap activityIcon) {
+    public void setRecentsActivityValues(IBinder token, ActivityManager.RecentsActivityValues rav) {
         synchronized (this) {
             ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r != null) {
-                r.activityLabel = activityLabel.toString();
-                r.activityIcon = activityIcon;
+                r.activityValues = rav;
             }
         }
     }
@@ -7636,82 +7697,6 @@
     }
 
     // =========================================================
-    // THUMBNAILS
-    // =========================================================
-
-    public void reportThumbnail(IBinder token,
-            Bitmap thumbnail, CharSequence description) {
-        //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
-        final long origId = Binder.clearCallingIdentity();
-        sendPendingThumbnail(null, token, thumbnail, description, true);
-        Binder.restoreCallingIdentity(origId);
-    }
-
-    final void sendPendingThumbnail(ActivityRecord r, IBinder token,
-            Bitmap thumbnail, CharSequence description, boolean always) {
-        TaskRecord task;
-        ArrayList<PendingThumbnailsRecord> receivers = null;
-
-        //System.out.println("Send pending thumbnail: " + r);
-
-        synchronized(this) {
-            if (r == null) {
-                r = ActivityRecord.isInStackLocked(token);
-                if (r == null) {
-                    return;
-                }
-            }
-            if (thumbnail == null && r.thumbHolder != null) {
-                thumbnail = r.thumbHolder.lastThumbnail;
-                description = r.thumbHolder.lastDescription;
-            }
-            if (thumbnail == null && !always) {
-                // If there is no thumbnail, and this entry is not actually
-                // going away, then abort for now and pick up the next
-                // thumbnail we get.
-                return;
-            }
-            task = r.task;
-
-            int N = mPendingThumbnails.size();
-            int i=0;
-            while (i<N) {
-                PendingThumbnailsRecord pr = mPendingThumbnails.get(i);
-                //System.out.println("Looking in " + pr.pendingRecords);
-                if (pr.pendingRecords.remove(r)) {
-                    if (receivers == null) {
-                        receivers = new ArrayList<PendingThumbnailsRecord>();
-                    }
-                    receivers.add(pr);
-                    if (pr.pendingRecords.size() == 0) {
-                        pr.finished = true;
-                        mPendingThumbnails.remove(i);
-                        N--;
-                        continue;
-                    }
-                }
-                i++;
-            }
-        }
-
-        if (receivers != null) {
-            final int N = receivers.size();
-            for (int i=0; i<N; i++) {
-                try {
-                    PendingThumbnailsRecord pr = receivers.get(i);
-                    pr.receiver.newThumbnail(
-                        task != null ? task.taskId : -1, thumbnail, description);
-                    if (pr.finished) {
-                        pr.receiver.finished();
-                    }
-                } catch (Exception e) {
-                    Slog.w(TAG, "Exception thrown when sending thumbnail", e);
-                }
-            }
-        }
-    }
-
-    // =========================================================
     // CONTENT PROVIDERS
     // =========================================================
 
@@ -7773,9 +7758,25 @@
      * in {@link ContentProvider}.
      */
     private final String checkContentProviderPermissionLocked(
-            ProviderInfo cpi, ProcessRecord r) {
+            ProviderInfo cpi, ProcessRecord r, int userId) {
         final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
         final int callingUid = (r != null) ? r.uid : Binder.getCallingUid();
+        final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
+        // Looking for cross-user grants before to enforce the typical cross-users permissions
+        if (userId != UserHandle.getUserId(callingUid)) {
+            if (perms != null) {
+                for (GrantUri grantUri : perms.keySet()) {
+                    if (grantUri.sourceUserId == userId) {
+                        String authority = grantUri.uri.getAuthority();
+                        if (authority.equals(cpi.authority)) {
+                            return null;
+                        }
+                    }
+                }
+            }
+        }
+        userId = handleIncomingUser(callingPid, callingUid, userId,
+                false, true, "checkContentProviderPermissionLocked", null);
         if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
                 cpi.applicationInfo.uid, cpi.exported)
                 == PackageManager.PERMISSION_GRANTED) {
@@ -7806,10 +7807,9 @@
             }
         }
 
-        final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
         if (perms != null) {
-            for (GrantUri uri : perms.keySet()) {
-                if (uri.uri.getAuthority().equals(cpi.authority)) {
+            for (GrantUri grantUri : perms.keySet()) {
+                if (grantUri.uri.getAuthority().equals(cpi.authority)) {
                     return null;
                 }
             }
@@ -7917,7 +7917,7 @@
             if (providerRunning) {
                 cpi = cpr.info;
                 String msg;
-                if ((msg=checkContentProviderPermissionLocked(cpi, r)) != null) {
+                if ((msg=checkContentProviderPermissionLocked(cpi, r, userId)) != null) {
                     throw new SecurityException(msg);
                 }
 
@@ -8005,7 +8005,7 @@
                 cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
 
                 String msg;
-                if ((msg=checkContentProviderPermissionLocked(cpi, r)) != null) {
+                if ((msg=checkContentProviderPermissionLocked(cpi, r, userId)) != null) {
                     throw new SecurityException(msg);
                 }
 
@@ -8171,6 +8171,7 @@
         return cpr != null ? cpr.newHolder(conn) : null;
     }
 
+    @Override
     public final ContentProviderHolder getContentProvider(
             IApplicationThread caller, String name, int userId, boolean stable) {
         enforceNotIsolatedCaller("getContentProvider");
@@ -8180,9 +8181,8 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
-
-        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
-                false, true, "getContentProvider", null);
+        // The incoming user check is now handled in checkContentProviderPermissionLocked() to deal
+        // with cross-user grant.
         return getContentProviderImpl(caller, name, null, stable, userId);
     }
 
@@ -9123,7 +9123,7 @@
     }
 
     @Override
-    public boolean convertToTranslucent(IBinder token) {
+    public boolean convertToTranslucent(IBinder token, ActivityOptions options) {
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
@@ -9132,7 +9132,7 @@
                     return false;
                 }
                 if (r.changeWindowTranslucency(false)) {
-                    r.task.stack.convertToTranslucent(r);
+                    r.task.stack.convertToTranslucent(r, options);
                     mWindowManager.setAppFullscreen(token, false);
                     mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
                     return true;
@@ -9145,6 +9145,24 @@
     }
 
     @Override
+    public ActivityOptions getActivityOptions(IBinder token) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r != null) {
+                    final ActivityOptions activityOptions = r.pendingOptions;
+                    r.pendingOptions = null;
+                    return activityOptions;
+                }
+                return null;
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
     public void setImmersive(IBinder token, boolean immersive) {
         synchronized(this) {
             final ActivityRecord r = ActivityRecord.isInStackLocked(token);
@@ -9667,6 +9685,7 @@
             }
 
             mAppOpsService.systemReady();
+            mUsageStatsService.systemReady();
             mSystemReady = true;
         }
 
@@ -10635,6 +10654,7 @@
         int adj = app.curAdj;
         outInfo.importance = oomAdjToImportance(adj, outInfo);
         outInfo.importanceReasonCode = app.adjTypeCode;
+        outInfo.processState = app.curProcState;
     }
 
     public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
@@ -13859,7 +13879,7 @@
         }
 
         if (Proxy.PROXY_CHANGE_ACTION.equals(intent.getAction())) {
-            ProxyProperties proxy = intent.getParcelableExtra("proxy");
+            ProxyInfo proxy = intent.getParcelableExtra("proxy");
             mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy));
         }
 
@@ -14487,6 +14507,7 @@
                 newConfig.seq = mConfigurationSeq;
                 mConfiguration = newConfig;
                 Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + newConfig);
+                mUsageStatsService.noteStartConfig(newConfig);
 
                 final Configuration configCopy = new Configuration(mConfiguration);
                 
@@ -14690,7 +14711,7 @@
             app.keeping = true;
             app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
             app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT;
-            // System process can do UI, and when they do we want to have
+            // System processes can do UI, and when they do we want to have
             // them trim their memory after the user leaves the UI.  To
             // facilitate this, here we need to determine whether or not it
             // is currently showing UI.
@@ -15305,89 +15326,10 @@
         // it when computing the final cached adj later.  Note that we don't need to
         // worry about this for max adj above, since max adj will always be used to
         // keep it out of the cached vaues.
-        adj = app.modifyRawOomAdj(adj);
-
+        app.curAdj = app.modifyRawOomAdj(adj);
+        app.curSchedGroup = schedGroup;
         app.curProcState = procState;
-
-        int importance = app.memImportance;
-        if (importance == 0 || adj != app.curAdj || schedGroup != app.curSchedGroup) {
-            app.curAdj = adj;
-            app.curSchedGroup = schedGroup;
-            if (!interesting) {
-                // For this reporting, if there is not something explicitly
-                // interesting in this process then we will push it to the
-                // background importance.
-                importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
-            } else if (adj >= ProcessList.CACHED_APP_MIN_ADJ) {
-                importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
-            } else if (adj >= ProcessList.SERVICE_B_ADJ) {
-                importance =  ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
-            } else if (adj >= ProcessList.HOME_APP_ADJ) {
-                importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
-            } else if (adj >= ProcessList.SERVICE_ADJ) {
-                importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
-            } else if (adj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
-                importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE;
-            } else if (adj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
-                importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE;
-            } else if (adj >= ProcessList.VISIBLE_APP_ADJ) {
-                importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
-            } else if (adj >= ProcessList.FOREGROUND_APP_ADJ) {
-                importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
-            } else {
-                importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERSISTENT;
-            }
-        }
-
-        int changes = importance != app.memImportance ? ProcessChangeItem.CHANGE_IMPORTANCE : 0;
-        if (foregroundActivities != app.foregroundActivities) {
-            changes |= ProcessChangeItem.CHANGE_ACTIVITIES;
-        }
-        if (changes != 0) {
-            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Changes in " + app + ": " + changes);
-            app.memImportance = importance;
-            app.foregroundActivities = foregroundActivities;
-            int i = mPendingProcessChanges.size()-1;
-            ProcessChangeItem item = null;
-            while (i >= 0) {
-                item = mPendingProcessChanges.get(i);
-                if (item.pid == app.pid) {
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Re-using existing item: " + item);
-                    break;
-                }
-                i--;
-            }
-            if (i < 0) {
-                // No existing item in pending changes; need a new one.
-                final int NA = mAvailProcessChanges.size();
-                if (NA > 0) {
-                    item = mAvailProcessChanges.remove(NA-1);
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Retreiving available item: " + item);
-                } else {
-                    item = new ProcessChangeItem();
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Allocating new item: " + item);
-                }
-                item.changes = 0;
-                item.pid = app.pid;
-                item.uid = app.info.uid;
-                if (mPendingProcessChanges.size() == 0) {
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG,
-                            "*** Enqueueing dispatch processes changed!");
-                    mHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED).sendToTarget();
-                }
-                mPendingProcessChanges.add(item);
-            }
-            item.changes |= changes;
-            item.importance = importance;
-            item.foregroundActivities = foregroundActivities;
-            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Item "
-                    + Integer.toHexString(System.identityHashCode(item))
-                    + " " + app.toShortString() + ": changes=" + item.changes
-                    + " importance=" + item.importance
-                    + " foreground=" + item.foregroundActivities
-                    + " type=" + app.adjType + " source=" + app.adjSource
-                    + " target=" + app.adjTarget);
-        }
+        app.foregroundActivities = foregroundActivities;
 
         return app.curRawAdj;
     }
@@ -15660,7 +15602,7 @@
     }
 
     private final boolean applyOomAdjLocked(ProcessRecord app, boolean wasKeeping,
-            ProcessRecord TOP_APP, boolean doingAll, boolean reportingProcessState, long now) {
+            ProcessRecord TOP_APP, boolean doingAll, long now) {
         boolean success = true;
 
         if (app.curRawAdj != app.setRawAdj) {
@@ -15679,6 +15621,8 @@
             app.setRawAdj = app.curRawAdj;
         }
 
+        int changes = 0;
+
         if (app.curAdj != app.setAdj) {
             ProcessList.setOomAdj(app.pid, app.curAdj);
             if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
@@ -15720,9 +15664,14 @@
                         app.curSchedGroup <= Process.THREAD_GROUP_BG_NONINTERACTIVE);
             }
         }
+        if (app.repForegroundActivities != app.foregroundActivities) {
+            app.repForegroundActivities = app.foregroundActivities;
+            changes |= ProcessChangeItem.CHANGE_ACTIVITIES;
+        }
         if (app.repProcState != app.curProcState) {
             app.repProcState = app.curProcState;
-            if (!reportingProcessState && app.thread != null) {
+            changes |= ProcessChangeItem.CHANGE_PROCESS_STATE;
+            if (app.thread != null) {
                 try {
                     if (false) {
                         //RuntimeException h = new RuntimeException("here");
@@ -15767,6 +15716,51 @@
                 app.procStateChanged = true;
             }
         }
+
+        if (changes != 0) {
+            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Changes in " + app + ": " + changes);
+            int i = mPendingProcessChanges.size()-1;
+            ProcessChangeItem item = null;
+            while (i >= 0) {
+                item = mPendingProcessChanges.get(i);
+                if (item.pid == app.pid) {
+                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Re-using existing item: " + item);
+                    break;
+                }
+                i--;
+            }
+            if (i < 0) {
+                // No existing item in pending changes; need a new one.
+                final int NA = mAvailProcessChanges.size();
+                if (NA > 0) {
+                    item = mAvailProcessChanges.remove(NA-1);
+                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Retreiving available item: " + item);
+                } else {
+                    item = new ProcessChangeItem();
+                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Allocating new item: " + item);
+                }
+                item.changes = 0;
+                item.pid = app.pid;
+                item.uid = app.info.uid;
+                if (mPendingProcessChanges.size() == 0) {
+                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG,
+                            "*** Enqueueing dispatch processes changed!");
+                    mHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED).sendToTarget();
+                }
+                mPendingProcessChanges.add(item);
+            }
+            item.changes |= changes;
+            item.processState = app.repProcState;
+            item.foregroundActivities = app.repForegroundActivities;
+            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Item "
+                    + Integer.toHexString(System.identityHashCode(item))
+                    + " " + app.toShortString() + ": changes=" + item.changes
+                    + " procState=" + item.processState
+                    + " foreground=" + item.foregroundActivities
+                    + " type=" + app.adjType + " source=" + app.adjSource
+                    + " target=" + app.adjTarget);
+        }
+
         return success;
     }
 
@@ -15777,7 +15771,7 @@
     }
 
     private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj,
-            ProcessRecord TOP_APP, boolean doingAll, boolean reportingProcessState, long now) {
+            ProcessRecord TOP_APP, boolean doingAll, long now) {
         if (app.thread == null) {
             return false;
         }
@@ -15786,8 +15780,7 @@
 
         computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now);
 
-        return applyOomAdjLocked(app, wasKeeping, TOP_APP, doingAll,
-                reportingProcessState, now);
+        return applyOomAdjLocked(app, wasKeeping, TOP_APP, doingAll, now);
     }
 
     final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground,
@@ -15853,10 +15846,6 @@
     }
 
     final boolean updateOomAdjLocked(ProcessRecord app) {
-        return updateOomAdjLocked(app, false);
-    }
-
-    final boolean updateOomAdjLocked(ProcessRecord app, boolean doingProcessState) {
         final ActivityRecord TOP_ACT = resumedAppLocked();
         final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
         final boolean wasCached = app.cached;
@@ -15869,7 +15858,7 @@
         // need to do a complete oom adj.
         final int cachedAdj = app.curRawAdj >= ProcessList.CACHED_APP_MIN_ADJ
                 ? app.curRawAdj : ProcessList.UNKNOWN_ADJ;
-        boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false, doingProcessState,
+        boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false,
                 SystemClock.uptimeMillis());
         if (wasCached != app.cached || app.curRawAdj == ProcessList.UNKNOWN_ADJ) {
             // Changed to/from cached state, so apps after it in the LRU
@@ -16002,7 +15991,7 @@
                     }
                 }
 
-                applyOomAdjLocked(app, wasKeeping, TOP_APP, true, false, now);
+                applyOomAdjLocked(app, wasKeeping, TOP_APP, true, now);
 
                 // Count the number of process types.
                 switch (app.curProcState) {
@@ -16656,7 +16645,7 @@
                 }
 
                 if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
-                    if (userId != 0) {
+                    if (userId != UserHandle.USER_OWNER) {
                         Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
                         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                         broadcastIntentLocked(null, null, intent, null,
@@ -16685,6 +16674,8 @@
                     EventLogTags.writeAmSwitchUser(userId);
                     getUserManagerLocked().userForeground(userId);
                     sendUserSwitchBroadcastsLocked(oldUserId, userId);
+                } else {
+                    mStackSupervisor.startBackgroundUserLocked(userId, uss);
                 }
 
                 if (needStart) {
@@ -16860,7 +16851,7 @@
         }
     }
 
-    void finishUserSwitch(UserStartedState uss) {
+    void finishUserBoot(UserStartedState uss) {
         synchronized (this) {
             if (uss.mState == UserStartedState.STATE_BOOTING
                     && mStartedUsers.get(uss.mHandle.getIdentifier()) == uss) {
@@ -16874,6 +16865,12 @@
                         android.Manifest.permission.RECEIVE_BOOT_COMPLETED, AppOpsManager.OP_NONE,
                         true, false, MY_PID, Process.SYSTEM_UID, userId);
             }
+        }
+    }
+
+    void finishUserSwitch(UserStartedState uss) {
+        synchronized (this) {
+            finishUserBoot(uss);
 
             startProfilesLocked();
 
@@ -17213,4 +17210,69 @@
             ActivityManagerService.this.wakingUp();
         }
     }
+
+    /**
+     * An implementation of IAppTask, that allows an app to manage its own tasks via
+     * {@link android.app.ActivityManager#AppTask}.  We keep track of the callingUid to ensure that
+     * only the process that calls getAppTasks() can call the AppTask methods.
+     */
+    class AppTaskImpl extends IAppTask.Stub {
+        private int mTaskId;
+        private int mCallingUid;
+
+        public AppTaskImpl(int taskId, int callingUid) {
+            mTaskId = taskId;
+            mCallingUid = callingUid;
+        }
+
+        @Override
+        public void finishAndRemoveTask() {
+            // Ensure that we are called from the same process that created this AppTask
+            if (mCallingUid != Binder.getCallingUid()) {
+                Slog.w(TAG, "finishAndRemoveTask: caller " + mCallingUid
+                        + " does not match caller of getAppTasks(): " + Binder.getCallingUid());
+                return;
+            }
+
+            synchronized (ActivityManagerService.this) {
+                long origId = Binder.clearCallingIdentity();
+                try {
+                    TaskRecord tr = recentTaskForIdLocked(mTaskId);
+                    if (tr != null) {
+                        // Only kill the process if we are not a new document
+                        int flags = tr.getBaseIntent().getFlags();
+                        boolean isDocument = (flags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) ==
+                                Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+                        removeTaskByIdLocked(mTaskId,
+                                !isDocument ? ActivityManager.REMOVE_TASK_KILL_PROCESS : 0);
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(origId);
+                }
+            }
+        }
+
+        @Override
+        public ActivityManager.RecentTaskInfo getTaskInfo() {
+            // Ensure that we are called from the same process that created this AppTask
+            if (mCallingUid != Binder.getCallingUid()) {
+                Slog.w(TAG, "finishAndRemoveTask: caller " + mCallingUid
+                        + " does not match caller of getAppTasks(): " + Binder.getCallingUid());
+                return null;
+            }
+
+            synchronized (ActivityManagerService.this) {
+                long origId = Binder.clearCallingIdentity();
+                try {
+                    TaskRecord tr = recentTaskForIdLocked(mTaskId);
+                    if (tr != null) {
+                        return createRecentTaskInfoFromTaskRecord(tr);
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(origId);
+                }
+                return null;
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 7a44473..9582ac7 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -16,13 +16,14 @@
 
 package com.android.server.am;
 
+import android.os.PersistableBundle;
 import android.os.Trace;
-import com.android.internal.R.styleable;
 import com.android.internal.app.ResolverActivity;
 import com.android.server.AttributeCache;
 import com.android.server.am.ActivityStack.ActivityState;
 import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
 
+import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ResultInfo;
 import android.content.ComponentName;
@@ -117,6 +118,7 @@
     ProcessRecord app;      // if non-null, hosting application
     ActivityState state;    // current state we are in
     Bundle  icicle;         // last saved activity state
+    PersistableBundle persistentState; // last persistently saved activity state
     boolean frontOfTask;    // is this the root activity of its task?
     boolean launchFailed;   // set if a launched failed, to abort on 2nd try
     boolean haveState;      // have we gotten the last activity state?
@@ -131,7 +133,6 @@
     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 thumbnailNeeded;// has someone requested a thumbnail?
     boolean idle;           // has the activity gone idle?
     boolean hasBeenLaunched;// has this activity ever been launched?
     boolean frozenBeforeDestroy;// has been frozen but not yet destroyed.
@@ -148,8 +149,7 @@
     boolean mStartingWindowShown = false;
     ActivityContainer mInitialActivityContainer;
 
-    String activityLabel;
-    Bitmap activityIcon;
+    ActivityManager.RecentsActivityValues activityValues; // the recents information for this activity
 
     void dump(PrintWriter pw, String prefix) {
         final long now = SystemClock.uptimeMillis();
@@ -239,7 +239,6 @@
                 pw.print(" immersive="); pw.print(immersive);
                 pw.print(" launchMode="); pw.println(launchMode);
         pw.print(prefix); pw.print("frozenBeforeDestroy="); pw.print(frozenBeforeDestroy);
-                pw.print(" thumbnailNeeded="); pw.print(thumbnailNeeded);
                 pw.print(" forceNewConfig="); pw.println(forceNewConfig);
         pw.print(prefix); pw.print("mActivityType=");
                 pw.println(activityTypeToString(mActivityType));
@@ -348,7 +347,7 @@
             ActivityInfo aInfo, Configuration _configuration,
             ActivityRecord _resultTo, String _resultWho, int _reqCode,
             boolean _componentSpecified, ActivityStackSupervisor supervisor,
-            ActivityContainer container) {
+            ActivityContainer container, Bundle options) {
         service = _service;
         appToken = new Token(this);
         info = aInfo;
@@ -375,11 +374,13 @@
         visible = true;
         waitingVisible = false;
         nowVisible = false;
-        thumbnailNeeded = false;
         idle = false;
         hasBeenLaunched = false;
         mStackSupervisor = supervisor;
         mInitialActivityContainer = container;
+        if (options != null) {
+            pendingOptions = new ActivityOptions(options);
+        }
 
         // This starts out true, since the initial state of an activity
         // is that we have everything, and we shouldn't never consider it
@@ -713,6 +714,9 @@
                                         + pendingOptions.getThumbnail().getHeight()));
                     }
                     break;
+                default:
+                    Slog.e(TAG, "applyOptionsLocked: Unknown animationType=" + animationType);
+                    break;
             }
             pendingOptions = null;
         }
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 6769c9c..c1e5e5b 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -36,8 +36,6 @@
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES;
 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
 
-import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.CONTAINER_STATE_HAS_SURFACE;
-
 import android.service.voice.IVoiceInteractionSession;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.os.BatteryStatsImpl;
@@ -53,7 +51,6 @@
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
 import android.app.IActivityController;
-import android.app.IThumbnailReceiver;
 import android.app.ResultInfo;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.content.ComponentName;
@@ -71,9 +68,9 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.util.EventLog;
@@ -208,6 +205,9 @@
     ActivityRecord mTranslucentActivityWaiting = null;
     ArrayList<ActivityRecord> mUndrawnActivitiesBelowTopTranslucent =
             new ArrayList<ActivityRecord>();
+    // Options passed from the caller of the convertToTranslucent to the activity that will
+    // appear below it.
+    ActivityOptions mReturningActivityOptions = null;
 
     /**
      * Set when we know we are going to be calling updateConfiguration()
@@ -280,7 +280,7 @@
                         if (r.app != null) {
                             mService.logAppTooSlow(r.app, r.pauseTime, "pausing " + r);
                         }
-                        activityPausedLocked(r.appToken, true);
+                        activityPausedLocked(r.appToken, true, r.persistentState);
                     }
                 } break;
                 case LAUNCH_TICK_MSG: {
@@ -864,13 +864,15 @@
         }
     }
 
-    final void activityPausedLocked(IBinder token, boolean timeout) {
+    final void activityPausedLocked(IBinder token, boolean timeout,
+            PersistableBundle persistentState) {
         if (DEBUG_PAUSE) Slog.v(
             TAG, "Activity paused: token=" + token + ", timeout=" + timeout);
 
         final ActivityRecord r = isInStackLocked(token);
         if (r != null) {
             mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
+            r.persistentState = persistentState;
             if (mPausingActivity == r) {
                 if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
                         + (timeout ? " (due to timeout)" : " (pause complete)"));
@@ -885,13 +887,14 @@
         }
     }
 
-    final void activityStoppedLocked(ActivityRecord r, Bundle icicle, Bitmap thumbnail,
-            CharSequence description) {
+    final void activityStoppedLocked(ActivityRecord r, Bundle icicle,
+            PersistableBundle persistentState, CharSequence description) {
         if (r.state != ActivityState.STOPPING) {
             Slog.i(TAG, "Activity reported stop, but no longer stopping: " + r);
             mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
             return;
         }
+        r.persistentState = persistentState;
         if (DEBUG_SAVED_STATE) Slog.i(TAG, "Saving icicle of " + r + ": " + icicle);
         if (icicle != null) {
             // If icicle is null, this is happening due to a timeout, so we
@@ -899,7 +902,7 @@
             r.icicle = icicle;
             r.haveState = true;
             r.launchCount = 0;
-            r.updateThumbnail(thumbnail, description);
+            r.updateThumbnail(null, description);
         }
         if (!r.stopped) {
             if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r + " (stop complete)");
@@ -1084,26 +1087,59 @@
         }
     }
 
-    /**
-     * Version of ensureActivitiesVisible that can easily be called anywhere.
-     */
-    final boolean ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
-        return ensureActivitiesVisibleLocked(starting, configChanges, false);
+    // 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() {
+        if (!isAttached()) {
+            return false;
+        }
+
+        if (mStackSupervisor.isFrontStack(this)) {
+            return true;
+        }
+
+        /**
+         * Start at the task above this one and go up, looking for a visible
+         * fullscreen activity, or a translucent activity that requested the
+         * wallpaper to be shown behind it.
+         */
+        for (int i = mStacks.indexOf(this) + 1; i < mStacks.size(); i++) {
+            final ArrayList<TaskRecord> tasks = mStacks.get(i).getAllTasks();
+            for (int taskNdx = 0; taskNdx < tasks.size(); taskNdx++) {
+                final ArrayList<ActivityRecord> activities = tasks.get(taskNdx).mActivities;
+                for (int activityNdx = 0; activityNdx < activities.size(); activityNdx++) {
+                    final ActivityRecord r = activities.get(activityNdx);
+
+                    // Conditions for an activity to obscure the stack we're
+                    // examining:
+                    // 1. Not Finishing AND Visible AND:
+                    // 2. Either:
+                    // - Full Screen Activity OR
+                    // - On top of Home and our stack is NOT home
+                    if (!r.finishing && r.visible && (r.fullscreen ||
+                            (!isHomeStack() && r.frontOfTask && tasks.get(taskNdx).mOnTopOfHome))) {
+                        return false;
+                    }
+                }
+            }
+        }
+
+        return true;
     }
 
-    final boolean ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
-            boolean forceHomeShown) {
+    final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
         ActivityRecord r = topRunningActivityLocked(null);
-        return r != null &&
-                ensureActivitiesVisibleLocked(r, starting, null, configChanges, forceHomeShown);
+        if (r != null) {
+            ensureActivitiesVisibleLocked(r, starting, null, configChanges);
+        }
     }
 
     /**
      * Make sure that all activities that need to be visible (that is, they
      * currently can be seen by the user) actually are.
      */
-    final boolean ensureActivitiesVisibleLocked(ActivityRecord top, ActivityRecord starting,
-            String onlyThisProcess, int configChanges, boolean forceHomeShown) {
+    final void ensureActivitiesVisibleLocked(ActivityRecord top, ActivityRecord starting,
+            String onlyThisProcess, int configChanges) {
         if (DEBUG_VISBILITY) Slog.v(
                 TAG, "ensureActivitiesVisible behind " + top
                 + " configChanges=0x" + Integer.toHexString(configChanges));
@@ -1121,9 +1157,8 @@
         // If the top activity is not fullscreen, then we need to
         // make sure any activities under it are now visible.
         boolean aboveTop = true;
-        boolean showHomeBehindStack = false;
-        boolean behindFullscreen = !mStackSupervisor.isFrontStack(this) &&
-                !(forceHomeShown && isHomeStack());
+        boolean behindFullscreen = !isStackVisible();
+
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
             final ArrayList<ActivityRecord> activities = task.mActivities;
@@ -1186,6 +1221,7 @@
                                     TAG, "Making visible and scheduling visibility: " + r);
                             try {
                                 if (mTranslucentActivityWaiting != null) {
+                                    r.updateOptionsLocked(mReturningActivityOptions);
                                     mUndrawnActivitiesBelowTopTranslucent.add(r);
                                 }
                                 setVisibile(r, true);
@@ -1209,11 +1245,9 @@
                         // At this point, nothing else needs to be shown
                         if (DEBUG_VISBILITY) Slog.v(TAG, "Fullscreen: at " + r);
                         behindFullscreen = true;
-                        showHomeBehindStack = false;
-                    } else if (isActivityOverHome(r)) {
+                    } else if (!isHomeStack() && r.frontOfTask && task.mOnTopOfHome) {
                         if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r);
-                        showHomeBehindStack = true;
-                        behindFullscreen = !isHomeStack() && r.frontOfTask && task.mOnTopOfHome;
+                        behindFullscreen = true;
                     }
                 } else {
                     if (DEBUG_VISBILITY) Slog.v(
@@ -1263,12 +1297,12 @@
                 }
             }
         }
-        return showHomeBehindStack;
     }
 
-    void convertToTranslucent(ActivityRecord r) {
+    void convertToTranslucent(ActivityRecord r, ActivityOptions options) {
         mTranslucentActivityWaiting = r;
         mUndrawnActivitiesBelowTopTranslucent.clear();
+        mReturningActivityOptions = options;
         mHandler.sendEmptyMessageDelayed(TRANSLUCENT_TIMEOUT_MSG, TRANSLUCENT_CONVERSION_TIMEOUT);
     }
 
@@ -1392,7 +1426,8 @@
 
         final TaskRecord nextTask = next.task;
         final TaskRecord prevTask = prev != null ? prev.task : null;
-        if (prevTask != null && prevTask.mOnTopOfHome && prev.finishing && prev.frontOfTask) {
+        if (prevTask != null && prevTask.stack == this &&
+                prevTask.mOnTopOfHome && prev.finishing && prev.frontOfTask) {
             if (DEBUG_STACK)  mStackSupervisor.validateTopActivitiesLocked();
             if (prevTask == nextTask) {
                 prevTask.setFrontOfTask();
@@ -1441,8 +1476,6 @@
         next.sleeping = false;
         mStackSupervisor.mWaitingVisibleActivities.remove(next);
 
-        next.updateOptionsLocked(options);
-
         if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);
 
         // If we are currently pausing an activity, then don't do anything
@@ -1886,7 +1919,6 @@
                         : AppTransition.TRANSIT_ACTIVITY_OPEN, keepCurTransition);
                 mNoAnimActivities.remove(r);
             }
-            r.updateOptionsLocked(options);
             mWindowManager.addAppToken(task.mActivities.indexOf(r),
                     r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                     (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
@@ -1937,13 +1969,14 @@
                     (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
                     r.info.configChanges);
             ActivityOptions.abort(options);
+            options = null;
         }
         if (VALIDATE_TOKENS) {
             validateAppTokensLocked();
         }
 
         if (doResume) {
-            mStackSupervisor.resumeTopActivitiesLocked();
+            mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
         }
     }
 
@@ -2537,13 +2570,6 @@
 
         finishActivityResultsLocked(r, resultCode, resultData);
 
-        if (!mService.mPendingThumbnails.isEmpty()) {
-            // There are clients waiting to receive thumbnails so, in case
-            // this is an activity that someone is waiting for, add it
-            // to the pending list so we can correctly update the clients.
-            mStackSupervisor.mCancelledThumbnails.add(r);
-        }
-
         if (mResumedActivity == r) {
             boolean endTask = index <= 0;
             if (DEBUG_VISBILITY || DEBUG_TRANSITION) Slog.v(TAG,
@@ -2782,13 +2808,6 @@
             cleanUpActivityServicesLocked(r);
         }
 
-        if (!mService.mPendingThumbnails.isEmpty()) {
-            // There are clients waiting to receive thumbnails so, in case
-            // this is an activity that someone is waiting for, add it
-            // to the pending list so we can correctly update the clients.
-            mStackSupervisor.mCancelledThumbnails.add(r);
-        }
-
         // Get rid of any pending idle timeouts.
         removeTimeoutsForActivityLocked(r);
     }
@@ -3535,9 +3554,7 @@
         return didSomething;
     }
 
-    ActivityRecord getTasksLocked(IThumbnailReceiver receiver,
-            PendingThumbnailsRecord pending, List<RunningTaskInfo> list) {
-        ActivityRecord topRecord = null;
+    void getTasksLocked(List<RunningTaskInfo> list, int callingUid, boolean allowed) {
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
             ActivityRecord r = null;
@@ -3548,6 +3565,9 @@
             if (activities.isEmpty()) {
                 continue;
             }
+            if (!allowed && !task.isHomeTask() && task.creatorUid != callingUid) {
+                continue;
+            }
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 r = activities.get(activityNdx);
 
@@ -3581,23 +3601,8 @@
             ci.numRunning = numRunning;
             //System.out.println(
             //    "#" + maxNum + ": " + " descr=" + ci.description);
-            if (receiver != null) {
-                if (localLOGV) Slog.v(
-                    TAG, "State=" + top.state + "Idle=" + top.idle
-                    + " app=" + top.app
-                    + " thr=" + (top.app != null ? top.app.thread : null));
-                if (top.state == ActivityState.RESUMED || top.state == ActivityState.PAUSING) {
-                    if (top.idle && top.app != null && top.app.thread != null) {
-                        topRecord = top;
-                    } else {
-                        top.thumbnailNeeded = true;
-                    }
-                }
-                pending.pendingRecords.add(top);
-            }
             list.add(ci);
         }
-        return topRecord;
     }
 
     public void unhandledBackLocked() {
@@ -3731,10 +3736,20 @@
             mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true;
         }
         mTaskHistory.remove(task);
-        if (task.voiceInteractor != null) {
-            // This task was a voice interaction, so it should not remain on the
-            // recent tasks list.
-            mService.mRecentTasks.remove(task);
+
+        if (task.mActivities.isEmpty()) {
+            final boolean isVoiceSession = task.voiceSession != null;
+            if (isVoiceSession) {
+                try {
+                    task.voiceSession.taskFinished(task.intent, task.taskId);
+                } catch (RemoteException e) {
+                }
+            }
+            if (task.autoRemoveFromRecents() || isVoiceSession) {
+                // Task creator asked to remove this when done, or this task was a voice
+                // interaction, so it should not remain on the recent tasks list.
+                mService.mRecentTasks.remove(task);
+            }
         }
 
         if (mTaskHistory.isEmpty()) {
@@ -3753,7 +3768,7 @@
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             boolean toTop) {
         TaskRecord task = new TaskRecord(taskId, info, intent, voiceSession, voiceInteractor);
-        addTask(task, toTop);
+        addTask(task, toTop, false);
         return task;
     }
 
@@ -3761,13 +3776,19 @@
         return new ArrayList<TaskRecord>(mTaskHistory);
     }
 
-    void addTask(final TaskRecord task, final boolean toTop) {
+    void addTask(final TaskRecord task, final boolean toTop, boolean moving) {
         task.stack = this;
         if (toTop) {
             insertTaskAtTop(task);
         } else {
             mTaskHistory.add(0, task);
         }
+        if (!moving && task.voiceSession != null) {
+            try {
+                task.voiceSession.taskStarted(task.intent, task.taskId);
+            } catch (RemoteException e) {
+            }
+        }
     }
 
     public int getStackId() {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 3770a07..5d744e6 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -41,7 +41,6 @@
 import android.app.IActivityContainerCallback;
 import android.app.IActivityManager;
 import android.app.IApplicationThread;
-import android.app.IThumbnailReceiver;
 import android.app.PendingIntent;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.IActivityManager.WaitResult;
@@ -191,13 +190,12 @@
     /** List of activities that are in the process of going to sleep. */
     final ArrayList<ActivityRecord> mGoingToSleepActivities = new ArrayList<ActivityRecord>();
 
-    /** List of ActivityRecord objects that have been finished and must still report back to a
-     * pending thumbnail receiver. */
-    final ArrayList<ActivityRecord> mCancelledThumbnails = new ArrayList<ActivityRecord>();
-
     /** Used on user changes */
     final ArrayList<UserStartedState> mStartingUsers = new ArrayList<UserStartedState>();
 
+    /** Used to queue up any background users being started */
+    final ArrayList<UserStartedState> mStartingBackgroundUsers = new ArrayList<UserStartedState>();
+
     /** Set to indicate whether to issue an onUserLeaving callback when a newly launched activity
      * is being brought in front of us. */
     boolean mUserLeaving = false;
@@ -591,10 +589,7 @@
         return null;
     }
 
-    ActivityRecord getTasksLocked(int maxNum, IThumbnailReceiver receiver,
-            PendingThumbnailsRecord pending, List<RunningTaskInfo> list) {
-        ActivityRecord r = null;
-
+    void getTasksLocked(int maxNum, List<RunningTaskInfo> list, int callingUid, boolean allowed) {
         // Gather all of the running tasks for each stack into runningTaskLists.
         ArrayList<ArrayList<RunningTaskInfo>> runningTaskLists =
                 new ArrayList<ArrayList<RunningTaskInfo>>();
@@ -605,10 +600,7 @@
                 final ActivityStack stack = stacks.get(stackNdx);
                 ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<RunningTaskInfo>();
                 runningTaskLists.add(stackTaskList);
-                final ActivityRecord ar = stack.getTasksLocked(receiver, pending, stackTaskList);
-                if (r == null && isFrontStack(stack)) {
-                    r = ar;
-                }
+                stack.getTasksLocked(stackTaskList, callingUid, allowed);
             }
         }
 
@@ -635,8 +627,6 @@
                 break;
             }
         }
-
-        return r;
     }
 
     ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,
@@ -1032,14 +1022,12 @@
             }
 
             app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_TOP);
-            Bundle options = (r.pendingOptions == null) ? null : r.pendingOptions.toBundle();
-            r.clearOptionsLocked();
             app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                     System.identityHashCode(r), r.info,
-                    new Configuration(mService.mConfiguration), r.compat,
-                    r.task.voiceInteractor, app.repProcState, r.icicle, results, newIntents,
-                    !andResume, mService.isNextTransitionForward(), profileFile, profileFd,
-                    profileAutoStop, options);
+                    new Configuration(mService.mConfiguration), r.compat, r.task.voiceInteractor,
+                    app.repProcState, r.icicle, r.persistentState, results, newIntents, !andResume,
+                    mService.isNextTransitionForward(), profileFile, profileFd, profileAutoStop
+            );
 
             if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
                 // This may be a heavy-weight process!  Note that the package
@@ -1335,7 +1323,7 @@
 
         ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
                 intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
-                requestCode, componentSpecified, this, container);
+                requestCode, componentSpecified, this, container, options);
         if (outActivity != null) {
             outActivity[0] = r;
         }
@@ -1484,6 +1472,17 @@
             }
         }
 
+        switch (r.info.documentLaunchMode) {
+            case ActivityInfo.DOCUMENT_LAUNCH_NONE:
+                break;
+            case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
+                intent.addFlags(
+                        Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+                break;
+            case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+                break;
+        }
         final boolean newDocument = intent.isDocument();
         if (sourceRecord == null) {
             // This activity is not being started from another...  in this
@@ -1912,7 +1911,6 @@
         ArrayList<UserStartedState> startingUsers = null;
         int NS = 0;
         int NF = 0;
-        IApplicationThread sendThumbnail = null;
         boolean booting = false;
         boolean enableScreen = false;
         boolean activityRemoved = false;
@@ -1940,11 +1938,6 @@
             // us, we can now deliver.
             r.idle = true;
 
-            if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
-                sendThumbnail = r.app.thread;
-                r.thumbnailNeeded = false;
-            }
-
             //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
             if (!mService.mBooted && isFrontStack(r.task.stack)) {
                 mService.mBooted = true;
@@ -1976,15 +1969,6 @@
             mFinishingActivities.clear();
         }
 
-        final ArrayList<ActivityRecord> thumbnails;
-        final int NT = mCancelledThumbnails.size();
-        if (NT > 0) {
-            thumbnails = new ArrayList<ActivityRecord>(mCancelledThumbnails);
-            mCancelledThumbnails.clear();
-        } else {
-            thumbnails = null;
-        }
-
         if (isFrontStack(mHomeStack)) {
             booting = mService.mBooting;
             mService.mBooting = false;
@@ -1995,28 +1979,6 @@
             mStartingUsers.clear();
         }
 
-        // Perform the following actions from unsynchronized state.
-        final IApplicationThread thumbnailThread = sendThumbnail;
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                if (thumbnailThread != null) {
-                    try {
-                        thumbnailThread.requestThumbnail(token);
-                    } catch (Exception e) {
-                        Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
-                        mService.sendPendingThumbnail(null, token, null, null, true);
-                    }
-                }
-
-                // Report back to any thumbnail receivers.
-                for (int i = 0; i < NT; i++) {
-                    ActivityRecord r = thumbnails.get(i);
-                    mService.sendPendingThumbnail(r, null, null, null, true);
-                }
-            }
-        });
-
         // Stop any activities that are scheduled to do so but have been
         // waiting for the next one to start.
         for (int i = 0; i < NS; i++) {
@@ -2038,9 +2000,20 @@
 
         if (booting) {
             mService.finishBooting();
-        } else if (startingUsers != null) {
-            for (int i = 0; i < startingUsers.size(); i++) {
-                mService.finishUserSwitch(startingUsers.get(i));
+        } else {
+            // Complete user switch
+            if (startingUsers != null) {
+                for (int i = 0; i < startingUsers.size(); i++) {
+                    mService.finishUserSwitch(startingUsers.get(i));
+                }
+            }
+            // Complete starting up of background users
+            if (mStartingBackgroundUsers.size() > 0) {
+                startingUsers = new ArrayList<UserStartedState>(mStartingBackgroundUsers);
+                mStartingBackgroundUsers.clear();
+                for (int i = 0; i < startingUsers.size(); i++) {
+                    mService.finishUserBoot(startingUsers.get(i));
+                }
             }
         }
 
@@ -2288,7 +2261,7 @@
             return;
         }
         task.stack.removeTask(task);
-        stack.addTask(task, toTop);
+        stack.addTask(task, toTop, true);
         mWindowManager.addTask(taskId, stackId, toTop);
         resumeTopActivitiesLocked();
     }
@@ -2480,21 +2453,12 @@
 
     void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
         // First the front stacks. In case any are not fullscreen and are in front of home.
-        boolean showHomeBehindStack = false;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             final int topStackNdx = stacks.size() - 1;
             for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
-                if (stackNdx == topStackNdx) {
-                    // Top stack.
-                    showHomeBehindStack =
-                            stack.ensureActivitiesVisibleLocked(starting, configChanges);
-                } else {
-                    // Back stack.
-                    stack.ensureActivitiesVisibleLocked(starting, configChanges,
-                            showHomeBehindStack);
-                }
+                stack.ensureActivitiesVisibleLocked(starting, configChanges);
             }
         }
     }
@@ -2546,6 +2510,15 @@
         return homeInFront;
     }
 
+    /**
+     * Add background users to send boot completed events to.
+     * @param userId The user being started in the background
+     * @param uss The state object for the user.
+     */
+    public void startBackgroundUserLocked(int userId, UserStartedState uss) {
+        mStartingBackgroundUsers.add(uss);
+    }
+
     final ArrayList<ActivityRecord> processStoppingActivitiesLocked(boolean remove) {
         int N = mStoppingActivities.size();
         if (N <= 0) return null;
@@ -3169,7 +3142,7 @@
                 }
             }
             ActivityInfo aInfo = resolveActivity(intent, resolvedType, 0, null, null, userId);
-            if ((aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
+            if (aInfo != null && (aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
                 throw new SecurityException(
                         "Attempt to embed activity that has not set allowEmbedded=\"true\"");
             }
@@ -3288,9 +3261,9 @@
             } else {
                 mContainerState = CONTAINER_STATE_NO_SURFACE;
                 ((VirtualActivityDisplay) mActivityDisplay).setSurface(null);
-//                if (mStack.mPausingActivity == null && mStack.mResumedActivity != null) {
-//                    mStack.startPausingLocked(false, true);
-//                }
+                if (mStack.mPausingActivity == null && mStack.mResumedActivity != null) {
+                    mStack.startPausingLocked(false, true);
+                }
             }
 
             setSurfaceIfReady();
@@ -3300,6 +3273,11 @@
         }
 
         @Override
+        boolean isAttached() {
+            return mSurface != null && super.isAttached();
+        }
+
+        @Override
         void setDrawn() {
             synchronized (mService) {
                 mDrawn = true;
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 83e8a4b..dd12a65 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -230,10 +230,10 @@
         }
     }
         
-    public void noteScreenOn() {
+    public void noteScreenState(int state) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteScreenOnLocked();
+            mStats.noteScreenStateLocked(state);
         }
     }
     
@@ -244,24 +244,19 @@
         }
     }
     
-    public void noteScreenOff() {
-        enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteScreenOffLocked();
-        }
-    }
-
-    public void noteInputEvent() {
-        enforceCallingPermission();
-        mStats.noteInputEventAtomic();
-    }
-    
     public void noteUserActivity(int uid, int event) {
         enforceCallingPermission();
         synchronized (mStats) {
             mStats.noteUserActivityLocked(uid, event);
         }
     }
+    
+    public void noteInteractive(boolean interactive) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteInteractiveLocked(interactive);
+        }
+    }
 
     public void noteMobileRadioPowerState(int powerState, long timestampNs) {
         enforceCallingPermission();
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index b15fa5d..9d6481a 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -503,7 +503,7 @@
                     // are already core system stuff so don't matter for this.
                     r.curApp = filter.receiverList.app;
                     filter.receiverList.app.curReceiver = r;
-                    mService.updateOomAdjLocked(r.curApp, true);
+                    mService.updateOomAdjLocked(r.curApp);
                 }
             }
             try {
diff --git a/services/core/java/com/android/server/am/PendingThumbnailsRecord.java b/services/core/java/com/android/server/am/PendingThumbnailsRecord.java
deleted file mode 100644
index e4eb4d0..0000000
--- a/services/core/java/com/android/server/am/PendingThumbnailsRecord.java
+++ /dev/null
@@ -1,39 +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.server.am;
-
-import android.app.IThumbnailReceiver;
-
-import java.util.HashSet;
-
-/**
- * This class keeps track of calls to getTasks() that are still
- * waiting for thumbnail images.
- */
-final class PendingThumbnailsRecord
-{
-    final IThumbnailReceiver receiver;   // who is waiting.
-    final HashSet<ActivityRecord> pendingRecords; // HistoryRecord objects we still wait for.
-    boolean finished;       // Is pendingRecords empty?
-
-    PendingThumbnailsRecord(IThumbnailReceiver _receiver)
-    {
-        receiver = _receiver;
-        pendingRecords = new HashSet<ActivityRecord>();
-        finished = false;
-    }
-}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index d04a6b2..8d7d300 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -77,7 +77,6 @@
     int curSchedGroup;          // Currently desired scheduling class
     int setSchedGroup;          // Last set to background scheduling class
     int trimMemoryLevel;        // Last selected memory trimming level
-    int memImportance;          // Importance constant computed from curAdj
     int curProcState = -1;      // Currently computed process state: ActivityManager.PROCESS_STATE_*
     int repProcState = -1;      // Last reported process state
     int setProcState = -1;      // Last set process state in process tracker
@@ -91,6 +90,7 @@
     boolean hasStartedServices; // Are there any started services running in this process?
     boolean foregroundServices; // Running any services that are foreground?
     boolean foregroundActivities; // Running any activities that are foreground?
+    boolean repForegroundActivities; // Last reported foreground activities.
     boolean systemNoUi;         // This is a system process, but not currently showing UI.
     boolean hasShownUi;         // Has UI been shown in this process since it was started?
     boolean pendingUiClean;     // Want to clean up resources from showing UI?
@@ -267,9 +267,10 @@
             pw.print(prefix); pw.print("persistent="); pw.print(persistent);
                     pw.print(" removed="); pw.println(removed);
         }
-        if (hasClientActivities || foregroundActivities) {
+        if (hasClientActivities || foregroundActivities || repForegroundActivities) {
             pw.print(prefix); pw.print("hasClientActivities="); pw.print(hasClientActivities);
-                    pw.print(" foregroundActivities="); pw.println(foregroundActivities);
+                    pw.print(" foregroundActivities="); pw.print(foregroundActivities);
+                    pw.print(" (rep="); pw.print(repForegroundActivities); pw.println(")");
         }
         if (hasStartedServices) {
             pw.print(prefix); pw.print("hasStartedServices="); pw.println(hasStartedServices);
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 68da54d..be884e7 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -52,9 +52,15 @@
 
     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.
 
+    // This represents the last resolved activity values for this task
+    // NOTE: This value needs to be persisted with each task
+    ActivityManager.RecentsActivityValues lastActivityValues =
+            new ActivityManager.RecentsActivityValues();
+
     /** List of all activities in the task arranged in history order */
     final ArrayList<ActivityRecord> mActivities = new ArrayList<ActivityRecord>();
 
@@ -131,8 +137,10 @@
             rootWasReset = true;
         }
 
-        if (info.applicationInfo != null) {
-            userId = UserHandle.getUserId(info.applicationInfo.uid);
+        userId = UserHandle.getUserId(info.applicationInfo.uid);
+        creatorUid = info.applicationInfo.uid;
+        if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
+            intent.addFlags(Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
         }
     }
 
@@ -146,6 +154,11 @@
         }
     }
 
+    /** Returns the intent for the root activity for this task */
+    Intent getBaseIntent() {
+        return intent != null ? intent : affinityIntent;
+    }
+
     /** Returns the first non-finishing activity from the root. */
     ActivityRecord getRootActivity() {
         for (int i = 0; i < mActivities.size(); i++) {
@@ -241,6 +254,11 @@
         return mActivities.size() == 0;
     }
 
+    boolean autoRemoveFromRecents() {
+        return intent != null &&
+                (intent.getFlags() & Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS) != 0;
+    }
+
     /**
      * Completely remove all activities associated with an existing
      * task starting at a specified index.
diff --git a/services/core/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/am/UriPermission.java
index 4970b8d..284086d 100644
--- a/services/core/java/com/android/server/am/UriPermission.java
+++ b/services/core/java/com/android/server/am/UriPermission.java
@@ -44,7 +44,7 @@
     public static final int STRENGTH_GLOBAL = 2;
     public static final int STRENGTH_PERSISTABLE = 3;
 
-    final int userHandle;
+    final int targetUserId;
     final String sourcePkg;
     final String targetPkg;
 
@@ -86,7 +86,7 @@
     private String stringName;
 
     UriPermission(String sourcePkg, String targetPkg, int targetUid, GrantUri uri) {
-        this.userHandle = UserHandle.getUserId(targetUid);
+        this.targetUserId = UserHandle.getUserId(targetUid);
         this.sourcePkg = sourcePkg;
         this.targetPkg = targetPkg;
         this.targetUid = targetUid;
@@ -307,7 +307,7 @@
 
     void dump(PrintWriter pw, String prefix) {
         pw.print(prefix);
-        pw.print("userHandle=" + userHandle);
+        pw.print("targetUserId=" + targetUserId);
         pw.print(" sourcePkg=" + sourcePkg);
         pw.println(" targetPkg=" + targetPkg);
 
@@ -352,7 +352,7 @@
      * {@link UriPermission#persistedModeFlags} state.
      */
     public static class Snapshot {
-        final int userHandle;
+        final int targetUserId;
         final String sourcePkg;
         final String targetPkg;
         final GrantUri uri;
@@ -360,7 +360,7 @@
         final long persistedCreateTime;
 
         private Snapshot(UriPermission perm) {
-            this.userHandle = perm.userHandle;
+            this.targetUserId = perm.targetUserId;
             this.sourcePkg = perm.sourcePkg;
             this.targetPkg = perm.targetPkg;
             this.uri = perm.uri;
diff --git a/services/core/java/com/android/server/am/UriPermissionOwner.java b/services/core/java/com/android/server/am/UriPermissionOwner.java
index 65d7047..ae83940 100644
--- a/services/core/java/com/android/server/am/UriPermissionOwner.java
+++ b/services/core/java/com/android/server/am/UriPermissionOwner.java
@@ -70,13 +70,13 @@
         removeUriPermissionLocked(null, mode);
     }
 
-    void removeUriPermissionLocked(Uri uri, int mode) {
+    void removeUriPermissionLocked(ActivityManagerService.GrantUri grantUri, int mode) {
         if ((mode & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0
                 && mReadPerms != null) {
             Iterator<UriPermission> it = mReadPerms.iterator();
             while (it.hasNext()) {
                 UriPermission perm = it.next();
-                if (uri == null || uri.equals(perm.uri)) {
+                if (grantUri == null || grantUri.equals(perm.uri)) {
                     perm.removeReadOwner(this);
                     service.removeUriPermissionIfNeededLocked(perm);
                     it.remove();
@@ -91,7 +91,7 @@
             Iterator<UriPermission> it = mWritePerms.iterator();
             while (it.hasNext()) {
                 UriPermission perm = it.next();
-                if (uri == null || uri.equals(perm.uri)) {
+                if (grantUri == null || grantUri.equals(perm.uri)) {
                     perm.removeWriteOwner(this);
                     service.removeUriPermissionIfNeededLocked(perm);
                     it.remove();
diff --git a/services/core/java/com/android/server/am/UsageStatsService.java b/services/core/java/com/android/server/am/UsageStatsService.java
index 587f949..4a5a554 100644
--- a/services/core/java/com/android/server/am/UsageStatsService.java
+++ b/services/core/java/com/android/server/am/UsageStatsService.java
@@ -17,26 +17,31 @@
 package com.android.server.am;
 
 import android.app.AppGlobals;
+import android.app.AppOpsManager;
+import android.app.UsageStats;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
+import android.content.res.Configuration;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.FileUtils;
 import android.os.Parcel;
+import android.os.ParcelableParcel;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.text.format.DateFormat;
 import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.Slog;
+import android.util.TimeUtils;
 import android.util.Xml;
 
 import com.android.internal.app.IUsageStats;
 import com.android.internal.content.PackageMonitor;
-import com.android.internal.os.PkgUsageStats;
 import com.android.internal.util.FastXmlSerializer;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -46,7 +51,6 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -55,8 +59,6 @@
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
 import java.util.TimeZone;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -73,117 +75,133 @@
     private static final boolean localLOGV = false;
     private static final boolean REPORT_UNEXPECTED = false;
     private static final String TAG = "UsageStats";
-    
+
     // Current on-disk Parcel version
-    private static final int VERSION = 1008;
+    private static final int VERSION = 1010;
 
     private static final int CHECKIN_VERSION = 4;
-    
+
     private static final String FILE_PREFIX = "usage-";
 
     private static final String FILE_HISTORY = FILE_PREFIX + "history.xml";
 
-    private static final int FILE_WRITE_INTERVAL = 30*60*1000; //ms
-    
+    private static final int FILE_WRITE_INTERVAL = (localLOGV) ? 0 : 30*60*1000; // 30m in ms
+
     private static final int MAX_NUM_FILES = 5;
-    
+
     private static final int NUM_LAUNCH_TIME_BINS = 10;
     private static final int[] LAUNCH_TIME_BINS = {
         250, 500, 750, 1000, 1500, 2000, 3000, 4000, 5000
     };
-    
+
     static IUsageStats sService;
     private Context mContext;
-    // structure used to maintain statistics since the last checkin.
-    final private ArrayMap<String, PkgUsageStatsExtended> mStats;
+    private AppOpsManager mAppOps;
 
-    // Maintains the last time any component was resumed, for all time.
-    final private ArrayMap<String, ArrayMap<String, Long>> mLastResumeTimes;
+    // structure used to maintain statistics since the last checkin.
+    private LocalUsageStats mStats = new LocalUsageStats();
 
     // To remove last-resume time stats when a pacakge is removed.
     private PackageMonitor mPackageMonitor;
 
     // Lock to update package stats. Methods suffixed by SLOCK should invoked with
     // this lock held
-    final Object mStatsLock;
+    final Object mStatsLock = new Object();
     // Lock to write to file. Methods suffixed by FLOCK should invoked with
     // this lock held.
-    final Object mFileLock;
+    final Object mFileLock = new Object();
     // Order of locks is mFileLock followed by mStatsLock to avoid deadlocks
     private String mLastResumedPkg;
     private String mLastResumedComp;
     private boolean mIsResumed;
+    private ConfigUsageStatsExtended mCurrentConfigStats;
     private File mFile;
     private AtomicFile mHistoryFile;
     private String mFileLeaf;
     private File mDir;
 
-    private Calendar mCal; // guarded by itself
+    private final Calendar mCal // guarded by itself
+            = Calendar.getInstance(TimeZone.getTimeZone("GMT+0"));
 
     private final AtomicInteger mLastWriteDay = new AtomicInteger(-1);
     private final AtomicLong mLastWriteElapsedTime = new AtomicLong(0);
     private final AtomicBoolean mUnforcedDiskWriteRunning = new AtomicBoolean(false);
-    
+
+    static class LocalUsageStats extends UsageStats {
+        public LocalUsageStats() {
+        }
+        public LocalUsageStats(Parcel in, boolean extended) {
+            super(in, extended);
+        }
+        @Override
+        public PackageStats onNewPackageStats(String pkgName) {
+            return new PkgUsageStatsExtended(pkgName);
+        }
+        @Override
+        public PackageStats onNewPackageStats(Parcel in) {
+            return new PkgUsageStatsExtended(in);
+        }
+        @Override
+        public ConfigurationStats onNewConfigurationStats(Configuration config) {
+            return new ConfigUsageStatsExtended(config);
+        }
+        @Override
+        public ConfigurationStats onNewConfigurationStats(Parcel source) {
+            return new ConfigUsageStatsExtended(source);
+        }
+    }
+
     static class TimeStats {
-        int count;
-        int[] times = new int[NUM_LAUNCH_TIME_BINS];
-        
+        int mCount;
+        final int[] mTimes = new int[NUM_LAUNCH_TIME_BINS];
+
         TimeStats() {
         }
-        
+
         void incCount() {
-            count++;
+            mCount++;
         }
-        
+
         void add(int val) {
             final int[] bins = LAUNCH_TIME_BINS;
             for (int i=0; i<NUM_LAUNCH_TIME_BINS-1; i++) {
                 if (val < bins[i]) {
-                    times[i]++;
+                    mTimes[i]++;
                     return;
                 }
             }
-            times[NUM_LAUNCH_TIME_BINS-1]++;
+            mTimes[NUM_LAUNCH_TIME_BINS-1]++;
         }
-        
+
         TimeStats(Parcel in) {
-            count = in.readInt();
-            final int[] localTimes = times;
+            mCount = in.readInt();
+            final int[] localTimes = mTimes;
             for (int i=0; i<NUM_LAUNCH_TIME_BINS; i++) {
                 localTimes[i] = in.readInt();
             }
         }
-        
+
         void writeToParcel(Parcel out) {
-            out.writeInt(count);
-            final int[] localTimes = times;
+            out.writeInt(mCount);
+            final int[] localTimes = mTimes;
             for (int i=0; i<NUM_LAUNCH_TIME_BINS; i++) {
                 out.writeInt(localTimes[i]);
             }
         }
     }
-    
-    private class PkgUsageStatsExtended {
+
+    static class PkgUsageStatsExtended extends UsageStats.PackageStats {
         final ArrayMap<String, TimeStats> mLaunchTimes
                 = new ArrayMap<String, TimeStats>();
         final ArrayMap<String, TimeStats> mFullyDrawnTimes
                 = new ArrayMap<String, TimeStats>();
-        int mLaunchCount;
-        long mUsageTime;
-        long mPausedTime;
-        long mResumedTime;
-        
-        PkgUsageStatsExtended() {
-            mLaunchCount = 0;
-            mUsageTime = 0;
+
+        PkgUsageStatsExtended(String pkgName) {
+            super(pkgName);
         }
-        
+
         PkgUsageStatsExtended(Parcel in) {
-            mLaunchCount = in.readInt();
-            mUsageTime = in.readLong();
-            if (localLOGV) Slog.v(TAG, "Launch count: " + mLaunchCount
-                    + ", Usage time:" + mUsageTime);
-            
+            super(in);
             final int numLaunchTimeStats = in.readInt();
             if (localLOGV) Slog.v(TAG, "Reading launch times: " + numLaunchTimeStats);
             mLaunchTimes.ensureCapacity(numLaunchTimeStats);
@@ -205,18 +223,6 @@
             }
         }
 
-        void updateResume(String comp, boolean launched) {
-            if (launched) {
-                mLaunchCount ++;
-            }
-            mResumedTime = SystemClock.elapsedRealtime();
-        }
-        
-        void updatePause() {
-            mPausedTime =  SystemClock.elapsedRealtime();
-            mUsageTime += (mPausedTime - mResumedTime);
-        }
-        
         void addLaunchCount(String comp) {
             TimeStats times = mLaunchTimes.get(comp);
             if (times == null) {
@@ -225,7 +231,7 @@
             }
             times.incCount();
         }
-        
+
         void addLaunchTime(String comp, int millis) {
             TimeStats times = mLaunchTimes.get(comp);
             if (times == null) {
@@ -244,9 +250,7 @@
             times.add(millis);
         }
 
-        void writeToParcel(Parcel out) {
-            out.writeInt(mLaunchCount);
-            out.writeLong(mUsageTime);
+        public void writeExtendedToParcel(Parcel out, int parcelableFlags) {
             final int numLaunchTimeStats = mLaunchTimes.size();
             out.writeInt(numLaunchTimeStats);
             for (int i=0; i<numLaunchTimeStats; i++) {
@@ -260,40 +264,43 @@
                 mFullyDrawnTimes.valueAt(i).writeToParcel(out);
             }
         }
-        
-        void clear() {
+
+        @Override
+        public boolean clearUsageTimes() {
             mLaunchTimes.clear();
             mFullyDrawnTimes.clear();
-            mLaunchCount = 0;
-            mUsageTime = 0;
+            return super.clearUsageTimes();
         }
     }
-    
+
+    static class ConfigUsageStatsExtended extends UsageStats.ConfigurationStats {
+        ConfigUsageStatsExtended(Configuration config) {
+            super(config);
+        }
+
+        ConfigUsageStatsExtended(Parcel in) {
+            super(in);
+        }
+    }
+
     UsageStatsService(String dir) {
-        mStats = new ArrayMap<String, PkgUsageStatsExtended>();
-        mLastResumeTimes = new ArrayMap<String, ArrayMap<String, Long>>();
-        mStatsLock = new Object();
-        mFileLock = new Object();
+        if (localLOGV) Slog.v(TAG, "UsageStatsService: " + dir);
         mDir = new File(dir);
-        mCal = Calendar.getInstance(TimeZone.getTimeZone("GMT+0"));
-        
         mDir.mkdir();
-        
-        // Remove any old usage files from previous versions.
+
+        // Remove any old /data/system/usagestats.* files from previous versions.
         File parentDir = mDir.getParentFile();
-        String fList[] = parentDir.list();
-        if (fList != null) {
+        String files[] = parentDir.list();
+        if (files != null) {
             String prefix = mDir.getName() + ".";
-            int i = fList.length;
-            while (i > 0) {
-                i--;
-                if (fList[i].startsWith(prefix)) {
-                    Slog.i(TAG, "Deleting old usage file: " + fList[i]);
-                    (new File(parentDir, fList[i])).delete();
+            for (String file : files) {
+                if (file.startsWith(prefix)) {
+                    Slog.i(TAG, "Deleting old usage file: " + file);
+                    (new File(parentDir, file)).delete();
                 }
             }
         }
-        
+
         // Update current stats which are binned by date
         mFileLeaf = getCurrentDateStr(FILE_PREFIX);
         mFile = new File(mDir, mFileLeaf);
@@ -310,11 +317,11 @@
      */
     private String getCurrentDateStr(String prefix) {
         StringBuilder sb = new StringBuilder();
+        if (prefix != null) {
+            sb.append(prefix);
+        }
         synchronized (mCal) {
             mCal.setTimeInMillis(System.currentTimeMillis());
-            if (prefix != null) {
-                sb.append(prefix);
-            }
             sb.append(mCal.get(Calendar.YEAR));
             int mm = mCal.get(Calendar.MONTH) - Calendar.JANUARY +1;
             if (mm < 10) {
@@ -329,17 +336,20 @@
         }
         return sb.toString();
     }
-    
+
     private Parcel getParcelForFile(File file) throws IOException {
         FileInputStream stream = new FileInputStream(file);
-        byte[] raw = readFully(stream);
-        Parcel in = Parcel.obtain();
-        in.unmarshall(raw, 0, raw.length);
-        in.setDataPosition(0);
-        stream.close();
-        return in;
+        try {
+            byte[] raw = readFully(stream);
+            Parcel in = Parcel.obtain();
+            in.unmarshall(raw, 0, raw.length);
+            in.setDataPosition(0);
+            return in;
+        } finally {
+            stream.close();
+        }
     }
-    
+
     private void readStatsFromFile() {
         File newFile = mFile;
         synchronized (mFileLock) {
@@ -356,38 +366,30 @@
             }
         }
     }
-    
+
     private void readStatsFLOCK(File file) throws IOException {
         Parcel in = getParcelForFile(file);
         int vers = in.readInt();
-        if (vers != VERSION) {
-            Slog.w(TAG, "Usage stats version changed; dropping");
+        if (vers != VERSION) {  // vers will be 0 if the parcel file was empty
+            Slog.w(TAG, "Usage stats version of " + file + " changed from " + vers + " to "
+                   + VERSION + "; dropping");
             return;
         }
-        int N = in.readInt();
-        while (N > 0) {
-            N--;
-            String pkgName = in.readString();
-            if (pkgName == null) {
-                break;
-            }
-            if (localLOGV) Slog.v(TAG, "Reading package #" + N + ": " + pkgName);
-            PkgUsageStatsExtended pus = new PkgUsageStatsExtended(in);
-            synchronized (mStatsLock) {
-                mStats.put(pkgName, pus);
-            }
+        LocalUsageStats stats = new LocalUsageStats(in, true);
+        synchronized (mStatsLock) {
+            mStats = stats;
         }
     }
 
     private void readHistoryStatsFromFile() {
         synchronized (mFileLock) {
             if (mHistoryFile.getBaseFile().exists()) {
-                readHistoryStatsFLOCK(mHistoryFile);
+                readHistoryStatsFLOCK();
             }
         }
     }
 
-    private void readHistoryStatsFLOCK(AtomicFile file) {
+    private void readHistoryStatsFLOCK() {
         FileInputStream fis = null;
         try {
             fis = mHistoryFile.openRead();
@@ -419,12 +421,9 @@
                                 try {
                                     long lastResumeTime = Long.parseLong(lastResumeTimeStr);
                                     synchronized (mStatsLock) {
-                                        ArrayMap<String, Long> lrt = mLastResumeTimes.get(pkg);
-                                        if (lrt == null) {
-                                            lrt = new ArrayMap<String, Long>();
-                                            mLastResumeTimes.put(pkg, lrt);
-                                        }
-                                        lrt.put(comp, lastResumeTime);
+                                        PkgUsageStatsExtended pus = (PkgUsageStatsExtended)
+                                                mStats.getOrCreatePackageStats(pkg);
+                                        pus.componentResumeTimes.put(comp, lastResumeTime);
                                     }
                                 } catch (NumberFormatException e) {
                                 }
@@ -470,12 +469,12 @@
         }
         return fileList;
     }
-    
+
     private void checkFileLimitFLOCK() {
         // Get all usage stats output files
         ArrayList<String> fileList = getUsageStatsFileListFLOCK();
         if (fileList == null) {
-            // Strange but we dont have to delete any thing
+            // Empty /data/system/usagestats/ so we don't have anything to delete
             return;
         }
         int count = fileList.size();
@@ -543,6 +542,15 @@
             return;
         }
 
+        Parcel out = Parcel.obtain();
+        synchronized (mStatsLock) {
+            out.writeInt(VERSION);
+            mStats.writeExtendedToParcel(out, 0);
+            if (dayChanged) {
+                mStats.clearUsageTimes();
+            }
+        }
+
         synchronized (mFileLock) {
             // Get the most recent file
             mFileLeaf = getCurrentDateStr(FILE_PREFIX);
@@ -553,6 +561,7 @@
                 if (!backupFile.exists()) {
                     if (!mFile.renameTo(backupFile)) {
                         Slog.w(TAG, "Failed to persist new stats");
+                        out.recycle();
                         return;
                     }
                 } else {
@@ -562,21 +571,17 @@
 
             try {
                 // Write mStats to file
-                writeStatsFLOCK(mFile);
+                writeStatsFLOCK(mFile, out);
                 mLastWriteElapsedTime.set(currElapsedTime);
                 if (dayChanged) {
                     mLastWriteDay.set(curDay);
-                    // clear stats
-                    synchronized (mStats) {
-                        mStats.clear();
-                    }
                     mFile = new File(mDir, mFileLeaf);
                     checkFileLimitFLOCK();
                 }
 
                 if (dayChanged || forceWriteHistoryStats) {
-                    // Write history stats daily, or when forced (due to shutdown).
-                    writeHistoryStatsFLOCK(mHistoryFile);
+                    // Write history stats daily or when forced (due to shutdown) or when debugging.
+                    writeHistoryStatsFLOCK();
                 }
 
                 // Delete the backup file
@@ -590,17 +595,15 @@
                     backupFile.renameTo(mFile);
                 }
             }
+            out.recycle();
         }
         if (localLOGV) Slog.d(TAG, "Dumped usage stats.");
     }
 
-    private void writeStatsFLOCK(File file) throws IOException {
+    private void writeStatsFLOCK(File file, Parcel parcel) throws IOException {
         FileOutputStream stream = new FileOutputStream(file);
         try {
-            Parcel out = Parcel.obtain();
-            writeStatsToParcelFLOCK(out);
-            stream.write(out.marshall());
-            out.recycle();
+            stream.write(parcel.marshall());
             stream.flush();
         } finally {
             FileUtils.sync(stream);
@@ -608,29 +611,14 @@
         }
     }
 
-    private void writeStatsToParcelFLOCK(Parcel out) {
-        synchronized (mStatsLock) {
-            out.writeInt(VERSION);
-            Set<String> keys = mStats.keySet();
-            out.writeInt(keys.size());
-            for (String key : keys) {
-                PkgUsageStatsExtended pus = mStats.get(key);
-                out.writeString(key);
-                pus.writeToParcel(out);
-            }
-        }
-    }
-
     /** Filter out stats for any packages which aren't present anymore. */
     private void filterHistoryStats() {
         synchronized (mStatsLock) {
             IPackageManager pm = AppGlobals.getPackageManager();
-            for (int i=0; i<mLastResumeTimes.size(); i++) {
-                String pkg = mLastResumeTimes.keyAt(i);
+            for (int i=mStats.mPackages.size()-1; i>=0; i--) {
                 try {
-                    if (pm.getPackageUid(pkg, 0) < 0) {
-                        mLastResumeTimes.removeAt(i);
-                        i--;
+                    if (pm.getPackageUid(mStats.mPackages.valueAt(i).getPackageName(), 0) < 0) {
+                        mStats.mPackages.removeAt(i);
                     }
                 } catch (RemoteException e) {
                 }
@@ -638,20 +626,22 @@
         }
     }
 
-    private void writeHistoryStatsFLOCK(AtomicFile historyFile) {
+    private void writeHistoryStatsFLOCK() {
         FileOutputStream fos = null;
         try {
-            fos = historyFile.startWrite();
+            fos = mHistoryFile.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, "usage-history");
             synchronized (mStatsLock) {
-                for (int i=0; i<mLastResumeTimes.size(); i++) {
+                int NP = mStats.mPackages.size();
+                for (int i=0; i<NP; i++) {
+                    UsageStats.PackageStats ps = mStats.mPackages.valueAt(i);
                     out.startTag(null, "pkg");
-                    out.attribute(null, "name", mLastResumeTimes.keyAt(i));
-                    ArrayMap<String, Long> comp = mLastResumeTimes.valueAt(i);
+                    out.attribute(null, "name", ps.getPackageName());
+                    ArrayMap<String, Long> comp = ps.componentResumeTimes;
                     for (int j=0; j<comp.size(); j++) {
                         out.startTag(null, "comp");
                         out.attribute(null, "name", comp.keyAt(j));
@@ -664,11 +654,11 @@
             out.endTag(null, "usage-history");
             out.endDocument();
 
-            historyFile.finishWrite(fos);
+            mHistoryFile.finishWrite(fos);
         } catch (IOException e) {
             Slog.w(TAG,"Error writing history stats" + e);
             if (fos != null) {
-                historyFile.failWrite(fos);
+                mHistoryFile.failWrite(fos);
             }
         }
     }
@@ -678,6 +668,10 @@
         ServiceManager.addService(SERVICE_NAME, asBinder());
     }
 
+    public void systemReady() {
+        mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
+    }
+
     /**
      * Start watching packages to remove stats when a package is uninstalled.
      * May only be called when the package manager is ready.
@@ -687,7 +681,7 @@
             @Override
             public void onPackageRemovedAllUsers(String packageName, int uid) {
                 synchronized (mStatsLock) {
-                    mLastResumeTimes.remove(packageName);
+                    mStats.mPackages.remove(packageName);
                 }
             }
         };
@@ -711,7 +705,8 @@
         sService = asInterface(b);
         return sService;
     }
-    
+
+    @Override
     public void noteResumeComponent(ComponentName componentName) {
         enforceCallingPermission();
         String pkgName;
@@ -720,7 +715,7 @@
                     ((pkgName = componentName.getPackageName()) == null)) {
                 return;
             }
-            
+
             final boolean samePackage = pkgName.equals(mLastResumedPkg);
             if (mIsResumed) {
                 if (mLastResumedPkg != null) {
@@ -728,43 +723,36 @@
                     // to recover.
                     if (REPORT_UNEXPECTED) Slog.i(TAG, "Unexpected resume of " + pkgName
                             + " while already resumed in " + mLastResumedPkg);
-                    PkgUsageStatsExtended pus = mStats.get(mLastResumedPkg);
+                    PkgUsageStatsExtended pus = (PkgUsageStatsExtended)mStats.getPackageStats(
+                            mLastResumedPkg);
                     if (pus != null) {
-                        pus.updatePause();
+                        pus.pause();
                     }
                 }
             }
-            
+
             final boolean sameComp = samePackage
                     && componentName.getClassName().equals(mLastResumedComp);
-            
+
             mIsResumed = true;
             mLastResumedPkg = pkgName;
             mLastResumedComp = componentName.getClassName();
-            
+
             if (localLOGV) Slog.i(TAG, "started component:" + pkgName);
-            PkgUsageStatsExtended pus = mStats.get(pkgName);
-            if (pus == null) {
-                pus = new PkgUsageStatsExtended();
-                mStats.put(pkgName, pus);
-            }
-            pus.updateResume(mLastResumedComp, !samePackage);
+            PkgUsageStatsExtended pus = (PkgUsageStatsExtended)
+                    mStats.getOrCreatePackageStats(pkgName);
+            pus.resume(!samePackage);
             if (!sameComp) {
                 pus.addLaunchCount(mLastResumedComp);
             }
-
-            ArrayMap<String, Long> componentResumeTimes = mLastResumeTimes.get(pkgName);
-            if (componentResumeTimes == null) {
-                componentResumeTimes = new ArrayMap<String, Long>();
-                mLastResumeTimes.put(pkgName, componentResumeTimes);
-            }
-            componentResumeTimes.put(mLastResumedComp, System.currentTimeMillis());
+            pus.componentResumeTimes.put(mLastResumedComp, System.currentTimeMillis());
         }
     }
 
+    @Override
     public void notePauseComponent(ComponentName componentName) {
         enforceCallingPermission();
-        
+
         synchronized (mStatsLock) {
             String pkgName;
             if ((componentName == null) ||
@@ -777,22 +765,23 @@
                 return;
             }
             mIsResumed = false;
-            
+
             if (localLOGV) Slog.i(TAG, "paused component:"+pkgName);
-        
-            PkgUsageStatsExtended pus = mStats.get(pkgName);
+
+            PkgUsageStatsExtended pus = (PkgUsageStatsExtended)mStats.getPackageStats(pkgName);
             if (pus == null) {
                 // Weird some error here
                 Slog.i(TAG, "No package stats for pkg:"+pkgName);
                 return;
             }
-            pus.updatePause();
+            pus.pause();
         }
-        
+
         // Persist current data to file if needed.
         writeStatsToFile(false, false);
     }
-    
+
+    @Override
     public void noteLaunchTime(ComponentName componentName, int millis) {
         enforceCallingPermission();
         String pkgName;
@@ -800,18 +789,18 @@
                 ((pkgName = componentName.getPackageName()) == null)) {
             return;
         }
-        
+
         // Persist current data to file if needed.
         writeStatsToFile(false, false);
-        
+
         synchronized (mStatsLock) {
-            PkgUsageStatsExtended pus = mStats.get(pkgName);
+            PkgUsageStatsExtended pus = (PkgUsageStatsExtended)mStats.getPackageStats(pkgName);
             if (pus != null) {
                 pus.addLaunchTime(componentName.getClassName(), millis);
             }
         }
     }
-    
+
     public void noteFullyDrawnTime(ComponentName componentName, int millis) {
         enforceCallingPermission();
         String pkgName;
@@ -824,13 +813,29 @@
         writeStatsToFile(false, false);
 
         synchronized (mStatsLock) {
-            PkgUsageStatsExtended pus = mStats.get(pkgName);
+            PkgUsageStatsExtended pus = (PkgUsageStatsExtended)mStats.getPackageStats(pkgName);
             if (pus != null) {
                 pus.addFullyDrawnTime(componentName.getClassName(), millis);
             }
         }
     }
 
+    public void noteStartConfig(Configuration config) {
+        enforceCallingPermission();
+        synchronized (mStatsLock) {
+            config = new Configuration(config);
+            ConfigUsageStatsExtended cus = (ConfigUsageStatsExtended)
+                    mStats.getOrCreateConfigurationStats(config);
+            if (cus != mCurrentConfigStats) {
+                if (mCurrentConfigStats != null) {
+                    mCurrentConfigStats.stop();
+                }
+                cus.start();
+                mCurrentConfigStats = cus;
+            }
+        }
+    }
+
     public void enforceCallingPermission() {
         if (Binder.getCallingPid() == Process.myPid()) {
             return;
@@ -838,54 +843,74 @@
         mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
                 Binder.getCallingPid(), Binder.getCallingUid(), null);
     }
-    
-    public PkgUsageStats getPkgUsageStats(ComponentName componentName) {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.PACKAGE_USAGE_STATS, null);
+
+    @Override
+    public UsageStats.PackageStats getPkgUsageStats(String callingPkg,
+            ComponentName componentName) {
+        checkCallerPermission(callingPkg, "getPkgUsageStats");
         String pkgName;
         if ((componentName == null) ||
                 ((pkgName = componentName.getPackageName()) == null)) {
             return null;
         }
         synchronized (mStatsLock) {
-            PkgUsageStatsExtended pus = mStats.get(pkgName);
-            Map<String, Long> lastResumeTimes = mLastResumeTimes.get(pkgName);
-            if (pus == null && lastResumeTimes == null) {
+            PkgUsageStatsExtended pus = (PkgUsageStatsExtended)mStats.getPackageStats(pkgName);
+            if (pus == null) {
                 return null;
             }
-            int launchCount = pus != null ? pus.mLaunchCount : 0;
-            long usageTime = pus != null ? pus.mUsageTime : 0;
-            return new PkgUsageStats(pkgName, launchCount, usageTime, lastResumeTimes);
+            return new UsageStats.PackageStats(pus);
         }
     }
-    
-    public PkgUsageStats[] getAllPkgUsageStats() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.PACKAGE_USAGE_STATS, null);
+
+    @Override
+    public UsageStats.PackageStats[] getAllPkgUsageStats(String callingPkg) {
+        checkCallerPermission(callingPkg, "getAllPkgUsageStats");
         synchronized (mStatsLock) {
-            int size = mLastResumeTimes.size();
-            if (size <= 0) {
+            int NP = mStats.mPackages.size();
+            if (NP <= 0) {
                 return null;
             }
-            PkgUsageStats retArr[] = new PkgUsageStats[size];
-            for (int i=0; i<size; i++) {
-                String pkg = mLastResumeTimes.keyAt(i);
-                long usageTime = 0;
-                int launchCount = 0;
-
-                PkgUsageStatsExtended pus = mStats.get(pkg);
-                if (pus != null) {
-                    usageTime = pus.mUsageTime;
-                    launchCount = pus.mLaunchCount;
-                }
-                retArr[i] = new PkgUsageStats(pkg, launchCount, usageTime,
-                        mLastResumeTimes.valueAt(i));
+            UsageStats.PackageStats retArr[] = new UsageStats.PackageStats[NP];
+            for (int p=0; p<NP; p++) {
+                UsageStats.PackageStats ps = mStats.mPackages.valueAt(p);
+                retArr[p] = new UsageStats.PackageStats(ps);
             }
             return retArr;
         }
     }
-    
-    static byte[] readFully(FileInputStream stream) throws java.io.IOException {
+
+    @Override
+    public ParcelableParcel getCurrentStats(String callingPkg) {
+        checkCallerPermission(callingPkg, "getCurrentStats");
+        synchronized (mStatsLock) {
+            ParcelableParcel out = new ParcelableParcel(null);
+            mStats.writeToParcel(out.getParcel(), 0);
+            return out;
+        }
+    }
+
+    private void checkCallerPermission(String callingPkg, String callingOp) {
+        // Because the permission for this is system-only, its use with
+        // app ops is a little different: the op is disabled by default,
+        // and enabling it allows apps to get access even if they don't
+        // hold the permission.
+        int mode = mAppOps.noteOpNoThrow(AppOpsManager.OP_GET_USAGE_STATS, Binder.getCallingUid(),
+                callingPkg);
+        if (mode == AppOpsManager.MODE_ALLOWED) {
+            return;
+        } else if (mode != AppOpsManager.MODE_IGNORED) {
+            if (mContext.checkCallingOrSelfPermission(
+                    android.Manifest.permission.PACKAGE_USAGE_STATS)
+                    == PackageManager.PERMISSION_GRANTED) {
+                return;
+            }
+        }
+
+        String msg = "Package " + callingPkg + " not allowed to call " + callingOp;
+        throw new SecurityException(msg);
+    }
+
+    static byte[] readFully(FileInputStream stream) throws IOException {
         int pos = 0;
         int avail = stream.available();
         byte[] data = new byte[avail];
@@ -903,7 +928,7 @@
             }
         }
     }
-    
+
     private void collectDumpInfoFLOCK(PrintWriter pw, boolean isCompactOutput,
             boolean deleteAfterPrint, HashSet<String> packages) {
         List<String> fileList = getUsageStatsFileListFLOCK();
@@ -932,15 +957,12 @@
                     // Delete old file after collecting info only for checkin requests
                     dFile.delete();
                 }
-            } catch (FileNotFoundException e) {
-                Slog.w(TAG, "Failed with "+e+" when collecting dump info from file : " + file);
-                return;
             } catch (IOException e) {
                 Slog.w(TAG, "Failed with "+e+" when collecting dump info from file : "+file);
-            }      
+            }
         }
     }
-    
+
     private void collectDumpInfoFromParcelFLOCK(Parcel in, PrintWriter pw,
             String date, boolean isCompactOutput, HashSet<String> packages) {
         StringBuilder sb = new StringBuilder(512);
@@ -951,73 +973,78 @@
         } else {
             sb.append("Date: ");
         }
-        
+
         sb.append(date);
-        
+
         int vers = in.readInt();
         if (vers != VERSION) {
             sb.append(" (old data version)");
             pw.println(sb.toString());
             return;
         }
-        
+
+        final LocalUsageStats stats = new LocalUsageStats(in, true);
+        final long time = SystemClock.elapsedRealtime();
+
         pw.println(sb.toString());
-        int N = in.readInt();
-        
-        while (N > 0) {
-            N--;
-            String pkgName = in.readString();
-            if (pkgName == null) {
-                break;
-            }
+        int NP = stats.mPackages.size();
+        for (int p=0; p<NP; p++) {
+            PkgUsageStatsExtended pus = (PkgUsageStatsExtended)stats.mPackages.valueAt(p);
             sb.setLength(0);
-            PkgUsageStatsExtended pus = new PkgUsageStatsExtended(in);
-            if (packages != null && !packages.contains(pkgName)) {
+            if (packages != null && !packages.contains(pus.getPackageName())) {
                 // This package has not been requested -- don't print
                 // anything for it.
             } else if (isCompactOutput) {
                 sb.append("P:");
-                sb.append(pkgName);
+                sb.append(pus.getPackageName());
                 sb.append(',');
-                sb.append(pus.mLaunchCount);
+                sb.append(pus.getLaunchCount());
                 sb.append(',');
-                sb.append(pus.mUsageTime);
+                sb.append(pus.getUsageTime(time));
                 sb.append('\n');
                 final int NLT = pus.mLaunchTimes.size();
                 for (int i=0; i<NLT; i++) {
-                    sb.append("A:");
+                    sb.append("L:");
                     String activity = pus.mLaunchTimes.keyAt(i);
                     sb.append(activity);
                     TimeStats times = pus.mLaunchTimes.valueAt(i);
                     sb.append(',');
-                    sb.append(times.count);
+                    sb.append(times.mCount);
                     for (int j=0; j<NUM_LAUNCH_TIME_BINS; j++) {
                         sb.append(",");
-                        sb.append(times.times[j]);
+                        sb.append(times.mTimes[j]);
                     }
                     sb.append('\n');
                 }
                 final int NFDT = pus.mFullyDrawnTimes.size();
                 for (int i=0; i<NFDT; i++) {
-                    sb.append("A:");
+                    sb.append("D:");
                     String activity = pus.mFullyDrawnTimes.keyAt(i);
                     sb.append(activity);
                     TimeStats times = pus.mFullyDrawnTimes.valueAt(i);
                     for (int j=0; j<NUM_LAUNCH_TIME_BINS; j++) {
                         sb.append(",");
-                        sb.append(times.times[j]);
+                        sb.append(times.mTimes[j]);
                     }
                     sb.append('\n');
                 }
+                final int NC = pus.componentResumeTimes.size();
+                for (int c=0; c<NC; c++) {
+                    pw.print("R:"); pw.print(pus.componentResumeTimes.keyAt(c)); pw.print(",");
+                    pw.println(pus.componentResumeTimes.valueAt(c));
+                }
 
             } else {
                 sb.append("  ");
-                sb.append(pkgName);
-                sb.append(": ");
-                sb.append(pus.mLaunchCount);
-                sb.append(" times, ");
-                sb.append(pus.mUsageTime);
-                sb.append(" ms");
+                sb.append(pus.getPackageName());
+                if (pus.getLaunchCount() != 0 || pus.getUsageTime(time) != 0) {
+                    sb.append(": ");
+                    sb.append(pus.getLaunchCount());
+                    sb.append(" times, ");
+                    TimeUtils.formatDuration(pus.getUsageTime(time), sb);
+                } else {
+                    sb.append(":");
+                }
                 sb.append('\n');
                 final int NLT = pus.mLaunchTimes.size();
                 for (int i=0; i<NLT; i++) {
@@ -1025,26 +1052,26 @@
                     sb.append(pus.mLaunchTimes.keyAt(i));
                     TimeStats times = pus.mLaunchTimes.valueAt(i);
                     sb.append(": ");
-                    sb.append(times.count);
+                    sb.append(times.mCount);
                     sb.append(" starts");
                     int lastBin = 0;
                     for (int j=0; j<NUM_LAUNCH_TIME_BINS-1; j++) {
-                        if (times.times[j] != 0) {
+                        if (times.mTimes[j] != 0) {
                             sb.append(", ");
                             sb.append(lastBin);
                             sb.append('-');
                             sb.append(LAUNCH_TIME_BINS[j]);
                             sb.append("ms=");
-                            sb.append(times.times[j]);
+                            sb.append(times.mTimes[j]);
                         }
                         lastBin = LAUNCH_TIME_BINS[j];
                     }
-                    if (times.times[NUM_LAUNCH_TIME_BINS-1] != 0) {
+                    if (times.mTimes[NUM_LAUNCH_TIME_BINS-1] != 0) {
                         sb.append(", ");
                         sb.append(">=");
                         sb.append(lastBin);
                         sb.append("ms=");
-                        sb.append(times.times[NUM_LAUNCH_TIME_BINS-1]);
+                        sb.append(times.mTimes[NUM_LAUNCH_TIME_BINS-1]);
                     }
                     sb.append('\n');
                 }
@@ -1057,7 +1084,7 @@
                     boolean needComma = false;
                     int lastBin = 0;
                     for (int j=0; j<NUM_LAUNCH_TIME_BINS-1; j++) {
-                        if (times.times[j] != 0) {
+                        if (times.mTimes[j] != 0) {
                             if (needComma) {
                                 sb.append(", ");
                             } else {
@@ -1067,27 +1094,67 @@
                             sb.append('-');
                             sb.append(LAUNCH_TIME_BINS[j]);
                             sb.append("ms=");
-                            sb.append(times.times[j]);
+                            sb.append(times.mTimes[j]);
                         }
                         lastBin = LAUNCH_TIME_BINS[j];
                     }
-                    if (times.times[NUM_LAUNCH_TIME_BINS-1] != 0) {
+                    if (times.mTimes[NUM_LAUNCH_TIME_BINS-1] != 0) {
                         if (needComma) {
                             sb.append(", ");
                         }
                         sb.append(">=");
                         sb.append(lastBin);
                         sb.append("ms=");
-                        sb.append(times.times[NUM_LAUNCH_TIME_BINS-1]);
+                        sb.append(times.mTimes[NUM_LAUNCH_TIME_BINS-1]);
                     }
                     sb.append('\n');
                 }
+                final int NC = pus.componentResumeTimes.size();
+                for (int c=0; c<NC; c++) {
+                    sb.append("    ");
+                    sb.append(pus.componentResumeTimes.keyAt(c));
+                    sb.append(" last resumed ");
+                    sb.append(DateFormat.format("yyyy-MM-dd-HH-mm-ss",
+                            pus.componentResumeTimes.valueAt(c)).toString());
+                    sb.append('\n');
+                }
             }
-            
+
             pw.write(sb.toString());
         }
+        if (packages == null) {
+            int NC = stats.mConfigurations.size();
+            for (int c=0; c<NC; c++) {
+                ConfigUsageStatsExtended cus
+                        = (ConfigUsageStatsExtended)stats.mConfigurations.valueAt(c);
+                sb.setLength(0);
+                if (isCompactOutput) {
+                    sb.append("C:"); sb.append(cus.getConfiguration().toString());
+                    sb.append(","); sb.append(cus.getUsageCount()); sb.append(",");
+                    sb.append(cus.getUsageTime(time));
+                } else {
+                    sb.append("  ");
+                    sb.append(cus.getConfiguration().toString());
+                    sb.append(":\n");
+                    if (cus.getUsageCount() != 0 || cus.getUsageTime(time) != 0) {
+                        sb.append("    Used ");
+                        sb.append(cus.getUsageCount());
+                        sb.append(" times, ");
+                        TimeUtils.formatDuration(cus.getUsageTime(time), sb);
+                        sb.append("\n");
+                    }
+                    if (cus.getLastUsedTime() > 0) {
+                        sb.append("    Last used: ");
+                        sb.append(DateFormat.format("yyyy-MM-dd-HH-mm-ss",
+                                cus.getLastUsedTime()).toString());
+                        sb.append("\n");
+                    }
+                }
+                pw.write(sb.toString());
+            }
+        }
     }
-    
+
     /**
      * Searches array of arguments for the specified string
      * @param args array of argument strings
@@ -1104,7 +1171,7 @@
         }
         return false;
     }
-    
+
     /**
      * Searches array of arguments for the specified string's data
      * @param args array of argument strings
@@ -1123,11 +1190,11 @@
         }
         return null;
     }
-    
-    @Override
+
     /*
-     * The data persisted to file is parsed and the stats are computed. 
+     * The data persisted to file is parsed and the stats are computed.
      */
+    @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingPermission(android.Manifest.permission.DUMP)
                 != PackageManager.PERMISSION_GRANTED) {
@@ -1141,23 +1208,23 @@
         final boolean isCompactOutput = isCheckinRequest || scanArgs(args, "-c");
         final boolean deleteAfterPrint = isCheckinRequest || scanArgs(args, "-d");
         final String rawPackages = scanArgsData(args, "--packages");
-        
+
         // Make sure the current stats are written to the file.  This
         // doesn't need to be done if we are deleting files after printing,
-        // since it that case we won't print the current stats.
+        // since in that case we won't print the current stats.
         if (!deleteAfterPrint) {
             writeStatsToFile(true, false);
         }
-        
+
         HashSet<String> packages = null;
         if (rawPackages != null) {
             if (!"*".equals(rawPackages)) {
                 // A * is a wildcard to show all packages.
                 String[] names = rawPackages.split(",");
+                if (names.length != 0) {
+                    packages = new HashSet<String>();
+                }
                 for (String n : names) {
-                    if (packages == null) {
-                        packages = new HashSet<String>();
-                    }
                     packages.add(n);
                 }
             }
@@ -1167,10 +1234,9 @@
             Slog.w(TAG, "Checkin without packages");
             return;
         }
-        
+
         synchronized (mFileLock) {
             collectDumpInfoFLOCK(pw, isCompactOutput, deleteAfterPrint, packages);
         }
     }
-
 }
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index f47d66d..15e3e89 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -23,6 +23,7 @@
 import android.content.BroadcastReceiver;
 import android.content.ClipData;
 import android.content.ClipDescription;
+import android.content.ContentProvider;
 import android.content.IClipboard;
 import android.content.IOnPrimaryClipChangedListener;
 import android.content.Context;
@@ -255,7 +256,8 @@
         long ident = Binder.clearCallingIdentity();
         try {
             // This will throw SecurityException for us.
-            mAm.checkGrantUriPermission(uid, null, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
+            mAm.checkGrantUriPermission(uid, null, ContentProvider.getUriWithoutUserId(uri),
+                    Intent.FLAG_GRANT_READ_URI_PERMISSION, resolveUserId(uri, uid));
         } catch (RemoteException e) {
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -282,8 +284,10 @@
     private final void grantUriLocked(Uri uri, String pkg) {
         long ident = Binder.clearCallingIdentity();
         try {
-            mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(), pkg, uri,
-                    Intent.FLAG_GRANT_READ_URI_PERMISSION);
+            mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(), pkg,
+                    ContentProvider.getUriWithoutUserId(uri),
+                    Intent.FLAG_GRANT_READ_URI_PERMISSION,
+                    resolveUserId(uri, Process.myUid()));
         } catch (RemoteException e) {
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -331,9 +335,10 @@
     private final void revokeUriLocked(Uri uri) {
         long ident = Binder.clearCallingIdentity();
         try {
-            mAm.revokeUriPermissionFromOwner(mPermissionOwner, uri,
-                    Intent.FLAG_GRANT_READ_URI_PERMISSION
-                    | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+            mAm.revokeUriPermissionFromOwner(mPermissionOwner,
+                    ContentProvider.getUriWithoutUserId(uri),
+                    Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+                    resolveUserId(uri, Process.myUid()));
         } catch (RemoteException e) {
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -361,4 +366,8 @@
             revokeItemLocked(clipboard.primaryClip.getItemAt(i));
         }
     }
+
+    private final int resolveUserId(Uri uri, int uid) {
+        return ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(uid));
+    }
 }
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index a15d678..3884ab0 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -25,11 +25,12 @@
 import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
-import android.net.NetworkStateTracker;
+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;
@@ -45,15 +46,18 @@
     private Context mContext;
     private INetworkManagementService mNMService;
     private IConnectivityManager mConnService;
-    private NetworkStateTracker mTracker;
-    private Handler mHandler;
-
     // Whether we started clatd and expect it to be running.
     private boolean mIsStarted;
     // Whether the clatd interface exists (i.e., clatd is running).
     private boolean mIsRunning;
     // The LinkProperties of the clat interface.
     private LinkProperties mLP;
+    // Current LinkProperties of the network.  Includes mLP as a stacked link when clat is active.
+    private LinkProperties mBaseLP;
+    // ConnectivityService Handler for LinkProperties updates.
+    private Handler mHandler;
+    // Marker to connote which network we're augmenting.
+    private Messenger mNetworkMessenger;
 
     // This must match the interface name in clatd.conf.
     private static final String CLAT_INTERFACE_NAME = "clat4";
@@ -73,14 +77,13 @@
     }
 
     /**
-     * Determines whether an interface requires clat.
-     * @param netType the network type (one of the
-     *   android.net.ConnectivityManager.TYPE_* constants)
-     * @param tracker the NetworkStateTracker corresponding to the network type.
-     * @return true if the interface requires clat, false otherwise.
+     * Determines whether a network requires clat.
+     * @param network the NetworkAgentInfo corresponding to the network.
+     * @return true if the network requires clat, false otherwise.
      */
-    public boolean requiresClat(int netType, NetworkStateTracker tracker) {
-        LinkProperties lp = tracker.getLinkProperties();
+    public boolean requiresClat(NetworkAgentInfo network) {
+        int netType = network.networkInfo.getType();
+        LinkProperties lp = network.linkProperties;
         // Only support clat on mobile for now.
         Slog.d(TAG, "requiresClat: netType=" + netType + ", hasIPv4Address=" +
                lp.hasIPv4Address());
@@ -95,13 +98,18 @@
      * Starts the clat daemon.
      * @param lp The link properties of the interface to start clatd on.
      */
-    public void startClat(NetworkStateTracker tracker) {
+    public void startClat(NetworkAgentInfo network) {
+        if (mNetworkMessenger != null && mNetworkMessenger != network.messenger) {
+            Slog.e(TAG, "startClat: too many networks requesting clat");
+            return;
+        }
+        mNetworkMessenger = network.messenger;
+        LinkProperties lp = network.linkProperties;
+        mBaseLP = new LinkProperties(lp);
         if (mIsStarted) {
             Slog.e(TAG, "startClat: already started");
             return;
         }
-        mTracker = tracker;
-        LinkProperties lp = mTracker.getLinkProperties();
         String iface = lp.getInterfaceName();
         Slog.i(TAG, "Starting clatd on " + iface + ", lp=" + lp);
         try {
@@ -125,7 +133,8 @@
             }
             mIsStarted = false;
             mIsRunning = false;
-            mTracker = null;
+            mNetworkMessenger = null;
+            mBaseLP = null;
             mLP.clear();
         } else {
             Slog.e(TAG, "stopClat: already stopped");
@@ -140,6 +149,14 @@
         return mIsRunning;
     }
 
+    private void updateConnectivityService() {
+        Message msg = mHandler.obtainMessage(
+            NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED, mBaseLP);
+        msg.replyTo = mNetworkMessenger;
+        Slog.i(TAG, "sending message to ConnectivityService: " + msg);
+        msg.sendToTarget();
+    }
+
     @Override
     public void interfaceAdded(String iface) {
         if (iface.equals(CLAT_INTERFACE_NAME)) {
@@ -165,19 +182,12 @@
                                                       clatAddress.getAddress(), iface);
                 mLP.addRoute(ipv4Default);
                 mLP.addLinkAddress(clatAddress);
-                mTracker.addStackedLink(mLP);
-                Slog.i(TAG, "Adding stacked link. tracker LP: " +
-                       mTracker.getLinkProperties());
+                mBaseLP.addStackedLink(mLP);
+                Slog.i(TAG, "Adding stacked link. tracker LP: " + mBaseLP);
+                updateConnectivityService();
             } catch(RemoteException e) {
                 Slog.e(TAG, "Error getting link properties: " + e);
             }
-
-            // Inform ConnectivityService that things have changed.
-            Message msg = mHandler.obtainMessage(
-                NetworkStateTracker.EVENT_CONFIGURATION_CHANGED,
-                mTracker.getNetworkInfo());
-            Slog.i(TAG, "sending message to ConnectivityService: " + msg);
-            msg.sendToTarget();
         }
     }
 
@@ -192,8 +202,9 @@
             Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME +
                    " removed, mIsRunning = " + mIsRunning + " -> false");
             mIsRunning = false;
-            mTracker.removeStackedLink(mLP);
+            mBaseLP.removeStackedLink(mLP);
             mLP.clear();
+            updateConnectivityService();
             Slog.i(TAG, "mLP = " + mLP);
         }
     }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
new file mode 100644
index 0000000..8102591
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import android.content.Context;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.NetworkRequest;
+import android.os.Handler;
+import android.os.Messenger;
+import android.util.SparseArray;
+
+import com.android.internal.util.AsyncChannel;
+import com.android.server.connectivity.NetworkMonitor;
+
+import java.util.ArrayList;
+
+/**
+ * A bag class used by ConnectivityService for holding a collection of most recent
+ * information published by a particular NetworkAgent as well as the
+ * AsyncChannel/messenger for reaching that NetworkAgent and lists of NetworkRequests
+ * interested in using it.
+ */
+public class NetworkAgentInfo {
+    public NetworkInfo networkInfo;
+    public final Network network;
+    public LinkProperties linkProperties;
+    public NetworkCapabilities networkCapabilities;
+    public int currentScore;
+    public final NetworkMonitor networkMonitor;
+
+
+    // The list of NetworkRequests being satisfied by this Network.
+    public final SparseArray<NetworkRequest> networkRequests = new SparseArray<NetworkRequest>();
+    public final ArrayList<NetworkRequest> networkLingered = new ArrayList<NetworkRequest>();
+
+    public final Messenger messenger;
+    public final AsyncChannel asyncChannel;
+
+    public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, int netId, NetworkInfo info,
+            LinkProperties lp, NetworkCapabilities nc, int score, Context context,
+            Handler handler) {
+        this.messenger = messenger;
+        asyncChannel = ac;
+        network = new Network(netId);
+        networkInfo = info;
+        linkProperties = lp;
+        networkCapabilities = nc;
+        currentScore = score;
+        networkMonitor = new NetworkMonitor(context, handler, this);
+    }
+
+    public String toString() {
+        return "NetworkAgentInfo{ ni{" + networkInfo + "}  network{" +
+                network + "}  lp{" +
+                linkProperties + "}  nc{" +
+                networkCapabilities + "}  Score{" + currentScore + "} }";
+    }
+
+    public String name() {
+        return "NetworkAgentInfo [" + networkInfo.getTypeName() + " (" +
+                networkInfo.getSubtypeName() + ")]";
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
new file mode 100644
index 0000000..47789b1
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.connectivity;
+
+import android.content.Context;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemProperties;
+import android.provider.Settings;
+
+import com.android.internal.util.Protocol;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+import com.android.server.connectivity.NetworkAgentInfo;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.URL;
+
+/**
+ * {@hide}
+ */
+public class NetworkMonitor extends StateMachine {
+    private static final boolean DBG = true;
+    private static final String TAG = "NetworkMonitor";
+    private static final String DEFAULT_SERVER = "clients3.google.com";
+    private static final int SOCKET_TIMEOUT_MS = 10000;
+
+    private static final int BASE = Protocol.BASE_NETWORK_MONITOR;
+
+    /**
+     * Inform NetworkMonitor that their network is connected.
+     * Initiates Network Validation.
+     */
+    public static final int CMD_NETWORK_CONNECTED = BASE + 1;
+
+    /**
+     * Inform ConnectivityService that the network is validated.
+     * obj = NetworkAgentInfo
+     */
+    public static final int EVENT_NETWORK_VALIDATED = BASE + 2;
+
+    /**
+     * Inform NetworkMonitor to linger a network.  The Monitor should
+     * start a timer and/or start watching for zero live connections while
+     * moving towards LINGER_COMPLETE.  After the Linger period expires
+     * (or other events mark the end of the linger state) the LINGER_COMPLETE
+     * event should be sent and the network will be shut down.  If a
+     * CMD_NETWORK_CONNECTED happens before the LINGER completes
+     * it indicates further desire to keep the network alive and so
+     * the LINGER is aborted.
+     */
+    public static final int CMD_NETWORK_LINGER = BASE + 3;
+
+    /**
+     * Message to self indicating linger delay has expired.
+     * arg1 = Token to ignore old messages.
+     */
+    private static final int CMD_LINGER_EXPIRED = BASE + 4;
+
+    /**
+     * Inform ConnectivityService that the network LINGER period has
+     * expired.
+     * obj = NetworkAgentInfo
+     */
+    public static final int EVENT_NETWORK_LINGER_COMPLETE = BASE + 5;
+
+    /**
+     * Message to self indicating it's time to check for a captive portal again.
+     * TODO - Remove this once broadcast intents are used to communicate with
+     * apps to log into captive portals.
+     * arg1 = Token to ignore old messages.
+     */
+    private static final int CMD_CAPTIVE_PORTAL_REEVALUATE = BASE + 6;
+
+    /**
+     * Message to self indicating it's time to evaluate a network's connectivity.
+     * arg1 = Token to ignore old messages.
+     */
+    private static final int CMD_REEVALUATE = BASE + 7;
+
+    /**
+     * Message to self indicating network evaluation is complete.
+     * arg1 = Token to ignore old messages.
+     * arg2 = HTTP response code of network evaluation.
+     */
+    private static final int EVENT_REEVALUATION_COMPLETE = BASE + 8;
+
+    /**
+     * Inform NetworkMonitor that the network has disconnected.
+     */
+    public static final int CMD_NETWORK_DISCONNECTED = BASE + 9;
+
+    /**
+     * Force evaluation even if it has succeeded in the past.
+     */
+    public static final int CMD_FORCE_REEVALUATION = BASE + 10;
+
+    private static final String LINGER_DELAY_PROPERTY = "persist.netmon.linger";
+    // Default to 30s linger time-out.
+    private static final int DEFAULT_LINGER_DELAY_MS = 30000;
+    private final int mLingerDelayMs;
+    private int mLingerToken = 0;
+
+    private static final int CAPTIVE_PORTAL_REEVALUATE_DELAY_MS = 5000;
+    private int mCaptivePortalReevaluateToken = 0;
+
+    // Negative values disable reevaluation.
+    private static final String REEVALUATE_DELAY_PROPERTY = "persist.netmon.reeval_delay";
+    // Default to 5s reevaluation delay.
+    private static final int DEFAULT_REEVALUATE_DELAY_MS = 5000;
+    private final int mReevaluateDelayMs;
+    private int mReevaluateToken = 0;
+
+    private final Context mContext;
+    private final Handler mConnectivityServiceHandler;
+    private final NetworkAgentInfo mNetworkAgentInfo;
+
+    private String mServer;
+    private boolean mIsCaptivePortalCheckEnabled = false;
+
+    private State mDefaultState = new DefaultState();
+    private State mOfflineState = new OfflineState();
+    private State mValidatedState = new ValidatedState();
+    private State mEvaluatingState = new EvaluatingState();
+    private State mCaptivePortalState = new CaptivePortalState();
+    private State mLingeringState = new LingeringState();
+
+    public NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo) {
+        // Add suffix indicating which NetworkMonitor we're talking about.
+        super(TAG + networkAgentInfo.name());
+
+        mContext = context;
+        mConnectivityServiceHandler = handler;
+        mNetworkAgentInfo = networkAgentInfo;
+
+        addState(mDefaultState);
+        addState(mOfflineState, mDefaultState);
+        addState(mValidatedState, mDefaultState);
+        addState(mEvaluatingState, mDefaultState);
+        addState(mCaptivePortalState, mDefaultState);
+        addState(mLingeringState, mDefaultState);
+        setInitialState(mOfflineState);
+
+        mServer = Settings.Global.getString(mContext.getContentResolver(),
+                Settings.Global.CAPTIVE_PORTAL_SERVER);
+        if (mServer == null) mServer = DEFAULT_SERVER;
+
+        mLingerDelayMs = SystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);
+        mReevaluateDelayMs = SystemProperties.getInt(REEVALUATE_DELAY_PROPERTY,
+                DEFAULT_REEVALUATE_DELAY_MS);
+
+        // TODO: Enable this when we're ready.
+        // mIsCaptivePortalCheckEnabled = Settings.Global.getInt(mContext.getContentResolver(),
+        //        Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 1) == 1;
+
+        start();
+    }
+
+    private class DefaultState extends State {
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) log(getName() + message.toString());
+            switch (message.what) {
+                case CMD_NETWORK_LINGER:
+                    if (DBG) log("Lingering");
+                    transitionTo(mLingeringState);
+                    break;
+                case CMD_NETWORK_CONNECTED:
+                    if (DBG) log("Connected");
+                    transitionTo(mEvaluatingState);
+                    break;
+                case CMD_NETWORK_DISCONNECTED:
+                    if (DBG) log("Disconnected");
+                    transitionTo(mOfflineState);
+                    break;
+                case CMD_FORCE_REEVALUATION:
+                    if (DBG) log("Forcing reevaluation");
+                    transitionTo(mEvaluatingState);
+                    break;
+                default:
+                    break;
+            }
+            return HANDLED;
+        }
+    }
+
+    private class OfflineState extends State {
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) log(getName() + message.toString());
+            return NOT_HANDLED;
+        }
+    }
+
+    private class ValidatedState extends State {
+        @Override
+        public void enter() {
+            if (DBG) log("Validated");
+            mConnectivityServiceHandler.sendMessage(
+                    obtainMessage(EVENT_NETWORK_VALIDATED, mNetworkAgentInfo));
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) log(getName() + message.toString());
+            switch (message.what) {
+                case CMD_NETWORK_CONNECTED:
+                    transitionTo(mValidatedState);
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            return HANDLED;
+        }
+    }
+
+    private class EvaluatingState extends State {
+        private class EvaluateInternetConnectivity extends Thread {
+            private int mToken;
+            EvaluateInternetConnectivity(int token) {
+                mToken = token;
+            }
+            public void run() {
+                sendMessage(EVENT_REEVALUATION_COMPLETE, mToken, isCaptivePortal());
+            }
+        }
+
+        @Override
+        public void enter() {
+            sendMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) log(getName() + message.toString());
+            switch (message.what) {
+                case CMD_REEVALUATE:
+                    if (message.arg1 != mReevaluateToken)
+                        break;
+                    // If network provides no internet connectivity adjust evaluation.
+                    if (mNetworkAgentInfo.networkCapabilities.hasCapability(
+                            NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
+                        // TODO: Try to verify something works.  Do all gateways respond to pings?
+                        transitionTo(mValidatedState);
+                    }
+                    // Kick off a thread to perform internet connectivity evaluation.
+                    Thread thread = new EvaluateInternetConnectivity(mReevaluateToken);
+                    thread.run();
+                    break;
+                case EVENT_REEVALUATION_COMPLETE:
+                    if (message.arg1 != mReevaluateToken)
+                        break;
+                    int httpResponseCode = message.arg2;
+                    if (httpResponseCode == 204) {
+                        transitionTo(mValidatedState);
+                    } else if (httpResponseCode >= 200 && httpResponseCode <= 399) {
+                        transitionTo(mCaptivePortalState);
+                    } else {
+                        if (mReevaluateDelayMs >= 0) {
+                            Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
+                            sendMessageDelayed(msg, mReevaluateDelayMs);
+                        }
+                    }
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            return HANDLED;
+        }
+    }
+
+    // TODO: Until we add an intent from the app handling captive portal
+    // login we'll just re-evaluate after a delay.
+    private class CaptivePortalState extends State {
+        @Override
+        public void enter() {
+            Message message = obtainMessage(CMD_CAPTIVE_PORTAL_REEVALUATE,
+                    ++mCaptivePortalReevaluateToken, 0);
+            sendMessageDelayed(message, CAPTIVE_PORTAL_REEVALUATE_DELAY_MS);
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) log(getName() + message.toString());
+            switch (message.what) {
+                case CMD_CAPTIVE_PORTAL_REEVALUATE:
+                    if (message.arg1 != mCaptivePortalReevaluateToken)
+                        break;
+                    transitionTo(mEvaluatingState);
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            return HANDLED;
+        }
+    }
+
+    private class LingeringState extends State {
+        @Override
+        public void enter() {
+            Message message = obtainMessage(CMD_LINGER_EXPIRED, ++mLingerToken, 0);
+            sendMessageDelayed(message, mLingerDelayMs);
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) log(getName() + message.toString());
+            switch (message.what) {
+                case CMD_NETWORK_CONNECTED:
+                    // Go straight to active as we've already evaluated.
+                    transitionTo(mValidatedState);
+                    break;
+                case CMD_LINGER_EXPIRED:
+                    if (message.arg1 != mLingerToken)
+                        break;
+                    mConnectivityServiceHandler.sendMessage(
+                            obtainMessage(EVENT_NETWORK_LINGER_COMPLETE, mNetworkAgentInfo));
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            return HANDLED;
+        }
+    }
+
+    /**
+     * Do a URL fetch on a known server to see if we get the data we expect.
+     * Returns HTTP response code.
+     */
+    private int isCaptivePortal() {
+        if (!mIsCaptivePortalCheckEnabled) return 204;
+
+        String urlString = "http://" + mServer + "/generate_204";
+        if (DBG) log("Checking " + urlString);
+        HttpURLConnection urlConnection = null;
+        Socket socket = null;
+        int httpResponseCode = 500;
+        try {
+            URL url = new URL(urlString);
+            if (false) {
+                // TODO: Need to add URLConnection.setNetwork() before we can enable.
+                urlConnection = (HttpURLConnection) url.openConnection();
+                urlConnection.setInstanceFollowRedirects(false);
+                urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
+                urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
+                urlConnection.setUseCaches(false);
+                urlConnection.getInputStream();
+                httpResponseCode = urlConnection.getResponseCode();
+            } else {
+                socket = new Socket();
+                // TODO: setNetworkForSocket(socket, mNetworkAgentInfo.network.netId);
+                InetSocketAddress address = new InetSocketAddress(url.getHost(), 80);
+                // TODO: address = new InetSocketAddress(
+                //               getByNameOnNetwork(mNetworkAgentInfo.network, url.getHost()), 80);
+                socket.connect(address);
+                BufferedReader reader = new BufferedReader(
+                        new InputStreamReader(socket.getInputStream()));
+                OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream());
+                writer.write("GET " + url.getFile() + " HTTP/1.1\r\n\n");
+                writer.flush();
+                String response = reader.readLine();
+                if (response.startsWith("HTTP/1.1 ")) {
+                    httpResponseCode = Integer.parseInt(response.substring(9, 12));
+                }
+            }
+            if (DBG) log("isCaptivePortal: ret=" + httpResponseCode);
+        } catch (IOException e) {
+            if (DBG) log("Probably not a portal: exception " + e);
+        } finally {
+            if (urlConnection != null) {
+                urlConnection.disconnect();
+            }
+            if (socket != null) {
+                try {
+                    socket.close();
+                } catch (IOException e) {
+                    // Ignore
+                }
+            }
+        }
+        return httpResponseCode;
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 8815d0f..63178eb 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -24,7 +24,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
+import android.net.Uri;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -32,7 +33,6 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.provider.Settings;
-import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
@@ -71,7 +71,7 @@
     public static final String KEY_PROXY = "keyProxy";
     private String mCurrentPac;
     @GuardedBy("mProxyLock")
-    private String mPacUrl;
+    private Uri mPacUrl;
 
     private AlarmManager mAlarmManager;
     @GuardedBy("mProxyLock")
@@ -100,7 +100,7 @@
         public void run() {
             String file;
             synchronized (mProxyLock) {
-                if (mPacUrl == null) return;
+                if (Uri.EMPTY.equals(mPacUrl)) return;
                 try {
                     file = get(mPacUrl);
                 } catch (IOException ioe) {
@@ -157,8 +157,8 @@
      * @param proxy Proxy information that is about to be broadcast.
      * @return Returns true when the broadcast should not be sent
      */
-    public synchronized boolean setCurrentProxyScriptUrl(ProxyProperties proxy) {
-        if (!TextUtils.isEmpty(proxy.getPacFileUrl())) {
+    public synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) {
+        if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) {
             if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) {
                 // Allow to send broadcast, nothing to do.
                 return false;
@@ -196,8 +196,8 @@
      *
      * @throws IOException
      */
-    private static String get(String urlString) throws IOException {
-        URL url = new URL(urlString);
+    private static String get(Uri pacUri) throws IOException {
+        URL url = new URL(pacUri.toString());
         URLConnection urlConnection = url.openConnection(java.net.Proxy.NO_PROXY);
         return new String(Streams.readFully(urlConnection.getInputStream()));
     }
@@ -268,7 +268,7 @@
         // Already bound no need to bind again.
         if ((mProxyConnection != null) && (mConnection != null)) {
             if (mLastPort != -1) {
-                sendPacBroadcast(new ProxyProperties(mPacUrl, mLastPort));
+                sendPacBroadcast(new ProxyInfo(mPacUrl, mLastPort));
             } else {
                 Log.e(TAG, "Received invalid port from Local Proxy,"
                         + " PAC will not be operational");
@@ -362,7 +362,7 @@
         mLastPort = -1;
     }
 
-    private void sendPacBroadcast(ProxyProperties proxy) {
+    private void sendPacBroadcast(ProxyInfo proxy) {
         mConnectivityHandler.sendMessage(mConnectivityHandler.obtainMessage(mProxyMessage, proxy));
     }
 
@@ -371,7 +371,7 @@
             return;
         }
         if (!mHasSentBroadcast) {
-            sendPacBroadcast(new ProxyProperties(mPacUrl, mLastPort));
+            sendPacBroadcast(new ProxyInfo(mPacUrl, mLastPort));
             mHasSentBroadcast = true;
         }
     }
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index abe362a..92b5f52 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -1325,7 +1325,7 @@
                 } else {
                     LinkProperties linkProperties = null;
                     try {
-                        linkProperties = mConnService.getLinkProperties(upType);
+                        linkProperties = mConnService.getLinkPropertiesForType(upType);
                     } catch (RemoteException e) { }
                     if (linkProperties != null) {
                         // Find the interface with the default IPv4 route. It may be the
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 026fd296..1b40cdf 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -411,6 +411,7 @@
 
         if (!factoryTest) {
             intentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
+            intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
             context.registerReceiver(mBootCompletedReceiver, intentFilter);
         }
 
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 5fa1584..4740cae 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -48,8 +48,7 @@
     private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
 
     // If true, enables the use of the screen auto-brightness adjustment setting.
-    private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT =
-            PowerManager.useScreenAutoBrightnessAdjustmentFeature();
+    private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT = true;
 
     // The maximum range of gamma adjustment possible using the screen
     // auto-brightness adjustment setting.
@@ -202,7 +201,7 @@
 
     public void updatePowerState(DisplayManagerInternal.DisplayPowerRequest request) {
         if (setScreenAutoBrightnessAdjustment(request.screenAutoBrightnessAdjustment)
-                || setLightSensorEnabled(request.wantLightSensorEnabled())) {
+                | setLightSensorEnabled(request.wantLightSensorEnabled())) {
             updateAutoBrightness(false /*sendUpdate*/);
         }
     }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 1f38eb6..3d5fb57 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -393,11 +393,7 @@
 
         // Initialize screen state for battery stats.
         try {
-            if (mPowerState.getScreenState() != Display.STATE_OFF) {
-                mBatteryStats.noteScreenOn();
-            } else {
-                mBatteryStats.noteScreenOff();
-            }
+            mBatteryStats.noteScreenState(mPowerState.getScreenState());
             mBatteryStats.noteScreenBrightness(mPowerState.getScreenBrightness());
         } catch (RemoteException ex) {
             // same process
@@ -522,6 +518,11 @@
                 // Brighten quickly.
                 slow = false;
             }
+            // If low power mode is enabled, brightness level
+            // would be scaled down to half
+            if (mPowerRequest.lowPowerMode) {
+                target = target/2;
+            }
             animateScreenBrightness(clampScreenBrightness(target),
                     slow ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
         } else {
@@ -641,11 +642,7 @@
         if (mPowerState.getScreenState() != state) {
             mPowerState.setScreenState(state);
             try {
-                if (state != Display.STATE_OFF) {
-                    mBatteryStats.noteScreenOn();
-                } else {
-                    mBatteryStats.noteScreenOff();
-                }
+                mBatteryStats.noteScreenState(state);
             } catch (RemoteException ex) {
                 // same process
             }
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 91afec7..7f43e43 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -21,6 +21,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.SystemProperties;
+import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayEventReceiver;
@@ -47,8 +48,6 @@
             new SparseArray<LocalDisplayDevice>();
     private HotplugDisplayEventReceiver mHotplugReceiver;
 
-    private final SurfaceControl.PhysicalDisplayInfo mTempPhys = new SurfaceControl.PhysicalDisplayInfo();
-
     // Called with SyncRoot lock held.
     public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
             Context context, Handler handler, Listener listener) {
@@ -68,14 +67,31 @@
 
     private void tryConnectDisplayLocked(int builtInDisplayId) {
         IBinder displayToken = SurfaceControl.getBuiltInDisplay(builtInDisplayId);
-        if (displayToken != null && SurfaceControl.getDisplayInfo(displayToken, mTempPhys)) {
+        if (displayToken != null) {
+            SurfaceControl.PhysicalDisplayInfo[] configs =
+                    SurfaceControl.getDisplayConfigs(displayToken);
+            if (configs == null) {
+                // There are no valid configs for this device, so we can't use it
+                Slog.w(TAG, "No valid configs found for display device " +
+                        builtInDisplayId);
+                return;
+            }
+            int activeConfig = SurfaceControl.getActiveConfig(displayToken);
+            if (activeConfig < 0) {
+                // There is no active config, and for now we don't have the
+                // policy to set one.
+                Slog.w(TAG, "No active config found for display device " +
+                        builtInDisplayId);
+                return;
+            }
             LocalDisplayDevice device = mDevices.get(builtInDisplayId);
             if (device == null) {
                 // Display was added.
-                device = new LocalDisplayDevice(displayToken, builtInDisplayId, mTempPhys);
+                device = new LocalDisplayDevice(displayToken, builtInDisplayId,
+                        configs[activeConfig]);
                 mDevices.put(builtInDisplayId, device);
                 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
-            } else if (device.updatePhysicalDisplayInfoLocked(mTempPhys)) {
+            } else if (device.updatePhysicalDisplayInfoLocked(configs[activeConfig])) {
                 // Display properties changed.
                 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
             }
@@ -228,4 +244,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index a165f26..14ef5a9 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -146,9 +146,7 @@
 
         @Override
         public void performTraversalInTransactionLocked() {
-            if (mSurface != null) {
-                setSurfaceInTransactionLocked(mSurface);
-            }
+            setSurfaceInTransactionLocked(mSurface);
         }
 
         public void setSurfaceLocked(Surface surface) {
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index fd2f8a1..8968da3 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -642,8 +642,9 @@
             try {
                 synchronized (mMcuHal) {
                     if (mReleased) {
-                        throw new IllegalStateException("This operation cannot be performed "
-                                + "because the dream has ended.");
+                        Slog.w(TAG, "Ignoring message to MCU HAL because the dream "
+                                + "has already ended: " + msg);
+                        return null;
                     }
                     return mMcuHal.sendMessage(msg, arg);
                 }
diff --git a/services/core/java/com/android/server/hdmi/FeatureAction.java b/services/core/java/com/android/server/hdmi/FeatureAction.java
new file mode 100644
index 0000000..296cc5b
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/FeatureAction.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.hdmi;
+
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Encapsulates a sequence of CEC/MHL command exchange for a certain feature.
+ *
+ * <p>Many CEC/MHL features are accomplished by CEC devices on the bus exchanging
+ * more than one command. {@link FeatureAction} represents the life cycle of the communication,
+ * manages the state as the process progresses, and if necessary, returns the result
+ * to the caller which initiates the action, through the callback given at the creation
+ * of the object. All the actual action classes inherit FeatureAction.
+ *
+ * <p>More than one FeatureAction objects can be up and running simultaneously,
+ * maintained by {@link HdmiControlService}. Each action is passed a new command
+ * arriving from the bus, and either consumes it if the command is what the action expects,
+ * or yields it to other action.
+ *
+ * Declared as package private, accessed by {@link HdmiControlService} only.
+ */
+abstract class FeatureAction {
+
+    private static final String TAG = "FeatureAction";
+
+    // Timer handler message used for timeout event
+    protected static final int MSG_TIMEOUT = 100;
+
+    // Default timeout for the incoming command to arrive in response to a request
+    protected static final int TIMEOUT_MS = 1000;
+
+    // Default state used in common by all the feature actions.
+    protected static final int STATE_NONE = 0;
+
+    // Internal state indicating the progress of action.
+    protected int mState = STATE_NONE;
+
+    protected final HdmiControlService mService;
+
+    // Logical address of the device for which the feature action is taken. The commands
+    // generated in an action all use this field as source address.
+    protected final int mSourceAddress;
+
+    // Timer that manages timeout events.
+    protected ActionTimer mActionTimer;
+
+    FeatureAction(HdmiControlService service, int sourceAddress) {
+        mService = service;
+        mSourceAddress = sourceAddress;
+        mActionTimer = createActionTimer(service.getServiceLooper());
+    }
+
+    @VisibleForTesting
+    void setActionTimer(ActionTimer actionTimer) {
+        mActionTimer = actionTimer;
+    }
+
+    /**
+     * Called right after the action is created. Initialization or first step to take
+     * for the action can be done in this method.
+     *
+     * @return true if the operation is successful; otherwise false.
+     */
+    abstract boolean start();
+
+    /**
+     * Process the command. Called whenever a new command arrives.
+     *
+     * @param cmd command to process
+     * @return true if the command was consumed in the process; Otherwise false, which
+     *          indicates that the command shall be handled by other actions.
+     */
+    abstract boolean processCommand(HdmiCecMessage cmd);
+
+    /**
+     * Called when the action should handle the timer event it created before.
+     *
+     * <p>CEC standard mandates each command transmission should be responded within
+     * certain period of time. The method is called when the timer it created as it transmitted
+     * a command gets expired. Inner logic should take an appropriate action.
+     *
+     * @param state the state associated with the time when the timer was created
+     */
+    abstract void handleTimerEvent(int state);
+
+    /**
+     * Timer handler interface used for FeatureAction classes.
+     */
+    interface ActionTimer {
+        /**
+         * Send a timer message.
+         *
+         * Also carries the state of the action when the timer is created. Later this state is
+         * compared to the one the action is in when it receives the timer to let the action tell
+         * the right timer to handle.
+         *
+         * @param state state of the action is in
+         * @param delayMillis amount of delay for the timer
+         */
+        void sendTimerMessage(int state, long delayMillis);
+    }
+
+    private class ActionTimerHandler extends Handler implements ActionTimer {
+
+        public ActionTimerHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void sendTimerMessage(int state, long delayMillis) {
+            sendMessageDelayed(obtainMessage(MSG_TIMEOUT, state), delayMillis);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case MSG_TIMEOUT:
+                handleTimerEvent(msg.arg1);
+                break;
+            default:
+                Slog.w(TAG, "Unsupported message:" + msg.what);
+                break;
+            }
+        }
+    }
+
+    private ActionTimer createActionTimer(Looper looper) {
+        return new ActionTimerHandler(looper);
+    }
+
+    // Add a new timer. The timer event will come to mActionTimer.handleMessage() in
+    // delayMillis.
+    protected void addTimer(int state, int delayMillis) {
+        mActionTimer.sendTimerMessage(state, delayMillis);
+    }
+
+    static HdmiCecMessage buildCommand(int src, int dst, int opcode, byte[] params) {
+        return new HdmiCecMessage(src, dst, opcode, params);
+    }
+
+    // Build a CEC command that does not have parameter.
+    static HdmiCecMessage buildCommand(int src, int dst, int opcode) {
+        return new HdmiCecMessage(src, dst, opcode, HdmiCecMessage.EMPTY_PARAM);
+    }
+
+    protected final void sendCommand(HdmiCecMessage cmd) {
+        mService.sendCecCommand(cmd);
+    }
+
+    protected final void sendBroadcastCommand(int opcode, byte[] param) {
+        sendCommand(buildCommand(mSourceAddress, HdmiCec.ADDR_BROADCAST, opcode, param));
+    }
+
+    /**
+     * Finish up the action. Reset the state, and remove itself from the action queue.
+     */
+    protected void finish() {
+        mState = STATE_NONE;
+        removeAction(this);
+    }
+
+    /**
+     * Remove the action from the action queue. This is called after the action finishes
+     * its role.
+     *
+     * @param action
+     */
+    private void removeAction(FeatureAction action) {
+        mService.removeAction(action);
+    }
+
+    // Utility methods for generating parameter byte arrays for CEC commands.
+    protected static byte[] uiCommandParam(int uiCommand) {
+        return new byte[] {(byte) uiCommand};
+    }
+
+    protected static byte[] physicalAddressParam(int physicalAddress) {
+        return new byte[] {
+                (byte) ((physicalAddress >> 8) & 0xFF),
+                (byte) (physicalAddress & 0xFF)
+        };
+    }
+
+    protected static byte[] pathPairParam(int oldPath, int newPath) {
+        return new byte[] {
+                (byte) ((oldPath >> 8) & 0xFF), (byte) (oldPath & 0xFF),
+                (byte) ((newPath >> 8) & 0xFF), (byte) (newPath & 0xFF)
+        };
+    }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 5f07108..b103a4d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -16,9 +16,20 @@
 
 package com.android.server.hdmi;
 
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiCecMessage;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import libcore.util.EmptyArray;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
 /**
  * Manages HDMI-CEC command and behaviors. It converts user's command into CEC command
@@ -29,20 +40,51 @@
  *
  * <p>Declared as package-private, accessed by {@link HdmiControlService} only.
  */
-class HdmiCecController {
+final class HdmiCecController {
     private static final String TAG = "HdmiCecController";
 
+    private static final byte[] EMPTY_BODY = EmptyArray.BYTE;
+
+    // A message to pass cec send command to IO looper.
+    private static final int MSG_SEND_CEC_COMMAND = 1;
+    // A message to delegate logical allocation to IO looper.
+    private static final int MSG_ALLOCATE_LOGICAL_ADDRESS = 2;
+
+    // Message types to handle incoming message in main service looper.
+    private final static int MSG_RECEIVE_CEC_COMMAND = 1;
+    // A message to report allocated logical address to main control looper.
+    private final static int MSG_REPORT_LOGICAL_ADDRESS = 2;
+
+    // TODO: move these values to HdmiCec.java once make it internal constant class.
+    // CEC's ABORT reason values.
+    private static final int ABORT_UNRECOGNIZED_MODE = 0;
+    private static final int ABORT_NOT_IN_CORRECT_MODE = 1;
+    private static final int ABORT_CANNOT_PROVIDE_SOURCE = 2;
+    private static final int ABORT_INVALID_OPERAND = 3;
+    private static final int ABORT_REFUSED = 4;
+    private static final int ABORT_UNABLE_TO_DETERMINE = 5;
+
+    private static final int NUM_LOGICAL_ADDRESS = 16;
+
+    // TODO: define other constants for errors.
+    private static final int ERROR_SUCCESS = 0;
+
     // Handler instance to process synchronous I/O (mainly send) message.
     private Handler mIoHandler;
 
     // Handler instance to process various messages coming from other CEC
     // device or issued by internal state change.
-    private Handler mMessageHandler;
+    private Handler mControlHandler;
 
     // Stores the pointer to the native implementation of the service that
     // interacts with HAL.
     private long mNativePtr;
 
+    // Map-like container of all cec devices. A logical address of device is
+    // used as key of container.
+    private final SparseArray<HdmiCecDeviceInfo> mDeviceInfos =
+            new SparseArray<HdmiCecDeviceInfo>();
+
     // Private constructor.  Use HdmiCecController.create().
     private HdmiCecController() {
     }
@@ -52,14 +94,12 @@
      * inner device or has no device it will return {@code null}.
      *
      * <p>Declared as package-private, accessed by {@link HdmiControlService} only.
-     *
-     * @param ioLooper a Looper instance to handle IO (mainly send message) operation.
-     * @param messageHandler a message handler that processes a message coming from other
-     *                       CEC compatible device or callback of internal state change.
+     * @param service {@link HdmiControlService} instance used to create internal handler
+     *                and to pass callback for incoming message or event.
      * @return {@link HdmiCecController} if device is initialized successfully. Otherwise,
      *         returns {@code null}.
      */
-    static HdmiCecController create(Looper ioLooper, Handler messageHandler) {
+    static HdmiCecController create(HdmiControlService service) {
         HdmiCecController handler = new HdmiCecController();
         long nativePtr = nativeInit(handler);
         if (nativePtr == 0L) {
@@ -67,28 +107,325 @@
             return null;
         }
 
-        handler.init(ioLooper, messageHandler, nativePtr);
+        handler.init(service, nativePtr);
         return handler;
     }
 
-    private void init(Looper ioLooper, Handler messageHandler, long nativePtr) {
-        mIoHandler = new Handler(ioLooper) {
-                @Override
-            public void handleMessage(Message msg) {
-                // TODO: Call native sendMessage.
-            }
-        };
-
-        mMessageHandler = messageHandler;
-        mNativePtr = nativePtr;
+    /**
+     * Interface to report allocated logical address.
+     */
+    interface AllocateLogicalAddressCallback {
+        /**
+         * Called when a new logical address is allocated.
+         *
+         * @param deviceType requested device type to allocate logical address
+         * @param logicalAddress allocated logical address. If it is
+         *                       {@link HdmiCec#ADDR_UNREGISTERED}, it means that
+         *                       it failed to allocate logical address for the given device type
+         */
+        void onAllocated(int deviceType, int logicalAddress);
     }
 
     /**
-     * Called by native when an HDMI-CEC message arrived.
+     * Allocate a new logical address of the given device type. Allocated
+     * address will be reported through {@link AllocateLogicalAddressCallback}.
+     *
+     * <p> Declared as package-private, accessed by {@link HdmiControlService} only.
+     *
+     * @param deviceType type of device to used to determine logical address
+     * @param preferredAddress a logical address preferred to be allocated.
+     *                         If sets {@link HdmiCec#ADDR_UNREGISTERED}, scans
+     *                         the smallest logical address matched with the given device type.
+     *                         Otherwise, scan address will start from {@code preferredAddress}
+     * @param callback callback interface to report allocated logical address to caller
      */
-    private void handleMessage(int srcAddress, int dstAddres, int opcode, byte[] params) {
-        // TODO: Translate message and delegate it to main message handler.
+    void allocateLogicalAddress(int deviceType, int preferredAddress,
+            AllocateLogicalAddressCallback callback) {
+        Message msg = mIoHandler.obtainMessage(MSG_ALLOCATE_LOGICAL_ADDRESS);
+        msg.arg1 = deviceType;
+        msg.arg2 = preferredAddress;
+        msg.obj = callback;
+        mIoHandler.sendMessage(msg);
+    }
+
+    private static byte[] buildBody(int opcode, byte[] params) {
+        byte[] body = new byte[params.length + 1];
+        body[0] = (byte) opcode;
+        System.arraycopy(params, 0, body, 1, params.length);
+        return body;
+    }
+
+    private final class IoHandler extends Handler {
+        private IoHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_SEND_CEC_COMMAND:
+                    HdmiCecMessage cecMessage = (HdmiCecMessage) msg.obj;
+                    byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams());
+                    nativeSendCecCommand(mNativePtr, cecMessage.getSource(),
+                            cecMessage.getDestination(), body);
+                    break;
+                case MSG_ALLOCATE_LOGICAL_ADDRESS:
+                    int deviceType = msg.arg1;
+                    int preferredAddress = msg.arg2;
+                    AllocateLogicalAddressCallback callback =
+                            (AllocateLogicalAddressCallback) msg.obj;
+                    handleAllocateLogicalAddress(deviceType, preferredAddress, callback);
+                    break;
+                default:
+                    Slog.w(TAG, "Unsupported CEC Io request:" + msg.what);
+                    break;
+            }
+        }
+
+        private void handleAllocateLogicalAddress(int deviceType, int preferredAddress,
+                AllocateLogicalAddressCallback callback) {
+            int startAddress = preferredAddress;
+            // If preferred address is "unregistered", start_index will be the smallest
+            // address matched with the given device type.
+            if (preferredAddress == HdmiCec.ADDR_UNREGISTERED) {
+                for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) {
+                    if (deviceType == HdmiCec.getTypeFromAddress(i)) {
+                        startAddress = i;
+                        break;
+                    }
+                }
+            }
+
+            int logcialAddress = HdmiCec.ADDR_UNREGISTERED;
+            // Iterates all possible addresses which has the same device type.
+            for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) {
+                int curAddress = (startAddress + i) % NUM_LOGICAL_ADDRESS;
+                if (curAddress != HdmiCec.ADDR_UNREGISTERED
+                        && deviceType == HdmiCec.getTypeFromAddress(i)) {
+                    // <Polling Message> is a message which has empty body and
+                    // uses same address for both source and destination address.
+                    // If sending <Polling Message> failed (NAK), it becomes
+                    // new logical address for the device because no device uses
+                    // it as logical address of the device.
+                    int error = nativeSendCecCommand(mNativePtr, curAddress, curAddress,
+                            EMPTY_BODY);
+                    if (error != ERROR_SUCCESS) {
+                        logcialAddress = curAddress;
+                        break;
+                    }
+                }
+            }
+
+            Message msg = mControlHandler.obtainMessage(MSG_REPORT_LOGICAL_ADDRESS);
+            msg.arg1 = deviceType;
+            msg.arg2 = logcialAddress;
+            msg.obj = callback;
+            mControlHandler.sendMessage(msg);
+        }
+    }
+
+    private final class ControlHandler extends Handler {
+        private ControlHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_RECEIVE_CEC_COMMAND:
+                    // TODO: delegate it to HdmiControl service.
+                    onReceiveCommand((HdmiCecMessage) msg.obj);
+                    break;
+                case MSG_REPORT_LOGICAL_ADDRESS:
+                    int deviceType = msg.arg1;
+                    int logicalAddress = msg.arg2;
+                    AllocateLogicalAddressCallback callback =
+                            (AllocateLogicalAddressCallback) msg.obj;
+                    callback.onAllocated(deviceType, logicalAddress);
+                    break;
+                default:
+                    Slog.i(TAG, "Unsupported message type:" + msg.what);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Add a new {@link HdmiCecDeviceInfo}. It returns old device info which has the same
+     * logical address as new device info's.
+     *
+     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+     *
+     * @param deviceInfo a new {@link HdmiCecDeviceInfo} to be added.
+     * @return {@code null} if it is new device. Otherwise, returns old {@HdmiCecDeviceInfo}
+     *         that has the same logical address as new one has.
+     */
+    HdmiCecDeviceInfo addDeviceInfo(HdmiCecDeviceInfo deviceInfo) {
+        HdmiCecDeviceInfo oldDeviceInfo = getDeviceInfo(deviceInfo.getLogicalAddress());
+        if (oldDeviceInfo != null) {
+            removeDeviceInfo(deviceInfo.getLogicalAddress());
+        }
+        mDeviceInfos.append(deviceInfo.getLogicalAddress(), deviceInfo);
+        return oldDeviceInfo;
+    }
+
+    /**
+     * Remove a device info corresponding to the given {@code logicalAddress}.
+     * It returns removed {@link HdmiCecDeviceInfo} if exists.
+     *
+     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+     *
+     * @param logicalAddress logical address of device to be removed
+     * @return removed {@link HdmiCecDeviceInfo} it exists. Otherwise, returns {@code null}
+     */
+    HdmiCecDeviceInfo removeDeviceInfo(int logicalAddress) {
+        HdmiCecDeviceInfo deviceInfo = mDeviceInfos.get(logicalAddress);
+        if (deviceInfo != null) {
+            mDeviceInfos.remove(logicalAddress);
+        }
+        return deviceInfo;
+    }
+
+    /**
+     * Return a list of all {@HdmiCecDeviceInfo}.
+     *
+     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+     */
+    List<HdmiCecDeviceInfo> getDeviceInfoList() {
+        List<HdmiCecDeviceInfo> deviceInfoList = new ArrayList<HdmiCecDeviceInfo>(
+                mDeviceInfos.size());
+        for (int i = 0; i < mDeviceInfos.size(); ++i) {
+            deviceInfoList.add(mDeviceInfos.valueAt(i));
+        }
+        return deviceInfoList;
+    }
+
+    /**
+     * Return a {@link HdmiCecDeviceInfo} corresponding to the given {@code logicalAddress}.
+     *
+     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+     *
+     * @param logicalAddress logical address to be retrieved
+     * @return {@link HdmiCecDeviceInfo} matched with the given {@code logicalAddress}.
+     *         Returns null if no logical address matched
+     */
+    HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) {
+        return mDeviceInfos.get(logicalAddress);
+    }
+
+    /**
+     * Add a new logical address to the device. Device's HW should be notified
+     * when a new logical address is assigned to a device, so that it can accept
+     * a command having available destinations.
+     *
+     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+     *
+     * @param newLogicalAddress a logical address to be added
+     * @return 0 on success. Otherwise, returns negative value
+     */
+    int addLogicalAddress(int newLogicalAddress) {
+        if (HdmiCec.isValidAddress(newLogicalAddress)) {
+            return nativeAddLogicalAddress(mNativePtr, newLogicalAddress);
+        } else {
+            return -1;
+        }
+    }
+
+    /**
+     * Clear all logical addresses registered in the device.
+     *
+     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+     */
+    void clearLogicalAddress() {
+        nativeClearLogicalAddress(mNativePtr);
+    }
+
+    /**
+     * Return the physical address of the device.
+     *
+     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+     *
+     * @return CEC physical address of the device. The range of success address
+     *         is between 0x0000 and 0xFFFF. If failed it returns -1
+     */
+    int getPhysicalAddress() {
+        return nativeGetPhysicalAddress(mNativePtr);
+    }
+
+    /**
+     * Return CEC version of the device.
+     *
+     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+     */
+    int getVersion() {
+        return nativeGetVersion(mNativePtr);
+    }
+
+    /**
+     * Return vendor id of the device.
+     *
+     * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+     */
+    int getVendorId() {
+        return nativeGetVendorId(mNativePtr);
+    }
+
+    private void init(HdmiControlService service, long nativePtr) {
+        mIoHandler = new IoHandler(service.getServiceLooper());
+        mControlHandler = new ControlHandler(service.getServiceLooper());
+        mNativePtr = nativePtr;
+    }
+
+    private void onReceiveCommand(HdmiCecMessage message) {
+        // TODO: Handle message according to opcode type.
+
+        // TODO: Use device's source address for broadcast message.
+        int sourceAddress = message.getDestination() != HdmiCec.ADDR_BROADCAST ?
+                message.getDestination() : 0;
+        // Reply <Feature Abort> to initiator (source) for all requests.
+        sendFeatureAbort(sourceAddress, message.getSource(), message.getOpcode(),
+                ABORT_REFUSED);
+    }
+
+    private void sendFeatureAbort(int srcAddress, int destAddress, int originalOpcode,
+            int reason) {
+        byte[] params = new byte[2];
+        params[0] = (byte) originalOpcode;
+        params[1] = (byte) reason;
+
+        HdmiCecMessage cecMessage = new HdmiCecMessage(srcAddress, destAddress,
+                HdmiCec.MESSAGE_FEATURE_ABORT, params);
+        Message message = mIoHandler.obtainMessage(MSG_SEND_CEC_COMMAND, cecMessage);
+        mIoHandler.sendMessage(message);
+    }
+
+    /**
+     * Called by native when incoming CEC message arrived.
+     */
+    private void handleIncomingCecCommand(int srcAddress, int dstAddress, byte[] body) {
+        byte opcode = body[0];
+        byte params[] = Arrays.copyOfRange(body, 1, body.length);
+        HdmiCecMessage cecMessage = new HdmiCecMessage(srcAddress, dstAddress, opcode, params);
+
+        // Delegate message to main handler so that it handles in main thread.
+        Message message = mControlHandler.obtainMessage(
+                MSG_RECEIVE_CEC_COMMAND, cecMessage);
+        mControlHandler.sendMessage(message);
+    }
+
+    /**
+     * Called by native when a hotplug event issues.
+     */
+    private void handleHotplug(boolean connected) {
+        // TODO: Delegate event to main message handler.
     }
 
     private static native long nativeInit(HdmiCecController handler);
+    private static native int nativeSendCecCommand(long controllerPtr, int srcAddress,
+            int dstAddress, byte[] body);
+    private static native int nativeAddLogicalAddress(long controllerPtr, int logicalAddress);
+    private static native void nativeClearLogicalAddress(long controllerPtr);
+    private static native int nativeGetPhysicalAddress(long controllerPtr);
+    private static native int nativeGetVersion(long controllerPtr);
+    private static native int nativeGetVendorId(long controllerPtr);
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 56c5b49..f99c717 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -18,9 +18,10 @@
 
 import android.annotation.Nullable;
 import android.content.Context;
-import android.os.Handler;
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiCecMessage;
 import android.os.HandlerThread;
-import android.os.Message;
+import android.os.Looper;
 import android.util.Slog;
 
 import com.android.server.SystemService;
@@ -37,14 +38,6 @@
     // and sparse call it shares a thread to handle IO operations.
     private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread");
 
-    // Main handler class to handle incoming message from each controller.
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            // TODO: Add handler for each message type.
-        }
-    };
-
     @Nullable
     private HdmiCecController mCecController;
 
@@ -57,14 +50,70 @@
 
     @Override
     public void onStart() {
-        mCecController = HdmiCecController.create(mIoThread.getLooper(), mHandler);
+        mCecController = HdmiCecController.create(this);
         if (mCecController == null) {
             Slog.i(TAG, "Device does not support HDMI-CEC.");
         }
 
-        mMhlController = HdmiMhlController.create(mIoThread.getLooper(), mHandler);
+        mMhlController = HdmiMhlController.create(this);
         if (mMhlController == null) {
             Slog.i(TAG, "Device does not support MHL-control.");
         }
     }
+
+    /**
+     * Returns {@link Looper} for IO operation.
+     *
+     * <p>Declared as package-private.
+     */
+    Looper getIoLooper() {
+        return mIoThread.getLooper();
+    }
+
+    /**
+     * Returns {@link Looper} of main thread. Use this {@link Looper} instance
+     * for tasks that are running on main service thread.
+     *
+     * <p>Declared as package-private.
+     */
+    Looper getServiceLooper() {
+        return Looper.myLooper();
+    }
+
+    /**
+     * Add a new {@link FeatureAction} to the action queue.
+     *
+     * @param action {@link FeatureAction} to add
+     */
+    void addAction(FeatureAction action) {
+        // TODO: Implement this.
+    }
+
+
+    /**
+     * Remove the given {@link FeatureAction} object from the action queue.
+     *
+     * @param action {@link FeatureAction} to add
+     */
+    void removeAction(FeatureAction action) {
+        // TODO: Implement this.
+    }
+
+    /**
+     * Transmit a CEC command to CEC bus.
+     *
+     * @param command CEC command to send out
+     */
+    void sendCecCommand(HdmiCecMessage command) {
+        // TODO: Implement this.
+    }
+
+    /**
+     * Add a new {@link HdmiCecDeviceInfo} to controller.
+     *
+     * @param deviceInfo new device information object to add
+     */
+    void addDeviceInfo(HdmiCecDeviceInfo deviceInfo) {
+        // TODO: Implement this.
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
new file mode 100644
index 0000000..c84a067
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.hdmi;
+
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.util.Slog;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Feature action that discovers the information of a newly found logical device.
+ *
+ * This action is created when receiving &lt;Report Physical Address&gt;, a CEC command a newly
+ * connected HDMI-CEC device broadcasts to announce its advent. Additional commands are issued in
+ * this action to gather more information on the device such as OSD name and device vendor ID.
+ *
+ * <p>The result is made in the form of {@link HdmiCecDeviceInfo} object, and passed to service
+ * for the management through its life cycle.
+ *
+ * <p>Package-private, accessed by {@link HdmiControlService} only.
+ */
+final class NewDeviceAction extends FeatureAction {
+
+    private static final String TAG = "NewDeviceAction";
+
+    // State in which the action sent <Give OSD Name> and is waiting for <Set OSD Name>
+    // that contains the name of the device for display on screen.
+    static final int STATE_WAITING_FOR_SET_OSD_NAME = 1;
+
+    // State in which the action sent <Give Device Vendor ID> and is waiting for
+    // <Device Vendor ID> that contains the vendor ID of the device.
+    static final int STATE_WAITING_FOR_DEVICE_VENDOR_ID = 2;
+
+    private final int mDeviceLogicalAddress;
+    private final int mDevicePhysicalAddress;
+
+    private int mVendorId;
+    private String mDisplayName;
+
+    /**
+     * Constructor.
+     *
+     * @param service {@link HdmiControlService} instance
+     * @param sourceAddress logical address to be used as source address
+     * @param deviceLogicalAddress logical address of the device in interest
+     * @param devicePhysicalAddress physical address of the device in interest
+     */
+    NewDeviceAction(HdmiControlService service, int sourceAddress, int deviceLogicalAddress,
+            int devicePhysicalAddress) {
+        super(service, sourceAddress);
+        mDeviceLogicalAddress = deviceLogicalAddress;
+        mDevicePhysicalAddress = devicePhysicalAddress;
+        mVendorId = HdmiCec.UNKNOWN_VENDOR_ID;
+    }
+
+    @Override
+    public boolean start() {
+        sendCommand(
+                buildCommand(mSourceAddress, mDeviceLogicalAddress, HdmiCec.MESSAGE_GET_OSD_NAME));
+        mState = STATE_WAITING_FOR_SET_OSD_NAME;
+        addTimer(mState, TIMEOUT_MS);
+        return true;
+    }
+
+    @Override
+    public boolean processCommand(HdmiCecMessage cmd) {
+        // For the logical device in interest, we want two more pieces of information -
+        // osd name and vendor id. They are requested in sequence. In case we don't
+        // get the expected responses (either by timeout or by receiving <feature abort> command),
+        // set them to a default osd name and unknown vendor id respectively.
+        int opcode = cmd.getOpcode();
+        int src = cmd.getSource();
+        byte[] params = cmd.getParams();
+
+        if (mDeviceLogicalAddress != src) {
+            return false;
+        }
+
+        if (mState == STATE_WAITING_FOR_SET_OSD_NAME) {
+            if (opcode == HdmiCec.MESSAGE_SET_OSD_NAME) {
+                try {
+                    mDisplayName = new String(params, "US-ASCII");
+                } catch (UnsupportedEncodingException e) {
+                    Slog.e(TAG, "Failed to get OSD name: " + e.getMessage());
+                }
+                mState = STATE_WAITING_FOR_DEVICE_VENDOR_ID;
+                requestVendorId();
+                return true;
+            } else if (opcode == HdmiCec.MESSAGE_FEATURE_ABORT) {
+                int requestOpcode = params[1];
+                if (requestOpcode == HdmiCec.MESSAGE_SET_OSD_NAME) {
+                    mState = STATE_WAITING_FOR_DEVICE_VENDOR_ID;
+                    requestVendorId();
+                    return true;
+                }
+            }
+        } else if (mState == STATE_WAITING_FOR_DEVICE_VENDOR_ID) {
+            if (opcode == HdmiCec.MESSAGE_DEVICE_VENDOR_ID) {
+                if (params.length == 3) {
+                    mVendorId = (params[0] << 16) + (params[1] << 8) + params[2];
+                } else {
+                    Slog.e(TAG, "Failed to get device vendor ID: ");
+                }
+                addDeviceInfo();
+                finish();
+                return true;
+            } else if (opcode == HdmiCec.MESSAGE_FEATURE_ABORT) {
+                int requestOpcode = params[1];
+                if (requestOpcode == HdmiCec.MESSAGE_DEVICE_VENDOR_ID) {
+                    addDeviceInfo();
+                    finish();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private void requestVendorId() {
+        sendCommand(buildCommand(mSourceAddress, mDeviceLogicalAddress,
+                HdmiCec.MESSAGE_GIVE_DEVICE_VENDOR_ID));
+        addTimer(mState, TIMEOUT_MS);
+    }
+
+    private void addDeviceInfo() {
+        if (mDisplayName == null) {
+            mDisplayName = HdmiCec.getDefaultDeviceName(mDeviceLogicalAddress);
+        }
+        mService.addDeviceInfo(new HdmiCecDeviceInfo(
+                mDeviceLogicalAddress, mDevicePhysicalAddress,
+                HdmiCec.getTypeFromAddress(mDeviceLogicalAddress),
+                mVendorId, mDisplayName));
+    }
+
+    @Override
+    public void handleTimerEvent(int state) {
+        if (mState == STATE_NONE || mState != state) {
+            return;
+        }
+        if (state == STATE_WAITING_FOR_SET_OSD_NAME) {
+            // Osd name request timed out. Try vendor id
+            mState = STATE_WAITING_FOR_DEVICE_VENDOR_ID;
+            requestVendorId();
+        } else if (state == STATE_WAITING_FOR_DEVICE_VENDOR_ID) {
+            // vendor id timed out. Go ahead creating the device info what we've got so far.
+            addDeviceInfo();
+            finish();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 54cb035..0f5805c 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -323,6 +323,10 @@
 
         mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
         mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
+
+        if (mWiredAccessoryCallbacks != null) {
+            mWiredAccessoryCallbacks.systemReady();
+        }
     }
 
     private void reloadKeyboardLayouts() {
@@ -1588,6 +1592,7 @@
      */
     public interface WiredAccessoryCallbacks {
         public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
+        public void systemReady();
     }
 
     /**
diff --git a/services/core/java/com/android/server/location/FlpHardwareProvider.java b/services/core/java/com/android/server/location/FlpHardwareProvider.java
index 79f192d..51ee93b 100644
--- a/services/core/java/com/android/server/location/FlpHardwareProvider.java
+++ b/services/core/java/com/android/server/location/FlpHardwareProvider.java
@@ -67,6 +67,7 @@
     public static FlpHardwareProvider getInstance(Context context) {
         if (sSingletonInstance == null) {
             sSingletonInstance = new FlpHardwareProvider(context);
+            sSingletonInstance.nativeInit();
         }
 
         return sSingletonInstance;
@@ -95,7 +96,7 @@
                 Looper.myLooper());
     }
 
-    public static boolean isSupported() {
+    public boolean isSupported() {
         return nativeIsSupported();
     }
 
@@ -258,12 +259,10 @@
     public static final String GEOFENCING = "Geofencing";
 
     public IFusedLocationHardware getLocationHardware() {
-        nativeInit();
         return mLocationHardware;
     }
 
     public IFusedGeofenceHardware getGeofenceHardware() {
-        nativeInit();
         return mGeofenceHardwareService;
     }
 
diff --git a/services/core/java/com/android/server/location/LocationRequestStatistics.java b/services/core/java/com/android/server/location/LocationRequestStatistics.java
index 85231bb..264026e 100644
--- a/services/core/java/com/android/server/location/LocationRequestStatistics.java
+++ b/services/core/java/com/android/server/location/LocationRequestStatistics.java
@@ -13,7 +13,7 @@
 public class LocationRequestStatistics {
     private static final String TAG = "LocationStats";
 
-    // Maps package name nad provider to location request statistics.
+    // Maps package name and provider to location request statistics.
     public final HashMap<PackageProviderKey, PackageStatistics> statistics
             = new HashMap<PackageProviderKey, PackageStatistics>();
 
diff --git a/services/core/java/com/android/server/media/MediaRouteProviderProxy.java b/services/core/java/com/android/server/media/MediaRouteProviderProxy.java
index d314ea7..c4e2058 100644
--- a/services/core/java/com/android/server/media/MediaRouteProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRouteProviderProxy.java
@@ -36,6 +36,7 @@
 import android.util.Log;
 import android.util.Slog;
 
+import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
@@ -55,13 +56,12 @@
     private final String mId;
     private final ComponentName mComponentName;
     private final int mUserId;
+    // Interfaces declared in the manifest
+    private final ArrayList<String> mInterfaces = new ArrayList<String>();
+    private final ArrayList<RouteConnectionRecord> mConnections = new ArrayList<RouteConnectionRecord>();
+    private final Handler mHandler = new Handler();
 
     private Intent mBindIntent;
-    // Interfaces declared in the manifest
-    private ArrayList<String> mInterfaces;
-    private ArrayList<RouteConnectionRecord> mConnections = new ArrayList<RouteConnectionRecord>();
-    private Handler mHandler = new Handler();
-
     private IRouteProvider mBinder;
     private boolean mRunning;
     private boolean mInterested;
@@ -76,7 +76,9 @@
         mId = id;
         mComponentName = component;
         mUserId = uid;
-        mInterfaces = interfaces;
+        if (interfaces != null) {
+            mInterfaces.addAll(interfaces);
+        }
         mBindIntent = new Intent(RouteProviderService.SERVICE_INTERFACE);
         mBindIntent.setComponent(mComponentName);
     }
@@ -202,7 +204,7 @@
 
                     if (connection != null) {
                         RouteConnectionRecord record = new RouteConnectionRecord(
-                                connection);
+                                connection, mComponentName.getPackageName(), mUserId);
                         mConnections.add(record);
                         if (mRouteListener != null) {
                             mRouteListener.onRouteConnected(sessionId, route, request, record);
@@ -234,6 +236,19 @@
         return mId;
     }
 
+    public void dump(PrintWriter pw, String prefix) {
+        pw.println(prefix + mId + " " + this);
+        String indent = prefix + "  ";
+
+        pw.println(indent + "component=" + mComponentName.toString());
+        pw.println(indent + "user id=" + mUserId);
+        pw.println(indent + "interfaces=" + mInterfaces.toString());
+        pw.println(indent + "connections=" + mConnections.toString());
+        pw.println(indent + "running=" + mRunning);
+        pw.println(indent + "interested=" + mInterested);
+        pw.println(indent + "bound=" + mBound);
+    }
+
     private void updateBinding() {
         if (shouldBind()) {
             bind();
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index ac7f4f3..41ab626 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -16,7 +16,9 @@
 
 package com.android.server.media;
 
+import android.app.ActivityManager;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.media.routeprovider.RouteRequest;
 import android.media.session.ISessionController;
 import android.media.session.ISessionControllerCallback;
@@ -40,12 +42,15 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
+import android.os.SystemClock;
+import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
 import android.view.KeyEvent;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
@@ -57,9 +62,29 @@
 public class MediaSessionRecord implements IBinder.DeathRecipient {
     private static final String TAG = "MediaSessionRecord";
 
+    /**
+     * These are the playback states that count as currently active.
+     */
+    private static final int[] ACTIVE_STATES = {
+            PlaybackState.PLAYSTATE_FAST_FORWARDING,
+            PlaybackState.PLAYSTATE_REWINDING,
+            PlaybackState.PLAYSTATE_SKIPPING_BACKWARDS,
+            PlaybackState.PLAYSTATE_SKIPPING_FORWARDS,
+            PlaybackState.PLAYSTATE_BUFFERING,
+            PlaybackState.PLAYSTATE_CONNECTING,
+            PlaybackState.PLAYSTATE_PLAYING };
+
+    /**
+     * The length of time a session will still be considered active after
+     * pausing in ms.
+     */
+    private static final int ACTIVE_BUFFER = 30000;
+
     private final MessageHandler mHandler;
 
-    private final int mPid;
+    private final int mOwnerPid;
+    private final int mOwnerUid;
+    private final int mUserId;
     private final SessionInfo mSessionInfo;
     private final String mTag;
     private final ControllerStub mController;
@@ -72,26 +97,29 @@
             new ArrayList<ISessionControllerCallback>();
     private final ArrayList<RouteRequest> mRequests = new ArrayList<RouteRequest>();
 
-    private boolean mTransportPerformerEnabled = false;
     private RouteInfo mRoute;
     private RouteOptions mRequest;
     private RouteConnectionRecord mConnection;
     // TODO define a RouteState class with relevant info
     private int mRouteState;
+    private long mFlags;
 
     // TransportPerformer fields
 
     private MediaMetadata mMetadata;
     private PlaybackState mPlaybackState;
     private int mRatingType;
+    private long mLastActiveTime;
     // End TransportPerformer fields
 
-    private boolean mIsPublished = false;
+    private boolean mIsActive = false;
 
-    public MediaSessionRecord(int pid, String packageName, ISessionCallback cb, String tag,
-            MediaSessionService service, Handler handler) {
-        mPid = pid;
-        mSessionInfo = new SessionInfo(UUID.randomUUID().toString(), packageName);
+    public MediaSessionRecord(int ownerPid, int ownerUid, int userId, String ownerPackageName,
+            ISessionCallback cb, String tag, MediaSessionService service, Handler handler) {
+        mOwnerPid = ownerPid;
+        mOwnerUid = ownerUid;
+        mUserId = userId;
+        mSessionInfo = new SessionInfo(UUID.randomUUID().toString(), ownerPackageName);
         mTag = tag;
         mController = new ControllerStub();
         mSession = new SessionStub();
@@ -146,6 +174,44 @@
     }
 
     /**
+     * Get this session's flags.
+     *
+     * @return The flags for this session.
+     */
+    public long getFlags() {
+        return mFlags;
+    }
+
+    /**
+     * Check if this session has the specified flag.
+     *
+     * @param flag The flag to check.
+     * @return True if this session has that flag set, false otherwise.
+     */
+    public boolean hasFlag(int flag) {
+        return (mFlags & flag) != 0;
+    }
+
+    /**
+     * Get the user id this session was created for.
+     *
+     * @return The user id for this session.
+     */
+    public int getUserId() {
+        return mUserId;
+    }
+
+    /**
+     * Check if this session has system priorty and should receive media buttons
+     * before any other sessions.
+     *
+     * @return True if this is a system priority session, false otherwise
+     */
+    public boolean isSystemPriority() {
+        return (mFlags & Session.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0;
+    }
+
+    /**
      * Set the selected route. This does not connect to the route, just notifies
      * the app that a new route has been selected.
      *
@@ -213,12 +279,36 @@
     }
 
     /**
-     * Check if this session has been published by the app yet.
+     * Check if this session has been set to active by the app.
      *
-     * @return True if it has been published, false otherwise.
+     * @return True if the session is active, false otherwise.
      */
-    public boolean isPublished() {
-        return mIsPublished;
+    public boolean isActive() {
+        return mIsActive;
+    }
+
+    /**
+     * Check if the session is currently performing playback. This will also
+     * return true if the session was recently paused.
+     *
+     * @return True if the session is performing playback, false otherwise.
+     */
+    public boolean isPlaybackActive() {
+        int state = mPlaybackState == null ? 0 : mPlaybackState.getState();
+        if (isActiveState(state)) {
+            return true;
+        }
+        if (state == mPlaybackState.PLAYSTATE_PAUSED) {
+            long inactiveTime = SystemClock.uptimeMillis() - mLastActiveTime;
+            if (inactiveTime < ACTIVE_BUFFER) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean isTransportControlEnabled() {
+        return hasFlag(Session.FLAG_HANDLES_TRANSPORT_CONTROLS);
     }
 
     @Override
@@ -226,6 +316,46 @@
         mService.sessionDied(this);
     }
 
+    public void dump(PrintWriter pw, String prefix) {
+        pw.println(prefix + mTag + " " + this);
+
+        final String indent = prefix + "  ";
+        pw.println(indent + "ownerPid=" + mOwnerPid + ", ownerUid=" + mOwnerUid
+                + ", userId=" + mUserId);
+        pw.println(indent + "info=" + mSessionInfo.toString());
+        pw.println(indent + "published=" + mIsActive);
+        pw.println(indent + "flags=" + mFlags);
+        pw.println(indent + "rating type=" + mRatingType);
+        pw.println(indent + "controllers: " + mControllerCallbacks.size());
+        pw.println(indent + "state=" + (mPlaybackState == null ? null : mPlaybackState.toString()));
+        pw.println(indent + "metadata:" + getShortMetadataString());
+        pw.println(indent + "route requests {");
+        int size = mRequests.size();
+        for (int i = 0; i < size; i++) {
+            pw.println(indent + "  " + mRequests.get(i).toString());
+        }
+        pw.println(indent + "}");
+        pw.println(indent + "route=" + (mRoute == null ? null : mRoute.toString()));
+        pw.println(indent + "connection=" + (mConnection == null ? null : mConnection.toString()));
+        pw.println(indent + "params=" + (mRequest == null ? null : mRequest.toString()));
+    }
+
+    private boolean isActiveState(int state) {
+        for (int i = 0; i < ACTIVE_STATES.length; i++) {
+            if (ACTIVE_STATES[i] == state) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private String getShortMetadataString() {
+        int fields = mMetadata == null ? 0 : mMetadata.size();
+        String title = mMetadata == null ? null : mMetadata
+                .getString(MediaMetadata.METADATA_KEY_TITLE);
+        return "size=" + fields + ", title=" + title;
+    }
+
     private void onDestroy() {
         mService.destroySession(this);
     }
@@ -301,6 +431,34 @@
         }
     }
 
+    private PlaybackState getStateWithUpdatedPosition() {
+        PlaybackState state = mPlaybackState;
+        long duration = -1;
+        if (mMetadata != null && mMetadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
+            duration = mMetadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
+        }
+        PlaybackState result = null;
+        if (state != null) {
+            if (state.getState() == PlaybackState.PLAYSTATE_PLAYING
+                    || state.getState() == PlaybackState.PLAYSTATE_FAST_FORWARDING
+                    || state.getState() == PlaybackState.PLAYSTATE_REWINDING) {
+                long updateTime = state.getLastPositionUpdateTime();
+                if (updateTime > 0) {
+                    long position = (long) (state.getRate()
+                            * (SystemClock.elapsedRealtime() - updateTime)) + state.getPosition();
+                    if (duration >= 0 && position > duration) {
+                        position = duration;
+                    } else if (position < 0) {
+                        position = 0;
+                    }
+                    result = new PlaybackState(state);
+                    result.setState(state.getState(), position, state.getRate());
+                }
+            }
+        }
+        return result == null ? state : result;
+    }
+
     private final RouteConnectionRecord.Listener mConnectionListener
             = new RouteConnectionRecord.Listener() {
         @Override
@@ -333,12 +491,21 @@
         }
 
         @Override
-        public void publish() {
-            mIsPublished = true; // TODO push update to service
+        public void setActive(boolean active) {
+            mIsActive = active;
+            mService.updateSession(MediaSessionRecord.this);
+            mHandler.post(MessageHandler.MSG_UPDATE_SESSION_STATE);
         }
+
         @Override
-        public void setTransportPerformerEnabled() {
-            mTransportPerformerEnabled = true;
+        public void setFlags(int flags) {
+            if ((flags & Session.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
+                int pid = getCallingPid();
+                int uid = getCallingUid();
+                mService.enforcePhoneStatePermission(pid, uid);
+            }
+            mFlags = flags;
+            mHandler.post(MessageHandler.MSG_UPDATE_SESSION_STATE);
         }
 
         @Override
@@ -349,7 +516,13 @@
 
         @Override
         public void setPlaybackState(PlaybackState state) {
+            int oldState = mPlaybackState == null ? 0 : mPlaybackState.getState();
+            int newState = state == null ? 0 : state.getState();
+            if (isActiveState(oldState) && newState == PlaybackState.PLAYSTATE_PAUSED) {
+                mLastActiveTime = SystemClock.elapsedRealtime();
+            }
             mPlaybackState = state;
+            mService.onSessionPlaystateChange(MediaSessionRecord.this, oldState, newState);
             mHandler.post(MessageHandler.MSG_UPDATE_PLAYBACK_STATE);
         }
 
@@ -603,7 +776,7 @@
 
         @Override
         public PlaybackState getPlaybackState() {
-            return mPlaybackState;
+            return getStateWithUpdatedPosition();
         }
 
         @Override
@@ -613,7 +786,7 @@
 
         @Override
         public boolean isTransportControlEnabled() {
-            return mTransportPerformerEnabled;
+            return MediaSessionRecord.this.isTransportControlEnabled();
         }
 
         @Override
@@ -629,6 +802,7 @@
         private static final int MSG_SEND_EVENT = 4;
         private static final int MSG_UPDATE_ROUTE_FILTERS = 5;
         private static final int MSG_SEND_COMMAND = 6;
+        private static final int MSG_UPDATE_SESSION_STATE = 7;
 
         public MessageHandler(Looper looper) {
             super(looper);
@@ -653,6 +827,9 @@
                             (Pair<RouteCommand, ResultReceiver>) msg.obj;
                     pushRouteCommand(cmd.first, cmd.second);
                     break;
+                case MSG_UPDATE_SESSION_STATE:
+                    // TODO add session state
+                    break;
             }
         }
 
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index bc91370..008f9be 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -16,59 +16,77 @@
 
 package com.android.server.media;
 
+import android.Manifest;
+import android.app.ActivityManager;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.media.routeprovider.RouteRequest;
 import android.media.session.ISession;
 import android.media.session.ISessionCallback;
+import android.media.session.ISessionController;
 import android.media.session.ISessionManager;
+import android.media.session.PlaybackState;
 import android.media.session.RouteInfo;
 import android.media.session.RouteOptions;
 import android.os.Binder;
 import android.os.Handler;
+import android.os.IBinder;
+import android.os.Process;
 import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.server.SystemService;
+import com.android.server.Watchdog;
+import com.android.server.Watchdog.Monitor;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * System implementation of MediaSessionManager
  */
-public class MediaSessionService extends SystemService {
+public class MediaSessionService extends SystemService implements Monitor {
     private static final String TAG = "MediaSessionService";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private final SessionManagerImpl mSessionManagerImpl;
     private final MediaRouteProviderWatcher mRouteProviderWatcher;
+    private final MediaSessionStack mPriorityStack;
 
-    private final ArrayList<MediaSessionRecord> mSessions
-            = new ArrayList<MediaSessionRecord>();
+    private final ArrayList<MediaSessionRecord> mRecords = new ArrayList<MediaSessionRecord>();
     private final ArrayList<MediaRouteProviderProxy> mProviders
             = new ArrayList<MediaRouteProviderProxy>();
     private final Object mLock = new Object();
-    // TODO do we want a separate thread for handling mediasession messages?
     private final Handler mHandler = new Handler();
 
+    private MediaSessionRecord mPrioritySession;
+
     // Used to keep track of the current request to show routes for a specific
     // session so we drop late callbacks properly.
     private int mShowRoutesRequestId = 0;
 
-    // TODO refactor to have per user state. See MediaRouterService for an
-    // example
+    // TODO refactor to have per user state for providers. See
+    // MediaRouterService for an example
 
     public MediaSessionService(Context context) {
         super(context);
         mSessionManagerImpl = new SessionManagerImpl();
         mRouteProviderWatcher = new MediaRouteProviderWatcher(context, mProviderWatcherCallback,
                 mHandler, context.getUserId());
+        mPriorityStack = new MediaSessionStack();
     }
 
     @Override
     public void onStart() {
         publishBinderService(Context.MEDIA_SESSION_SERVICE, mSessionManagerImpl);
         mRouteProviderWatcher.start();
+        Watchdog.getInstance().addMonitor(this);
     }
 
     /**
@@ -114,20 +132,55 @@
         }
     }
 
+    public void updateSession(MediaSessionRecord record) {
+        synchronized (mLock) {
+            mPriorityStack.onSessionStateChange(record);
+            if (record.isSystemPriority()) {
+                if (record.isActive()) {
+                    if (mPrioritySession != null) {
+                        Log.w(TAG, "Replacing existing priority session with a new session");
+                    }
+                    mPrioritySession = record;
+                } else {
+                    if (mPrioritySession == record) {
+                        mPrioritySession = null;
+                    }
+                }
+            }
+        }
+    }
+
+    public void onSessionPlaystateChange(MediaSessionRecord record, int oldState, int newState) {
+        synchronized (mLock) {
+            mPriorityStack.onPlaystateChange(record, oldState, newState);
+        }
+    }
+
+    @Override
+    public void monitor() {
+        synchronized (mLock) {
+            // Check for deadlock
+        }
+    }
+
     void sessionDied(MediaSessionRecord session) {
-        synchronized (mSessions) {
+        synchronized (mLock) {
             destroySessionLocked(session);
         }
     }
 
     void destroySession(MediaSessionRecord session) {
-        synchronized (mSessions) {
+        synchronized (mLock) {
             destroySessionLocked(session);
         }
     }
 
     private void destroySessionLocked(MediaSessionRecord session) {
-        mSessions.remove(session);
+        mRecords.remove(session);
+        mPriorityStack.removeSession(session);
+        if (session == mPrioritySession) {
+            mPrioritySession = null;
+        }
     }
 
     private void enforcePackageName(String packageName, int uid) {
@@ -144,31 +197,113 @@
         throw new IllegalArgumentException("packageName is not owned by the calling process");
     }
 
-    private MediaSessionRecord createSessionInternal(int pid, String packageName,
-            ISessionCallback cb, String tag) {
-        synchronized (mLock) {
-            return createSessionLocked(pid, packageName, cb, tag);
+    protected void enforcePhoneStatePermission(int pid, int uid) {
+        if (getContext().checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, pid, uid)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Must hold the MODIFY_PHONE_STATE permission.");
         }
     }
 
-    private MediaSessionRecord createSessionLocked(int pid, String packageName,
-            ISessionCallback cb, String tag) {
-        final MediaSessionRecord session = new MediaSessionRecord(pid, packageName, cb, tag, this,
-                mHandler);
+    /**
+     * 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
+     * for the caller's user</li>
+     * </ul>
+     */
+    private void enforceMediaPermissions(ComponentName compName, int pid, int uid,
+            int resolvedUserId) {
+        if (getContext()
+                .checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
+                    != PackageManager.PERMISSION_GRANTED
+                && !isEnabledNotificationListener(compName, UserHandle.getUserId(uid),
+                        resolvedUserId)) {
+            throw new SecurityException("Missing permission to control media.");
+        }
+    }
+
+    /**
+     * This checks if the component is an enabled notification listener for the
+     * specified user. Enabled components may only operate on behalf of the user
+     * they're running as.
+     *
+     * @param compName The component that is enabled.
+     * @param userId The user id of the caller.
+     * @param forUserId The user id they're making the request on behalf of.
+     * @return True if the component is enabled, false otherwise
+     */
+    private boolean isEnabledNotificationListener(ComponentName compName, int userId,
+            int forUserId) {
+        if (userId != forUserId) {
+            // You may not access another user's content as an enabled listener.
+            return false;
+        }
+        if (compName != null) {
+            final String enabledNotifListeners = Settings.Secure.getStringForUser(
+                    getContext().getContentResolver(),
+                    Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
+                    userId);
+            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 (compName.equals(component)) {
+                            if (DEBUG) {
+                                Log.d(TAG, "ok to get sessions: " + component +
+                                        " is authorized notification listener");
+                            }
+                            return true;
+                        }
+                    }
+                }
+            }
+            if (DEBUG) {
+                Log.d(TAG, "not ok to get sessions, " + compName +
+                        " is not in list of ENABLED_NOTIFICATION_LISTENERS for user " + userId);
+            }
+        }
+        return false;
+    }
+
+    private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId,
+            String callerPackageName, ISessionCallback cb, String tag) {
+        synchronized (mLock) {
+            return createSessionLocked(callerPid, callerUid, userId, callerPackageName, cb, tag);
+        }
+    }
+
+    private MediaSessionRecord createSessionLocked(int callerPid, int callerUid, int userId,
+            String callerPackageName, ISessionCallback cb, String tag) {
+        final MediaSessionRecord session = new MediaSessionRecord(callerPid, callerUid, userId,
+                callerPackageName, cb, tag, this, mHandler);
         try {
             cb.asBinder().linkToDeath(session, 0);
         } catch (RemoteException e) {
             throw new RuntimeException("Media Session owner died prematurely.", e);
         }
-        synchronized (mSessions) {
-            mSessions.add(session);
-        }
+        mRecords.add(session);
+        mPriorityStack.addSession(session);
         if (DEBUG) {
-            Log.d(TAG, "Created session for package " + packageName + " with tag " + tag);
+            Log.d(TAG, "Created session for package " + callerPackageName + " with tag " + tag);
         }
         return session;
     }
 
+    private int findIndexOfSessionForIdLocked(String sessionId) {
+        for (int i = mRecords.size() - 1; i >= 0; i--) {
+            MediaSessionRecord session = mRecords.get(i);
+            if (TextUtils.equals(session.getSessionInfo().getId(), sessionId)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
     private MediaRouteProviderProxy getProviderLocked(String providerId) {
         for (int i = mProviders.size() - 1; i >= 0; i--) {
             MediaRouteProviderProxy provider = mProviders.get(i);
@@ -179,14 +314,9 @@
         return null;
     }
 
-    private int findIndexOfSessionForIdLocked(String sessionId) {
-        for (int i = mSessions.size() - 1; i >= 0; i--) {
-            MediaSessionRecord session = mSessions.get(i);
-            if (TextUtils.equals(session.getSessionInfo().getId(), sessionId)) {
-                return i;
-            }
-        }
-        return -1;
+    private boolean isSessionDiscoverable(MediaSessionRecord record) {
+        // TODO probably want to check more than if it's published.
+        return record.isActive();
     }
 
     private MediaRouteProviderWatcher.Callback mProviderWatcherCallback
@@ -220,7 +350,7 @@
             synchronized (mLock) {
                 int index = findIndexOfSessionForIdLocked(sessionId);
                 if (index != -1 && routes != null && routes.size() > 0) {
-                    MediaSessionRecord record = mSessions.get(index);
+                    MediaSessionRecord record = mRecords.get(index);
                     record.selectRoute(routes.get(0));
                 }
             }
@@ -232,7 +362,7 @@
             synchronized (mLock) {
                 int index = findIndexOfSessionForIdLocked(sessionId);
                 if (index != -1) {
-                    MediaSessionRecord session = mSessions.get(index);
+                    MediaSessionRecord session = mRecords.get(index);
                     session.setRouteConnected(route, options.getConnectionOptions(), connection);
                 }
             }
@@ -244,21 +374,95 @@
         // ActivityManagerNative.handleIncomingUser and stash result for use
         // when starting services on that session's behalf.
         @Override
-        public ISession createSession(String packageName, ISessionCallback cb, String tag)
-                throws RemoteException {
+        public ISession createSession(String packageName, ISessionCallback cb, String tag,
+                int userId) throws RemoteException {
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
             try {
                 enforcePackageName(packageName, uid);
+                int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+                        false /* allowAll */, true /* requireFull */, "createSession", packageName);
                 if (cb == null) {
                     throw new IllegalArgumentException("Controller callback cannot be null");
                 }
-                return createSessionInternal(pid, packageName, cb, tag).getSessionBinder();
+                return createSessionInternal(pid, uid, resolvedUserId, packageName, cb, tag)
+                        .getSessionBinder();
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
         }
+
+        @Override
+        public List<IBinder> getSessions(ComponentName componentName, int userId) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+
+            try {
+                String packageName = null;
+                if (componentName != null) {
+                    // If they gave us a component name verify they own the
+                    // package
+                    packageName = componentName.getPackageName();
+                    enforcePackageName(packageName, uid);
+                }
+                // Check that they can make calls on behalf of the user and
+                // get the final user id
+                int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+                        true /* allowAll */, true /* requireFull */, "getSessions", packageName);
+                // Check if they have the permissions or their component is
+                // enabled for the user they're calling from.
+                enforceMediaPermissions(componentName, pid, uid, resolvedUserId);
+                ArrayList<IBinder> binders = new ArrayList<IBinder>();
+                synchronized (mLock) {
+                    ArrayList<MediaSessionRecord> records = mPriorityStack
+                            .getActiveSessions(resolvedUserId);
+                    int size = records.size();
+                    for (int i = 0; i < size; i++) {
+                        binders.add(records.get(i).getControllerBinder().asBinder());
+                    }
+                }
+                return binders;
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
+            if (getContext().checkCallingOrSelfPermission(Manifest.permission.DUMP)
+                    != PackageManager.PERMISSION_GRANTED) {
+                pw.println("Permission Denial: can't dump MediaSessionService from from pid="
+                        + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid());
+                return;
+            }
+
+            pw.println("MEDIA SESSION SERVICE (dumpsys media_session)");
+            pw.println();
+
+            synchronized (mLock) {
+                pw.println("Session for calls:" + mPrioritySession);
+                if (mPrioritySession != null) {
+                    mPrioritySession.dump(pw, "");
+                }
+                int count = mRecords.size();
+                pw.println(count + " Sessions:");
+                for (int i = 0; i < count; i++) {
+                    mRecords.get(i).dump(pw, "");
+                    pw.println();
+                }
+                mPriorityStack.dump(pw, "");
+
+                pw.println("Providers:");
+                count = mProviders.size();
+                for (int i = 0; i < count; i++) {
+                    MediaRouteProviderProxy provider = mProviders.get(i);
+                    provider.dump(pw, "");
+                }
+            }
+        }
     }
 
 }
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
new file mode 100644
index 0000000..1e1818d
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.media;
+
+import android.media.session.PlaybackState;
+import android.media.session.Session;
+import android.os.UserHandle;
+import android.text.TextUtils;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Keeps track of media sessions and their priority for notifications, media
+ * button routing, etc.
+ */
+public class MediaSessionStack {
+    /**
+     * These are states that usually indicate the user took an action and should
+     * bump priority regardless of the old state.
+     */
+    private static final int[] ALWAYS_PRIORITY_STATES = {
+            PlaybackState.PLAYSTATE_FAST_FORWARDING,
+            PlaybackState.PLAYSTATE_REWINDING,
+            PlaybackState.PLAYSTATE_SKIPPING_BACKWARDS,
+            PlaybackState.PLAYSTATE_SKIPPING_FORWARDS };
+    /**
+     * These are states that usually indicate the user took an action if they
+     * were entered from a non-priority state.
+     */
+    private static final int[] TRANSITION_PRIORITY_STATES = {
+            PlaybackState.PLAYSTATE_BUFFERING,
+            PlaybackState.PLAYSTATE_CONNECTING,
+            PlaybackState.PLAYSTATE_PLAYING };
+
+    private final ArrayList<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>();
+
+    private MediaSessionRecord mCachedButtonReceiver;
+    private MediaSessionRecord mCachedDefault;
+    private ArrayList<MediaSessionRecord> mCachedActiveList;
+    private ArrayList<MediaSessionRecord> mCachedTransportControlList;
+
+    /**
+     * Add a record to the priority tracker.
+     *
+     * @param record The record to add.
+     */
+    public void addSession(MediaSessionRecord record) {
+        mSessions.add(record);
+        clearCache();
+    }
+
+    /**
+     * Remove a record from the priority tracker.
+     *
+     * @param record The record to remove.
+     */
+    public void removeSession(MediaSessionRecord record) {
+        mSessions.remove(record);
+        clearCache();
+    }
+
+    /**
+     * Notify the priority tracker that a session's state changed.
+     *
+     * @param record The record that changed.
+     * @param oldState Its old playback state.
+     * @param newState Its new playback state.
+     */
+    public void onPlaystateChange(MediaSessionRecord record, int oldState, int newState) {
+        if (shouldUpdatePriority(oldState, newState)) {
+            mSessions.remove(record);
+            mSessions.add(0, record);
+            clearCache();
+        }
+    }
+
+    /**
+     * Handle any stack changes that need to occur in response to a session
+     * state change. TODO add the old and new session state as params
+     *
+     * @param record The record that changed.
+     */
+    public void onSessionStateChange(MediaSessionRecord record) {
+        // For now just clear the cache. Eventually we'll selectively clear
+        // depending on what changed.
+        clearCache();
+    }
+
+    /**
+     * Get the current priority sorted list of active sessions. The most
+     * important session is at index 0 and the least important at size - 1.
+     *
+     * @param userId The user to check.
+     * @return All the active sessions in priority order.
+     */
+    public ArrayList<MediaSessionRecord> getActiveSessions(int userId) {
+        if (mCachedActiveList == null) {
+            mCachedActiveList = getPriorityListLocked(true, 0, userId);
+        }
+        return mCachedActiveList;
+    }
+
+    /**
+     * Get the current priority sorted list of active sessions that use
+     * transport controls. The most important session is at index 0 and the
+     * least important at size -1.
+     *
+     * @param userId The user to check.
+     * @return All the active sessions that handle transport controls in
+     *         priority order.
+     */
+    public ArrayList<MediaSessionRecord> getTransportControlSessions(int userId) {
+        if (mCachedTransportControlList == null) {
+            mCachedTransportControlList = getPriorityListLocked(true,
+                    Session.FLAG_HANDLES_TRANSPORT_CONTROLS, userId);
+        }
+        return mCachedTransportControlList;
+    }
+
+    /**
+     * Get the highest priority active session.
+     *
+     * @param userId The user to check.
+     * @return The current highest priority session or null.
+     */
+    public MediaSessionRecord getDefaultSession(int userId) {
+        if (mCachedDefault != null) {
+            return mCachedDefault;
+        }
+        ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, 0, userId);
+        if (records.size() > 0) {
+            return records.get(0);
+        }
+        return null;
+    }
+
+    /**
+     * Get the highest priority session that can handle media buttons.
+     *
+     * @param userId The user to check.
+     * @return The default media button session or null.
+     */
+    public MediaSessionRecord getDefaultMediaButtonSession(int userId) {
+        if (mCachedButtonReceiver != null) {
+            return mCachedButtonReceiver;
+        }
+        ArrayList<MediaSessionRecord> records = getPriorityListLocked(true,
+                Session.FLAG_HANDLES_MEDIA_BUTTONS, userId);
+        if (records.size() > 0) {
+            mCachedButtonReceiver = records.get(0);
+        }
+        return mCachedButtonReceiver;
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        ArrayList<MediaSessionRecord> sortedSessions = getPriorityListLocked(false, 0,
+                UserHandle.USER_ALL);
+        int count = sortedSessions.size();
+        pw.println(prefix + "Sessions Stack - have " + count + " sessions:");
+        String indent = prefix + "  ";
+        for (int i = 0; i < count; i++) {
+            MediaSessionRecord record = sortedSessions.get(i);
+            record.dump(pw, indent);
+            pw.println();
+        }
+    }
+
+    /**
+     * Get a priority sorted list of sessions. Can filter to only return active
+     * sessions or sessions with specific flags.
+     *
+     * @param activeOnly True to only return active sessions, false to return
+     *            all sessions.
+     * @param withFlags Only return sessions with all the specified flags set. 0
+     *            returns all sessions.
+     * @param userId The user to get sessions for. {@link UserHandle#USER_ALL}
+     *            will return sessions for all users.
+     * @return The priority sorted list of sessions.
+     */
+    private ArrayList<MediaSessionRecord> getPriorityListLocked(boolean activeOnly, int withFlags,
+            int userId) {
+        ArrayList<MediaSessionRecord> result = new ArrayList<MediaSessionRecord>();
+        int lastLocalIndex = 0;
+        int lastActiveIndex = 0;
+        int lastPublishedIndex = 0;
+
+        int size = mSessions.size();
+        for (int i = 0; i < size; i++) {
+            final MediaSessionRecord session = mSessions.get(i);
+
+            if (userId != UserHandle.USER_ALL && userId != session.getUserId()) {
+                // Filter out sessions for the wrong user
+                continue;
+            }
+            if ((session.getFlags() & withFlags) != withFlags) {
+                // Filter out sessions with the wrong flags
+                continue;
+            }
+            if (!session.isActive()) {
+                if (!activeOnly) {
+                    // If we're getting unpublished as well always put them at
+                    // the end
+                    result.add(session);
+                }
+                continue;
+            }
+
+            if (session.isSystemPriority()) {
+                // System priority sessions are special and always go at the
+                // front. We expect there to only be one of these at a time.
+                result.add(0, session);
+                lastLocalIndex++;
+                lastActiveIndex++;
+                lastPublishedIndex++;
+            } else if (session.isPlaybackActive()) {
+                // TODO replace getRoute() == null with real local route check
+                if(session.getRoute() == null) {
+                    // Active local sessions get top priority
+                    result.add(lastLocalIndex, session);
+                    lastLocalIndex++;
+                    lastActiveIndex++;
+                    lastPublishedIndex++;
+                } else {
+                    // Then active remote sessions
+                    result.add(lastActiveIndex, session);
+                    lastActiveIndex++;
+                    lastPublishedIndex++;
+                }
+            } else {
+                // inactive sessions go at the end in order of whoever last did
+                // something.
+                result.add(lastPublishedIndex, session);
+                lastPublishedIndex++;
+            }
+        }
+
+        return result;
+    }
+
+    private boolean shouldUpdatePriority(int oldState, int newState) {
+        if (containsState(newState, ALWAYS_PRIORITY_STATES)) {
+            return true;
+        }
+        if (!containsState(oldState, TRANSITION_PRIORITY_STATES)
+                && containsState(newState, TRANSITION_PRIORITY_STATES)) {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean containsState(int state, int[] states) {
+        for (int i = 0; i < states.length; i++) {
+            if (states[i] == state) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void clearCache() {
+        mCachedDefault = null;
+        mCachedButtonReceiver = null;
+        mCachedActiveList = null;
+        mCachedTransportControlList = null;
+    }
+}
diff --git a/services/core/java/com/android/server/media/RouteConnectionRecord.java b/services/core/java/com/android/server/media/RouteConnectionRecord.java
index 8da0f95..90ddf29 100644
--- a/services/core/java/com/android/server/media/RouteConnectionRecord.java
+++ b/services/core/java/com/android/server/media/RouteConnectionRecord.java
@@ -29,10 +29,14 @@
 public class RouteConnectionRecord {
     private static final String TAG = "RouteConnRecord";
     private final IRouteConnection mBinder;
+    private final String mPackageName;
+    private final int mUid;
     private Listener mListener;
 
-    public RouteConnectionRecord(IRouteConnection binder) {
+    public RouteConnectionRecord(IRouteConnection binder, String packageName, int uid) {
         mBinder = binder;
+        mPackageName = packageName;
+        mUid = uid;
     }
 
     /**
@@ -89,6 +93,12 @@
         }
     }
 
+    @Override
+    public String toString() {
+        return "RouteConnection { binder=" + mBinder.toString() + ", package=" + mPackageName
+                + ", uid=" + mUid + "}";
+    }
+
     /**
      * Listener to receive updates from the provider for this connection.
      */
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 855ae23..416a6b1 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -410,7 +410,7 @@
         }
 
         @Override
-        public void onImportanceChanged(int pid, int uid, int importance) {
+        public void onProcessStateChanged(int pid, int uid, int procState) {
         }
 
         @Override
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 5567944..007032e 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -16,7 +16,13 @@
 
 package com.android.server.notification;
 
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.IBinder;
@@ -28,31 +34,34 @@
 import android.service.notification.ConditionProviderService;
 import android.service.notification.IConditionListener;
 import android.service.notification.IConditionProvider;
+import android.service.notification.ZenModeConfig;
+import android.text.format.DateUtils;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Slog;
 
 import com.android.internal.R;
 
-import libcore.util.Objects;
-
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Date;
 
 public class ConditionProviders extends ManagedServices {
+    private static final Condition[] NO_CONDITIONS = new Condition[0];
 
     private final ZenModeHelper mZenModeHelper;
     private final ArrayMap<IBinder, IConditionListener> mListeners
             = new ArrayMap<IBinder, IConditionListener>();
-    private final ArrayMap<Uri, ManagedServiceInfo> mConditions
-            = new ArrayMap<Uri, ManagedServiceInfo>();
-
-    private Uri mCurrentConditionId;
+    private final ArrayList<ConditionRecord> mRecords = new ArrayList<ConditionRecord>();
+    private final CountdownConditionHelper mCountdownHelper = new CountdownConditionHelper();
 
     public ConditionProviders(Context context, Handler handler,
             UserProfiles userProfiles, ZenModeHelper zenModeHelper) {
         super(context, handler, new Object(), userProfiles);
         mZenModeHelper = zenModeHelper;
         mZenModeHelper.addCallback(new ZenModeHelperCallback());
+        loadZenConfig();
     }
 
     @Override
@@ -71,20 +80,13 @@
     public void dump(PrintWriter pw) {
         super.dump(pw);
         synchronized(mMutex) {
-            pw.print("    mCurrentConditionId="); pw.println(mCurrentConditionId);
             pw.print("    mListeners("); pw.print(mListeners.size()); pw.println("):");
             for (int i = 0; i < mListeners.size(); i++) {
                 pw.print("      "); pw.println(mListeners.keyAt(i));
             }
-            pw.print("    mConditions("); pw.print(mConditions.size()); pw.println("):");
-            for (int i = 0; i < mConditions.size(); i++) {
-                pw.print("      "); pw.print(mConditions.keyAt(i));
-                final ManagedServiceInfo info = mConditions.valueAt(i);
-                pw.print(" -> "); pw.print(info.component);
-                if (!mServices.contains(info)) {
-                    pw.print(" (orphan)");
-                }
-                pw.println();
+            pw.print("    mRecords("); pw.print(mRecords.size()); pw.println("):");
+            for (int i = 0; i < mRecords.size(); i++) {
+                pw.print("      "); pw.println(mRecords.get(i));
             }
         }
     }
@@ -95,29 +97,49 @@
     }
 
     @Override
-    protected void onServiceAdded(IInterface service) {
-        Slog.d(TAG, "onServiceAdded " + service);
-        final IConditionProvider provider = (IConditionProvider) service;
+    protected void onServiceAdded(ManagedServiceInfo info) {
+        Slog.d(TAG, "onServiceAdded " + info);
+        final IConditionProvider provider = provider(info);
         try {
             provider.onConnected();
         } catch (RemoteException e) {
             // we tried
         }
+        synchronized (mMutex) {
+            final int N = mRecords.size();
+            for(int i = 0; i < N; i++) {
+                final ConditionRecord r = mRecords.get(i);
+                if (!r.component.equals(info.component)) continue;
+                r.info = info;
+                // if automatic, auto-subscribe
+                if (r.isAutomatic) {
+                    try {
+                        final Uri id = r.id;
+                        if (DEBUG) Slog.d(TAG, "Auto-subscribing to configured condition " + id);
+                        provider.onSubscribe(id);
+                    } catch (RemoteException e) {
+                        // we tried
+                    }
+                }
+            }
+        }
     }
 
     @Override
     protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
         if (removed == null) return;
-        if (mCurrentConditionId != null) {
-            if (removed.equals(mConditions.get(mCurrentConditionId))) {
-                mCurrentConditionId = null;
+        for (int i = mRecords.size() - 1; i >= 0; i--) {
+            final ConditionRecord r = mRecords.get(i);
+            if (!r.component.equals(removed.component)) continue;
+            if (r.isManual) {
+                // removing the current manual condition, exit zen
                 mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF);
             }
-        }
-        for (int i = mConditions.size() - 1; i >= 0; i--) {
-            if (removed.equals(mConditions.valueAt(i))) {
-                mConditions.removeAt(i);
+            if (r.isAutomatic) {
+                // removing an automatic condition, exit zen
+                mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF);
             }
+            mRecords.remove(i);
         }
     }
 
@@ -127,14 +149,15 @@
         }
     }
 
-    public void requestZenModeConditions(IConditionListener callback, boolean requested) {
+    public void requestZenModeConditions(IConditionListener callback, int relevance) {
         synchronized(mMutex) {
             if (DEBUG) Slog.d(TAG, "requestZenModeConditions callback=" + callback
-                    + " requested=" + requested);
+                    + " relevance=" + Condition.relevanceToString(relevance));
             if (callback == null) return;
-            if (requested) {
+            relevance = relevance & (Condition.FLAG_RELEVANT_NOW | Condition.FLAG_RELEVANT_ALWAYS);
+            if (relevance != 0) {
                 mListeners.put(callback.asBinder(), callback);
-                requestConditionsLocked(Condition.FLAG_RELEVANT_NOW);
+                requestConditionsLocked(relevance);
             } else {
                 mListeners.remove(callback.asBinder());
                 if (mListeners.isEmpty()) {
@@ -144,25 +167,51 @@
         }
     }
 
+    private Condition[] validateConditions(String pkg, Condition[] conditions) {
+        if (conditions == null || conditions.length == 0) return null;
+        final int N = conditions.length;
+        final ArrayMap<Uri, Condition> valid = new ArrayMap<Uri, Condition>(N);
+        for (int i = 0; i < N; i++) {
+            final Uri id = conditions[i].id;
+            if (!Condition.isValidId(id, pkg)) {
+                Slog.w(TAG, "Ignoring condition from " + pkg + " for invalid id: " + id);
+                continue;
+            }
+            if (valid.containsKey(id)) {
+                Slog.w(TAG, "Ignoring condition from " + pkg + " for duplicate id: " + id);
+                continue;
+            }
+            valid.put(id, conditions[i]);
+        }
+        if (valid.size() == 0) return null;
+        if (valid.size() == N) return conditions;
+        final Condition[] rt = new Condition[valid.size()];
+        for (int i = 0; i < rt.length; i++) {
+            rt[i] = valid.valueAt(i);
+        }
+        return rt;
+    }
+
+    private ConditionRecord getRecordLocked(Uri id, ComponentName component) {
+        final int N = mRecords.size();
+        for (int i = 0; i < N; i++) {
+            final ConditionRecord r = mRecords.get(i);
+            if (r.id.equals(id) && r.component.equals(component)) {
+                return r;
+            }
+        }
+        final ConditionRecord r = new ConditionRecord(id, component);
+        mRecords.add(r);
+        return r;
+    }
+
     public void notifyConditions(String pkg, ManagedServiceInfo info, Condition[] conditions) {
         synchronized(mMutex) {
             if (DEBUG) Slog.d(TAG, "notifyConditions pkg=" + pkg + " info=" + info + " conditions="
                     + (conditions == null ? null : Arrays.asList(conditions)));
+            conditions = validateConditions(pkg, conditions);
             if (conditions == null || conditions.length == 0) return;
             final int N = conditions.length;
-            boolean valid = true;
-            for (int i = 0; i < N; i++) {
-                final Uri id = conditions[i].id;
-                if (!Condition.isValidId(id, pkg)) {
-                    Slog.w(TAG, "Ignoring conditions from " + pkg + " for invalid id: " + id);
-                    valid = false;
-                }
-            }
-            if (!valid) return;
-
-            for (int i = 0; i < N; i++) {
-                mConditions.put(conditions[i].id, info);
-            }
             for (IConditionListener listener : mListeners.values()) {
                 try {
                     listener.onConditionsReceived(conditions);
@@ -170,62 +219,155 @@
                     Slog.w(TAG, "Error sending conditions to listener " + listener, e);
                 }
             }
-            if (mCurrentConditionId != null) {
-                for (int i = 0; i < N; i++) {
-                    final Condition c = conditions[i];
-                    if (!c.id.equals(mCurrentConditionId)) continue;
-                    if (c.state == Condition.STATE_TRUE || c.state == Condition.STATE_ERROR) {
-                        triggerExitLocked(c.state == Condition.STATE_ERROR);
-                        return;
+            for (int i = 0; i < N; i++) {
+                final Condition c = conditions[i];
+                final ConditionRecord r = getRecordLocked(c.id, info.component);
+                r.info = info;
+                r.condition = c;
+                // if manual, exit zen if false (or failed)
+                if (r.isManual) {
+                    if (c.state == Condition.STATE_FALSE || c.state == Condition.STATE_ERROR) {
+                        final boolean failed = c.state == Condition.STATE_ERROR;
+                        if (failed) {
+                            Slog.w(TAG, "Exit zen: manual condition failed: " + c);
+                        } else if (DEBUG) {
+                            Slog.d(TAG, "Exit zen: manual condition false: " + c);
+                        }
+                        mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF);
+                        unsubscribeLocked(r);
+                        r.isManual = false;
+                    }
+                }
+                // if automatic, exit zen if false (or failed), enter zen if true
+                if (r.isAutomatic) {
+                    if (c.state == Condition.STATE_FALSE || c.state == Condition.STATE_ERROR) {
+                        final boolean failed = c.state == Condition.STATE_ERROR;
+                        if (failed) {
+                            Slog.w(TAG, "Exit zen: automatic condition failed: " + c);
+                        } else if (DEBUG) {
+                            Slog.d(TAG, "Exit zen: automatic condition false: " + c);
+                        }
+                        mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF);
+                    } else if (c.state == Condition.STATE_TRUE) {
+                        Slog.d(TAG, "Enter zen: automatic condition true: " + c);
+                        mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_ON);
                     }
                 }
             }
         }
     }
 
-    private void triggerExitLocked(boolean error) {
-        if (error) {
-            Slog.w(TAG, "Zen mode exit condition failed");
-        } else if (DEBUG) {
-            Slog.d(TAG, "Zen mode exit condition triggered");
-        }
-        mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF);
-        unsubscribeLocked(mCurrentConditionId);
-        mCurrentConditionId = null;
-    }
-
     public void setZenModeCondition(Uri conditionId) {
+        if (DEBUG) Slog.d(TAG, "setZenModeCondition " + conditionId);
         synchronized(mMutex) {
-            if (DEBUG) Slog.d(TAG, "setZenModeCondition " + conditionId);
-            if (Objects.equal(mCurrentConditionId, conditionId)) return;
-
-            if (mCurrentConditionId != null) {
-                unsubscribeLocked(mCurrentConditionId);
-            }
-            if (conditionId != null) {
-                final ManagedServiceInfo info = mConditions.get(conditionId);
-                final IConditionProvider provider = provider(info);
-                if (provider == null) return;
-                try {
-                    provider.onSubscribe(conditionId);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Error subscribing to " + conditionId
-                            + " from " + info.component, e);
+            final int N = mRecords.size();
+            for (int i = 0; i < N; i++) {
+                final ConditionRecord r = mRecords.get(i);
+                final boolean idEqual = r.id.equals(conditionId);
+                if (r.isManual && !idEqual) {
+                    // was previous manual condition, unsubscribe
+                    unsubscribeLocked(r);
+                    r.isManual = false;
+                } else if (idEqual && !r.isManual) {
+                    // is new manual condition, subscribe
+                    subscribeLocked(r);
+                    r.isManual = true;
                 }
             }
-            mCurrentConditionId = conditionId;
+        }
+        mCountdownHelper.setZenModeCondition(conditionId);
+    }
+
+    private void subscribeLocked(ConditionRecord r) {
+        if (DEBUG) Slog.d(TAG, "subscribeLocked " + r);
+        final IConditionProvider provider = provider(r);
+        if (provider == null) {
+            Slog.w(TAG, "subscribeLocked: no provider");
+            return;
+        }
+        try {
+            provider.onSubscribe(r.id);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Error subscribing to " + r, e);
         }
     }
 
-    private void unsubscribeLocked(Uri conditionId) {
-        final ManagedServiceInfo info = mConditions.get(mCurrentConditionId);
-        final IConditionProvider provider = provider(info);
-        if (provider == null) return;
-        try {
-            provider.onUnsubscribe(conditionId);
-        } catch (RemoteException e) {
-            Slog.w(TAG, "Error unsubscribing to " + conditionId + " from " + info.component, e);
+    private static <T> ArraySet<T> safeSet(T... items) {
+        final ArraySet<T> rt = new ArraySet<T>();
+        if (items == null || items.length == 0) return rt;
+        final int N = items.length;
+        for (int i = 0; i < N; i++) {
+            final T item = items[i];
+            if (item != null) {
+                rt.add(item);
+            }
         }
+        return rt;
+    }
+
+    public void setAutomaticZenModeConditions(Uri[] conditionIds) {
+        setAutomaticZenModeConditions(conditionIds, true /*save*/);
+    }
+
+    private void setAutomaticZenModeConditions(Uri[] conditionIds, boolean save) {
+        if (DEBUG) Slog.d(TAG, "setAutomaticZenModeConditions "
+                + (conditionIds == null ? null : Arrays.asList(conditionIds)));
+        synchronized(mMutex) {
+            final ArraySet<Uri> newIds = safeSet(conditionIds);
+            final int N = mRecords.size();
+            boolean changed = false;
+            for (int i = 0; i < N; i++) {
+                final ConditionRecord r = mRecords.get(i);
+                final boolean automatic = newIds.contains(r.id);
+                if (!r.isAutomatic && automatic) {
+                    // subscribe to new automatic
+                    subscribeLocked(r);
+                    r.isAutomatic = true;
+                    changed = true;
+                } else if (r.isAutomatic && !automatic) {
+                    // unsubscribe from old automatic
+                    unsubscribeLocked(r);
+                    r.isAutomatic = false;
+                    changed = true;
+                }
+            }
+            if (save && changed) {
+                saveZenConfigLocked();
+            }
+        }
+    }
+
+    public Condition[] getAutomaticZenModeConditions() {
+        synchronized(mMutex) {
+            final int N = mRecords.size();
+            ArrayList<Condition> rt = null;
+            for (int i = 0; i < N; i++) {
+                final ConditionRecord r = mRecords.get(i);
+                if (r.isAutomatic && r.condition != null) {
+                    if (rt == null) rt = new ArrayList<Condition>();
+                    rt.add(r.condition);
+                }
+            }
+            return rt == null ? NO_CONDITIONS : rt.toArray(new Condition[rt.size()]);
+        }
+    }
+
+    private void unsubscribeLocked(ConditionRecord r) {
+        if (DEBUG) Slog.d(TAG, "unsubscribeLocked " + r);
+        final IConditionProvider provider = provider(r);
+        if (provider == null) {
+            Slog.w(TAG, "unsubscribeLocked: no provider");
+            return;
+        }
+        try {
+            provider.onUnsubscribe(r.id);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Error unsubscribing to " + r, e);
+        }
+    }
+
+    private static IConditionProvider provider(ConditionRecord r) {
+        return r == null ? null : provider(r.info);
     }
 
     private static IConditionProvider provider(ManagedServiceInfo info) {
@@ -244,20 +386,161 @@
         }
     }
 
+    private void loadZenConfig() {
+        final ZenModeConfig config = mZenModeHelper.getConfig();
+        if (config == null) {
+            if (DEBUG) Slog.d(TAG, "loadZenConfig: no config");
+            return;
+        }
+        synchronized (mMutex) {
+            if (config.conditionComponents == null || config.conditionIds == null
+                    || config.conditionComponents.length != config.conditionIds.length) {
+                if (DEBUG) Slog.d(TAG, "loadZenConfig: no conditions");
+                setAutomaticZenModeConditions(null, false /*save*/);
+                return;
+            }
+            final ArraySet<Uri> newIds = new ArraySet<Uri>();
+            final int N = config.conditionComponents.length;
+            for (int i = 0; i < N; i++) {
+                final ComponentName component = config.conditionComponents[i];
+                final Uri id = config.conditionIds[i];
+                if (component != null && id != null) {
+                    getRecordLocked(id, component);  // ensure record exists
+                    newIds.add(id);
+                }
+            }
+            if (DEBUG) Slog.d(TAG, "loadZenConfig: N=" + N);
+            setAutomaticZenModeConditions(newIds.toArray(new Uri[newIds.size()]), false /*save*/);
+        }
+    }
+
+    private void saveZenConfigLocked() {
+        ZenModeConfig config = mZenModeHelper.getConfig();
+        if (config == null) return;
+        config = config.copy();
+        final ArrayList<ConditionRecord> automatic = new ArrayList<ConditionRecord>();
+        final int automaticN = mRecords.size();
+        for (int i = 0; i < automaticN; i++) {
+            final ConditionRecord r = mRecords.get(i);
+            if (r.isAutomatic) {
+                automatic.add(r);
+            }
+        }
+        if (automatic.isEmpty()) {
+            config.conditionComponents = null;
+            config.conditionIds = null;
+        } else {
+            final int N = automatic.size();
+            config.conditionComponents = new ComponentName[N];
+            config.conditionIds = new Uri[N];
+            for (int i = 0; i < N; i++) {
+                final ConditionRecord r = automatic.get(i);
+                config.conditionComponents[i] = r.component;
+                config.conditionIds[i] = r.id;
+            }
+        }
+        if (DEBUG) Slog.d(TAG, "Setting zen config to: " + config);
+        mZenModeHelper.setConfig(config);
+    }
+
+    private final class CountdownConditionHelper extends BroadcastReceiver {
+        private static final String ACTION = "CountdownConditionHelper";
+        private static final int REQUEST_CODE = 100;
+        private static final String EXTRA_TIME = "time";
+
+        private long mCurrent;
+
+        public CountdownConditionHelper() {
+            mContext.registerReceiver(this, new IntentFilter(ACTION));
+        }
+
+        public void setZenModeCondition(Uri conditionId) {
+            final long time = tryParseCondition(conditionId);
+            final AlarmManager alarms = (AlarmManager)
+                    mContext.getSystemService(Context.ALARM_SERVICE);
+            final Intent intent = new Intent(ACTION).putExtra(EXTRA_TIME, time)
+                    .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+            final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, REQUEST_CODE,
+                    intent, PendingIntent.FLAG_UPDATE_CURRENT);
+            alarms.cancel(pendingIntent);
+            mCurrent = time;
+            if (time > 0) {
+                final long now = System.currentTimeMillis();
+                final CharSequence span =
+                        DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS);
+                Slog.d(TAG, String.format("Scheduling %s for %s, %s in the future (%s), now=%s",
+                        ACTION, ts(time), time - now, span, ts(now)));
+                alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
+            }
+        }
+
+        private String ts(long time) {
+            return new Date(time) + " (" + time + ")";
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (ACTION.equals(intent.getAction())) {
+                final long time = intent.getLongExtra(EXTRA_TIME, 0);
+                Slog.d(TAG, "Countdown condition fired. time=" + time + " mCurrent=" + mCurrent);
+                if (time > 0 && time == mCurrent) {
+                    // countdown condition is still the manual condition, leave zen
+                    mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF);
+                    ConditionProviders.this.setZenModeCondition(null);
+                }
+            }
+        }
+
+        private long tryParseCondition(Uri conditionId) {
+            // condition://android/countdown/1399917958951
+            if (!Condition.isValidId(conditionId, "android")) return 0;
+            if (conditionId.getPathSegments().size() != 2
+                    || !"countdown".equals(conditionId.getPathSegments().get(0))) return 0;
+            try {
+                return Long.parseLong(conditionId.getPathSegments().get(1));
+            } catch (RuntimeException e) {
+                Slog.w(TAG, "Error parsing countdown condition: " + conditionId, e);
+                return 0;
+            }
+        }
+    }
+
     private class ZenModeHelperCallback extends ZenModeHelper.Callback {
         @Override
+        void onConfigChanged() {
+            loadZenConfig();
+        }
+
+        @Override
         void onZenModeChanged() {
             final int mode = mZenModeHelper.getZenMode();
             if (mode == Global.ZEN_MODE_OFF) {
-                synchronized (mMutex) {
-                    if (mCurrentConditionId != null) {
-                        if (DEBUG) Slog.d(TAG, "Zen mode off, forcing unsubscribe from "
-                                + mCurrentConditionId);
-                        unsubscribeLocked(mCurrentConditionId);
-                        mCurrentConditionId = null;
-                    }
-                }
+                // ensure any manual condition is cleared
+                setZenModeCondition(null);
             }
         }
     }
+
+    private static class ConditionRecord {
+        public final Uri id;
+        public final ComponentName component;
+        public Condition condition;
+        public ManagedServiceInfo info;
+        public boolean isAutomatic;
+        public boolean isManual;
+
+        private ConditionRecord(Uri id, ComponentName component) {
+            this.id = id;
+            this.component = component;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder("ConditionRecord[id=")
+                    .append(id).append(",component=").append(component);
+            if (isAutomatic) sb.append(",automatic");
+            if (isManual) sb.append(",manual");
+            return sb.append(']').toString();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 0621f58..584145f 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -66,7 +66,7 @@
 
     private static final String ENABLED_SERVICES_SEPARATOR = ":";
 
-    private final Context mContext;
+    protected final Context mContext;
     protected final Object mMutex;
     private final UserProfiles mUserProfiles;
     private final SettingsObserver mSettingsObserver;
@@ -101,7 +101,7 @@
 
     abstract protected IInterface asInterface(IBinder binder);
 
-    abstract protected void onServiceAdded(IInterface service);
+    abstract protected void onServiceAdded(ManagedServiceInfo info);
 
     protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
 
@@ -368,11 +368,12 @@
                             @Override
                             public void onServiceConnected(ComponentName name, IBinder binder) {
                                 boolean added = false;
+                                ManagedServiceInfo info = null;
                                 synchronized (mMutex) {
                                     mServicesBinding.remove(servicesBindingTag);
                                     try {
                                         mService = asInterface(binder);
-                                        ManagedServiceInfo info = newServiceInfo(mService, name,
+                                        info = newServiceInfo(mService, name,
                                                 userid, false /*isSystem*/, this, targetSdkVersion);
                                         binder.linkToDeath(info, 0);
                                         added = mServices.add(info);
@@ -381,7 +382,7 @@
                                     }
                                 }
                                 if (added) {
-                                    onServiceAdded(mService);
+                                    onServiceAdded(info);
                                 }
                             }
 
diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java
new file mode 100644
index 0000000..49293d3
--- /dev/null
+++ b/services/core/java/com/android/server/notification/NotificationComparator.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.notification;
+
+import java.util.Comparator;
+
+/**
+ * Sorts notificaitons into attention-relelvant order.
+ */
+public class NotificationComparator
+        implements Comparator<NotificationManagerService.NotificationRecord> {
+
+    @Override
+    public int compare(NotificationManagerService.NotificationRecord lhs,
+            NotificationManagerService.NotificationRecord rhs) {
+        if (lhs.isRecentlyIntrusive() != rhs.isRecentlyIntrusive()) {
+            return lhs.isRecentlyIntrusive() ? -1 : 1;
+        }
+        final int leftScore = lhs.sbn.getScore();
+        final int rightScore = rhs.sbn.getScore();
+        if (leftScore != rightScore) {
+            // by priority, high to low
+            return -1 * Integer.compare(leftScore, rightScore);
+        }
+        final float leftPeple = lhs.getContactAffinity();
+        final float rightPeople = rhs.getContactAffinity();
+        if (leftPeple != rightPeople) {
+            // by contact proximity, close to far
+            return -1 * Float.compare(leftPeple, rightPeople);
+        }
+        // then break ties by time, most recent first
+        return -1 * Long.compare(lhs.sbn.getPostTime(), rhs.sbn.getPostTime());
+    }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java
index ce4c1ed..b41b478 100644
--- a/services/core/java/com/android/server/notification/NotificationDelegate.java
+++ b/services/core/java/com/android/server/notification/NotificationDelegate.java
@@ -21,8 +21,7 @@
 public interface NotificationDelegate {
     void onSetDisabled(int status);
     void onClearAll(int callingUid, int callingPid, int userId);
-    void onNotificationClick(int callingUid, int callingPid,
-            String pkg, String tag, int id, int userId);
+    void onNotificationClick(int callingUid, int callingPid, String key);
     void onNotificationClear(int callingUid, int callingPid,
             String pkg, String tag, int id, int userId);
     void onNotificationError(int callingUid, int callingPid,
diff --git a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
new file mode 100644
index 0000000..125158fd
--- /dev/null
+++ b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
@@ -0,0 +1,64 @@
+/*
+* Copyright (C) 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.android.server.notification;
+
+import android.app.Notification;
+import android.content.Context;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.server.notification.NotificationManagerService.NotificationRecord;
+
+/**
+ * This {@link com.android.server.notification.NotificationSignalExtractor} noticies noisy
+ * notifications and marks them to get a temporary ranking bump.
+ */
+public class NotificationIntrusivenessExtractor implements NotificationSignalExtractor {
+    private static final String TAG = "NotificationNoiseExtractor";
+    private static final boolean DBG = false;
+
+    /** Length of time (in milliseconds) that an intrusive or noisy notification will stay at
+    the top of the ranking order, before it falls back to its natural position. */
+    private static final long HANG_TIME_MS = 10000;
+
+    public void initialize(Context ctx) {
+        if (DBG) Slog.d(TAG, "Initializing  " + getClass().getSimpleName() + ".");
+    }
+
+    public RankingFuture process(NotificationRecord record) {
+        if (record == null || record.getNotification() == null) {
+            if (DBG) Slog.d(TAG, "skipping empty notification");
+            return null;
+        }
+
+        final Notification notification = record.getNotification();
+        if ((notification.defaults & Notification.DEFAULT_VIBRATE) != 0 ||
+                notification.vibrate != null ||
+                (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
+                notification.sound != null ||
+                notification.fullScreenIntent != null) {
+            record.setRecentlyIntusive(true);
+        }
+
+        return new RankingFuture(record, HANG_TIME_MS) {
+            @Override
+            public void work() {
+                mRecord.setRecentlyIntusive(false);
+            }
+        };
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6e4eb56..2f1d291 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -49,8 +49,10 @@
 import android.os.Binder;
 import android.os.Environment;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.IInterface;
+import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
@@ -61,6 +63,7 @@
 import android.service.notification.IConditionListener;
 import android.service.notification.IConditionProvider;
 import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationOrderUpdate;
 import android.service.notification.StatusBarNotification;
 import android.service.notification.Condition;
 import android.service.notification.ZenModeConfig;
@@ -76,7 +79,6 @@
 import android.widget.Toast;
 
 import com.android.internal.R;
-import com.android.internal.notification.NotificationScorer;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.server.EventLogTags;
 import com.android.server.SystemService;
@@ -104,9 +106,12 @@
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
 
 /** {@hide} */
 public class NotificationManagerService extends SystemService {
@@ -118,6 +123,8 @@
     // message codes
     static final int MESSAGE_TIMEOUT = 2;
     static final int MESSAGE_SAVE_POLICY_FILE = 3;
+    static final int MESSAGE_RECONSIDER_RANKING = 4;
+    static final int MESSAGE_SEND_RANKING_UPDATE = 5;
 
     static final int LONG_DELAY = 3500; // 3.5 seconds
     static final int SHORT_DELAY = 2000; // 2 seconds
@@ -147,6 +154,9 @@
 
     final IBinder mForegroundToken = new Binder();
     private WorkerHandler mHandler;
+    private final HandlerThread mRankingThread = new HandlerThread("ranker",
+            Process.THREAD_PRIORITY_BACKGROUND);
+    private Handler mRankingHandler = null;
 
     private Light mNotificationLight;
     Light mAttentionLight;
@@ -171,6 +181,7 @@
     // used as a mutex for access to all active notifications & listeners
     final ArrayList<NotificationRecord> mNotificationList =
             new ArrayList<NotificationRecord>();
+    final NotificationComparator mRankingComparator = new NotificationComparator();
     final ArrayMap<String, NotificationRecord> mNotificationsByKey =
             new ArrayMap<String, NotificationRecord>();
     final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
@@ -193,13 +204,12 @@
     private static final String TAG_PACKAGE = "package";
     private static final String ATTR_NAME = "name";
 
-    final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>();
+    final ArrayList<NotificationSignalExtractor> mSignalExtractors = new ArrayList<NotificationSignalExtractor>();
 
     private final UserProfiles mUserProfiles = new UserProfiles();
     private NotificationListeners mListeners;
     private ConditionProviders mConditionProviders;
-
-    private final NotificationUsageStats mUsageStats = new NotificationUsageStats();
+    private NotificationUsageStats mUsageStats;
 
     private static final String EXTRA_INTERCEPT = "android.intercept";
 
@@ -445,9 +455,14 @@
     public static final class NotificationRecord
     {
         final StatusBarNotification sbn;
-        final SingleNotificationStats stats = new SingleNotificationStats();
+        SingleNotificationStats stats;
         IBinder statusBarKey;
 
+        // These members are used by NotificationSignalExtractors
+        // to communicate with the ranking module.
+        private float mContactAffinity;
+        private boolean mRecentlyIntrusive;
+
         NotificationRecord(StatusBarNotification sbn)
         {
             this.sbn = sbn;
@@ -472,6 +487,7 @@
             pw.println(prefix + String.format("  defaults=0x%08x flags=0x%08x",
                     notification.defaults, notification.flags));
             pw.println(prefix + "  sound=" + notification.sound);
+            pw.println(prefix + String.format("  color=0x%08x", notification.color));
             pw.println(prefix + "  vibrate=" + Arrays.toString(notification.vibrate));
             pw.println(prefix + String.format("  led=0x%08x onMs=%d offMs=%d",
                     notification.ledARGB, notification.ledOnMS, notification.ledOffMS));
@@ -528,6 +544,22 @@
                     this.sbn.getTag(), this.sbn.getScore(), this.sbn.getKey(),
                     this.sbn.getNotification());
         }
+
+        public void setContactAffinity(float contactAffinity) {
+            mContactAffinity = contactAffinity;
+        }
+
+        public float getContactAffinity() {
+            return mContactAffinity;
+        }
+
+        public boolean isRecentlyIntrusive() {
+            return mRecentlyIntrusive;
+        }
+
+        public void setRecentlyIntusive(boolean recentlyIntrusive) {
+            mRecentlyIntrusive = recentlyIntrusive;
+        }
     }
 
     private static final class ToastRecord
@@ -602,10 +634,20 @@
         }
 
         @Override
-        public void onNotificationClick(int callingUid, int callingPid,
-                String pkg, String tag, int id, int userId) {
-            cancelNotification(callingUid, callingPid, pkg, tag, id, Notification.FLAG_AUTO_CANCEL,
-                    Notification.FLAG_FOREGROUND_SERVICE, false, userId, REASON_DELEGATE_CLICK, null);
+        public void onNotificationClick(int callingUid, int callingPid, String key) {
+            synchronized (mNotificationList) {
+                EventLogTags.writeNotificationClicked(key);
+                NotificationRecord r = mNotificationsByKey.get(key);
+                if (r == null) {
+                    Log.w(TAG, "No notification with key: " + key);
+                    return;
+                }
+                StatusBarNotification sbn = r.sbn;
+                cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
+                        sbn.getId(), Notification.FLAG_AUTO_CANCEL,
+                        Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
+                        REASON_DELEGATE_CLICK, null);
+            }
         }
 
         @Override
@@ -697,7 +739,7 @@
             boolean queryRemove = false;
             boolean packageChanged = false;
             boolean cancelNotifications = true;
-            
+
             if (action.equals(Intent.ACTION_PACKAGE_ADDED)
                     || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
                     || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
@@ -839,6 +881,8 @@
         mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
 
         mHandler = new WorkerHandler();
+        mRankingThread.start();
+        mRankingHandler = new RankingWorkerHandler(mRankingThread.getLooper());
         mZenModeHelper = new ZenModeHelper(getContext(), mHandler);
         mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
             @Override
@@ -848,6 +892,7 @@
         });
         final File systemDir = new File(Environment.getDataDirectory(), "system");
         mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
+        mUsageStats = new NotificationUsageStats(getContext());
 
         importOldBlockDb();
 
@@ -914,21 +959,22 @@
 
         mSettingsObserver = new SettingsObserver(mHandler);
 
-        // spin up NotificationScorers
-        String[] notificationScorerNames = resources.getStringArray(
-                R.array.config_notificationScorers);
-        for (String scorerName : notificationScorerNames) {
+        // spin up NotificationSignalExtractors
+        String[] extractorNames = resources.getStringArray(
+                R.array.config_notificationSignalExtractors);
+        for (String extractorName : extractorNames) {
             try {
-                Class<?> scorerClass = getContext().getClassLoader().loadClass(scorerName);
-                NotificationScorer scorer = (NotificationScorer) scorerClass.newInstance();
-                scorer.initialize(getContext());
-                mScorers.add(scorer);
+                Class<?> extractorClass = getContext().getClassLoader().loadClass(extractorName);
+                NotificationSignalExtractor extractor =
+                        (NotificationSignalExtractor) extractorClass.newInstance();
+                extractor.initialize(getContext());
+                mSignalExtractors.add(extractor);
             } catch (ClassNotFoundException e) {
-                Slog.w(TAG, "Couldn't find scorer " + scorerName + ".", e);
+                Slog.w(TAG, "Couldn't find extractor " + extractorName + ".", e);
             } catch (InstantiationException e) {
-                Slog.w(TAG, "Couldn't instantiate scorer " + scorerName + ".", e);
+                Slog.w(TAG, "Couldn't instantiate extractor " + extractorName + ".", e);
             } catch (IllegalAccessException e) {
-                Slog.w(TAG, "Problem accessing scorer " + scorerName + ".", e);
+                Slog.w(TAG, "Problem accessing extractor " + extractorName + ".", e);
             }
         }
 
@@ -1139,6 +1185,7 @@
          * System-only API for getting a list of current (i.e. not cleared) notifications.
          *
          * Requires ACCESS_NOTIFICATIONS which is signature|system.
+         * @returns A list of all the notifications, in natural order.
          */
         @Override
         public StatusBarNotification[] getActiveNotifications(String callingPkg) {
@@ -1295,6 +1342,9 @@
          * should be used.
          *
          * @param token The binder for the listener, to check that the caller is allowed
+         * @param keys the notification keys to fetch, or null for all active notifications.
+         * @returns The return value will contain the notifications specified in keys, in that
+         *      order, or if keys is null, all the notifications, in natural order.
          */
         @Override
         public StatusBarNotification[] getActiveNotificationsFromListener(
@@ -1326,7 +1376,7 @@
 
         @Override
         public String[] getActiveNotificationKeysFromListener(INotificationListener token) {
-            return NotificationManagerService.this.getActiveNotificationKeysFromListener(token);
+            return NotificationManagerService.this.getActiveNotificationKeys(token);
         }
 
         @Override
@@ -1355,15 +1405,32 @@
         }
 
         @Override
-        public void requestZenModeConditions(IConditionListener callback, boolean requested) {
+        public void requestZenModeConditions(IConditionListener callback, int relevance) {
             enforceSystemOrSystemUI("INotificationManager.requestZenModeConditions");
-            mConditionProviders.requestZenModeConditions(callback, requested);
+            mConditionProviders.requestZenModeConditions(callback, relevance);
         }
 
         @Override
         public void setZenModeCondition(Uri conditionId) {
             enforceSystemOrSystemUI("INotificationManager.setZenModeCondition");
-            mConditionProviders.setZenModeCondition(conditionId);
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                mConditionProviders.setZenModeCondition(conditionId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void setAutomaticZenModeConditions(Uri[] conditionIds) {
+            enforceSystemOrSystemUI("INotificationManager.setAutomaticZenModeConditions");
+            mConditionProviders.setAutomaticZenModeConditions(conditionIds);
+        }
+
+        @Override
+        public Condition[] getAutomaticZenModeConditions() {
+            enforceSystemOrSystemUI("INotificationManager.getAutomaticZenModeConditions");
+            return mConditionProviders.getAutomaticZenModeConditions();
         }
 
         private void enforceSystemOrSystemUI(String message) {
@@ -1386,19 +1453,21 @@
         }
     };
 
-    private String[] getActiveNotificationKeysFromListener(INotificationListener token) {
-        synchronized (mNotificationList) {
-            final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
-            final ArrayList<String> keys = new ArrayList<String>();
-            final int N = mNotificationList.size();
-            for (int i=0; i<N; i++) {
-                final StatusBarNotification sbn = mNotificationList.get(i).sbn;
-                if (info.enabledAndUserMatches(sbn.getUserId())) {
-                    keys.add(sbn.getKey());
+    private String[] getActiveNotificationKeys(INotificationListener token) {
+        final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
+        final ArrayList<String> keys = new ArrayList<String>();
+        if (info.isEnabledForCurrentProfiles()) {
+            synchronized (mNotificationList) {
+                final int N = mNotificationList.size();
+                for (int i = 0; i < N; i++) {
+                    final StatusBarNotification sbn = mNotificationList.get(i).sbn;
+                    if (info.enabledAndUserMatches(sbn.getUserId())) {
+                        keys.add(sbn.getKey());
+                    }
                 }
             }
-            return keys.toArray(new String[keys.size()]);
         }
+        return keys.toArray(new String[keys.size()]);
     }
 
     void dumpImpl(PrintWriter pw) {
@@ -1555,26 +1624,23 @@
                 // 1. initial score: buckets of 10, around the app
                 int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER; //[-20..20]
 
-                // 2. Consult external heuristics (TBD)
-
-                // 3. Apply local rules
-
-                int initialScore = score;
-                if (!mScorers.isEmpty()) {
-                    if (DBG) Slog.v(TAG, "Initial score is " + score + ".");
-                    for (NotificationScorer scorer : mScorers) {
+                // 2. extract ranking signals from the notification data
+                final StatusBarNotification n = new StatusBarNotification(
+                        pkg, opPkg, id, tag, callingUid, callingPid, score, notification,
+                        user);
+                NotificationRecord r = new NotificationRecord(n);
+                if (!mSignalExtractors.isEmpty()) {
+                    for (NotificationSignalExtractor extractor : mSignalExtractors) {
                         try {
-                            score = scorer.getScore(notification, score);
+                            RankingFuture future = extractor.process(r);
+                            scheduleRankingReconsideration(future);
                         } catch (Throwable t) {
-                            Slog.w(TAG, "Scorer threw on .getScore.", t);
+                            Slog.w(TAG, "NotificationSignalExtractor failed.", t);
                         }
                     }
-                    if (DBG) Slog.v(TAG, "Final score is " + score + ".");
                 }
 
-                // add extra to indicate score modified by NotificationScorer
-                notification.extras.putBoolean(Notification.EXTRA_SCORE_MODIFIED,
-                        score != initialScore);
+                // 3. Apply local rules
 
                 // blocked apps
                 if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) {
@@ -1585,10 +1651,6 @@
                     }
                 }
 
-                if (DBG) {
-                    Slog.v(TAG, "Assigned score=" + score + " to " + notification);
-                }
-
                 if (score < SCORE_DISPLAY_THRESHOLD) {
                     // Notification will be blocked because the score is too low.
                     return;
@@ -1600,14 +1662,10 @@
 
                 // Should this notification make noise, vibe, or use the LED?
                 final boolean canInterrupt = (score >= SCORE_INTERRUPTION_THRESHOLD) && !intercept;
-                if (DBG) Slog.v(TAG, "canInterrupt=" + canInterrupt + " intercept=" + intercept);
+                if (DBG || intercept) Slog.v(TAG,
+                        "pkg=" + pkg + " canInterrupt=" + canInterrupt + " intercept=" + intercept);
                 synchronized (mNotificationList) {
-                    final StatusBarNotification n = new StatusBarNotification(
-                            pkg, opPkg, id, tag, callingUid, callingPid, score, notification,
-                            user);
-                    NotificationRecord r = new NotificationRecord(n);
                     NotificationRecord old = null;
-
                     int index = indexOfNotificationLocked(pkg, tag, id, userId);
                     if (index < 0) {
                         mNotificationList.add(r);
@@ -1615,7 +1673,7 @@
                     } else {
                         old = mNotificationList.get(index);
                         mNotificationList.set(index, r);
-                        mUsageStats.registerUpdatedByApp(r);
+                        mUsageStats.registerUpdatedByApp(r, old);
                         // Make sure we don't lose the foreground service state.
                         if (old != null) {
                             notification.flags |=
@@ -1627,6 +1685,8 @@
                     }
                     mNotificationsByKey.put(n.getKey(), r);
 
+                    Collections.sort(mNotificationList, mRankingComparator);
+
                     // Ensure if this is a foreground service that the proper additional
                     // flags are set.
                     if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) {
@@ -1924,6 +1984,57 @@
         }
     }
 
+    private void scheduleRankingReconsideration(RankingFuture future) {
+        if (future != null) {
+            Message m = Message.obtain(mRankingHandler, MESSAGE_RECONSIDER_RANKING, future);
+            long delay = future.getDelay(TimeUnit.MILLISECONDS);
+            mRankingHandler.sendMessageDelayed(m, delay);
+        }
+    }
+
+    private void handleRankingReconsideration(Message message) {
+        if (!(message.obj instanceof RankingFuture)) return;
+
+        RankingFuture future = (RankingFuture) message.obj;
+        future.run();
+        try {
+            NotificationRecord record = future.get();
+            synchronized (mNotificationList) {
+                int before = mNotificationList.indexOf(record);
+                if (before != -1) {
+                    Collections.sort(mNotificationList, mRankingComparator);
+                    int after = mNotificationList.indexOf(record);
+
+                    if (before != after) {
+                        scheduleSendRankingUpdate();
+                    }
+                }
+            }
+        } catch (InterruptedException e) {
+            // we're running the future explicitly, so this should never happen
+        } catch (ExecutionException e) {
+            // we're running the future explicitly, so this should never happen
+        }
+    }
+
+    private void scheduleSendRankingUpdate() {
+        mHandler.removeMessages(MESSAGE_SEND_RANKING_UPDATE);
+        Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
+        mHandler.sendMessage(m);
+    }
+
+    private void handleSendRankingUpdate() {
+        synchronized (mNotificationList) {
+            final int N = mNotificationList.size();
+            ArrayList<StatusBarNotification> sbns =
+                    new ArrayList<StatusBarNotification>(N);
+            for (int i = 0; i < N; i++ ) {
+                sbns.add(mNotificationList.get(i).sbn);
+            }
+            mListeners.notifyOrderUpdateLocked(sbns);
+        }
+    }
+
     private final class WorkerHandler extends Handler
     {
         @Override
@@ -1937,11 +2048,30 @@
                 case MESSAGE_SAVE_POLICY_FILE:
                     handleSavePolicyFile();
                     break;
+                case MESSAGE_SEND_RANKING_UPDATE:
+                    handleSendRankingUpdate();
+                    break;
+            }
+        }
+
+    }
+
+    private final class RankingWorkerHandler extends Handler
+    {
+        public RankingWorkerHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MESSAGE_RECONSIDER_RANKING:
+                    handleRankingReconsideration(msg);
+                    break;
             }
         }
     }
 
-
     // Notifications
     // ============================================================================
     static int clamp(int x, int low, int high) {
@@ -2320,11 +2450,11 @@
         }
 
         @Override
-        public void onServiceAdded(IInterface service) {
-            final INotificationListener listener = (INotificationListener) service;
-            final String[] keys = getActiveNotificationKeysFromListener(listener);
+        public void onServiceAdded(ManagedServiceInfo info) {
+            final INotificationListener listener = (INotificationListener) info.service;
+            final String[] keys = getActiveNotificationKeys(listener);
             try {
-                listener.onListenerConnected(keys);
+                listener.onListenerConnected(new NotificationOrderUpdate(keys));
             } catch (RemoteException e) {
                 // we tried
             }
@@ -2337,12 +2467,18 @@
             // make a copy in case changes are made to the underlying Notification object
             final StatusBarNotification sbnClone = sbn.clone();
             for (final ManagedServiceInfo info : mServices) {
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        notifyPostedIfUserMatch(info, sbnClone);
+                if (info.isEnabledForCurrentProfiles()) {
+                    final INotificationListener listener = (INotificationListener) info.service;
+                    final String[] keys = getActiveNotificationKeys(listener);
+                    if (keys.length > 0) {
+                        mHandler.post(new Runnable() {
+                            @Override
+                            public void run() {
+                                notifyPostedIfUserMatch(info, sbnClone, keys);
+                            }
+                        });
                     }
-                });
+                }
             }
         }
 
@@ -2354,39 +2490,83 @@
             // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
             // notification
             final StatusBarNotification sbnLight = sbn.cloneLight();
-            for (ManagedServiceInfo serviceInfo : mServices) {
-                final ManagedServiceInfo info = (ManagedServiceInfo) serviceInfo;
+            for (final ManagedServiceInfo info : mServices) {
+                if (info.isEnabledForCurrentProfiles()) {
+                    final INotificationListener listener = (INotificationListener) info.service;
+                    final String[] keys = getActiveNotificationKeys(listener);
+                    mHandler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            notifyRemovedIfUserMatch(info, sbnLight, keys);
+                        }
+                    });
+                }
+            }
+        }
+
+        /**
+         * asynchronously notify all listeners about a reordering of notifications
+         * @param sbns an array of {@link StatusBarNotification}s to consider.  This code
+         *             must not rely on mutable members of these objects, such as the
+         *             {@link Notification}.
+         */
+        public void notifyOrderUpdateLocked(final ArrayList<StatusBarNotification> sbns) {
+            for (final ManagedServiceInfo serviceInfo : mServices) {
                 mHandler.post(new Runnable() {
                     @Override
                     public void run() {
-                        notifyRemovedIfUserMatch(info, sbnLight);
+                        notifyOrderUpdateIfUserMatch(serviceInfo, sbns);
                     }
                 });
             }
         }
 
-        private void notifyPostedIfUserMatch(ManagedServiceInfo info, StatusBarNotification sbn) {
+        private void notifyPostedIfUserMatch(final ManagedServiceInfo info,
+                final StatusBarNotification sbn, String[] keys) {
             if (!info.enabledAndUserMatches(sbn.getUserId())) {
                 return;
             }
             final INotificationListener listener = (INotificationListener)info.service;
             try {
-                listener.onNotificationPosted(sbn);
+                listener.onNotificationPosted(sbn, new NotificationOrderUpdate(keys));
             } catch (RemoteException ex) {
                 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
             }
         }
 
-        private void notifyRemovedIfUserMatch(ManagedServiceInfo info, StatusBarNotification sbn) {
+        private void notifyRemovedIfUserMatch(ManagedServiceInfo info, StatusBarNotification sbn,
+                String[] keys) {
             if (!info.enabledAndUserMatches(sbn.getUserId())) {
                 return;
             }
             final INotificationListener listener = (INotificationListener)info.service;
             try {
-                listener.onNotificationRemoved(sbn);
+                listener.onNotificationRemoved(sbn, new NotificationOrderUpdate(keys));
             } catch (RemoteException ex) {
                 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
             }
         }
+
+        /**
+         * @param sbns an array of {@link StatusBarNotification}s to consider.  This code
+         *             must not rely on mutable members of these objects, such as the
+         *             {@link Notification}.
+         */
+        public void notifyOrderUpdateIfUserMatch(ManagedServiceInfo info,
+                ArrayList<StatusBarNotification> sbns) {
+            ArrayList<String> keys = new ArrayList<String>(sbns.size());
+            for (StatusBarNotification sbn: sbns) {
+                if (info.enabledAndUserMatches(sbn.getUserId())) {
+                    keys.add(sbn.getKey());
+                }
+            }
+            final INotificationListener listener = (INotificationListener)info.service;
+            try {
+                listener.onNotificationOrderUpdate(
+                        new NotificationOrderUpdate(keys.toArray(new String[keys.size()])));
+            } catch (RemoteException ex) {
+                Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/notification/NotificationSignalExtractor.java b/services/core/java/com/android/server/notification/NotificationSignalExtractor.java
new file mode 100644
index 0000000..a41fdfe
--- /dev/null
+++ b/services/core/java/com/android/server/notification/NotificationSignalExtractor.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.server.notification;
+
+import android.content.Context;
+
+/**
+ * Extracts signals that will be useful to the {@link NotificationComparator} and caches them
+ *  on the {@link NotificationManagerService.NotificationRecord} object. These annotations will
+ *  not be passed on to {@link android.service.notification.NotificationListenerService}s.
+ */
+public interface NotificationSignalExtractor {
+
+    /** One-time initialization. */
+    public void initialize(Context context);
+
+    /**
+     * Called once per notification that is posted or updated.
+     *
+     * @return null if the work is done, or a future if there is more to do. The
+     * {@link RankingFuture} will be run on a worker thread, and if notifications are re-ordered
+     * by that execution, the {@link NotificationManagerService} may send order update
+     * events to the {@link android.service.notification.NotificationListenerService}s.
+     */
+    public RankingFuture process(NotificationManagerService.NotificationRecord notification);
+
+}
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index d9e2b91..a60e95b 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -18,8 +18,17 @@
 
 import com.android.server.notification.NotificationManagerService.NotificationRecord;
 
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
 import android.os.SystemClock;
 import android.service.notification.StatusBarNotification;
+import android.util.Log;
 
 import java.io.PrintWriter;
 import java.util.HashMap;
@@ -37,24 +46,31 @@
  * {@hide}
  */
 public class NotificationUsageStats {
-
     // Guarded by synchronized(this).
     private final Map<String, AggregatedStats> mStats = new HashMap<String, AggregatedStats>();
+    private final SQLiteLog mSQLiteLog;
+
+    public NotificationUsageStats(Context context) {
+        mSQLiteLog = new SQLiteLog(context);
+    }
 
     /**
      * Called when a notification has been posted.
      */
     public synchronized void registerPostedByApp(NotificationRecord notification) {
+        notification.stats = new SingleNotificationStats();
         notification.stats.posttimeElapsedMs = SystemClock.elapsedRealtime();
         for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
             stats.numPostedByApp++;
         }
+        mSQLiteLog.logPosted(notification);
     }
 
     /**
      * Called when a notification has been updated.
      */
-    public void registerUpdatedByApp(NotificationRecord notification) {
+    public void registerUpdatedByApp(NotificationRecord notification, NotificationRecord old) {
+        notification.stats = old.stats;
         for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
             stats.numUpdatedByApp++;
         }
@@ -68,6 +84,7 @@
             stats.numRemovedByApp++;
             stats.collect(notification.stats);
         }
+        mSQLiteLog.logRemoved(notification);
     }
 
     /**
@@ -79,6 +96,7 @@
             stats.numDismissedByUser++;
             stats.collect(notification.stats);
         }
+        mSQLiteLog.logDismissed(notification);
     }
 
     /**
@@ -89,6 +107,7 @@
         for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
             stats.numClickedByUser++;
         }
+        mSQLiteLog.logClicked(notification);
     }
 
     /**
@@ -146,6 +165,7 @@
         for (AggregatedStats as : mStats.values()) {
             as.dump(pw, indent);
         }
+        mSQLiteLog.dump(pw, indent);
     }
 
     /**
@@ -274,4 +294,211 @@
                     '}';
         }
     }
+
+    private static class SQLiteLog {
+        private static final String TAG = "NotificationSQLiteLog";
+
+        // Message types passed to the background handler.
+        private static final int MSG_POST = 1;
+        private static final int MSG_CLICK = 2;
+        private static final int MSG_REMOVE = 3;
+        private static final int MSG_DISMISS = 4;
+
+        private static final String DB_NAME = "notification_log.db";
+        private static final int DB_VERSION = 1;
+
+        /** Age in ms after which events are pruned from the DB. */
+        private static final long HORIZON_MS = 7 * 24 * 60 * 60 * 1000L;  // 1 week
+        /** Delay between pruning the DB. Used to throttle pruning. */
+        private static final long PRUNE_MIN_DELAY_MS = 6 * 60 * 60 * 1000L;  // 6 hours
+        /** Mininum number of writes between pruning the DB. Used to throttle pruning. */
+        private static final long PRUNE_MIN_WRITES = 1024;
+
+        // Table 'log'
+        private static final String TAB_LOG = "log";
+        private static final String COL_EVENT_USER_ID = "event_user_id";
+        private static final String COL_EVENT_TYPE = "event_type";
+        private static final String COL_EVENT_TIME = "event_time_ms";
+        private static final String COL_KEY = "key";
+        private static final String COL_PKG = "pkg";
+        private static final String COL_NOTIFICATION_ID = "nid";
+        private static final String COL_TAG = "tag";
+        private static final String COL_WHEN_MS = "when_ms";
+        private static final String COL_DEFAULTS = "defaults";
+        private static final String COL_FLAGS = "flags";
+        private static final String COL_PRIORITY = "priority";
+        private static final String COL_CATEGORY = "category";
+        private static final String COL_ACTION_COUNT = "action_count";
+
+        private static final int EVENT_TYPE_POST = 1;
+        private static final int EVENT_TYPE_CLICK = 2;
+        private static final int EVENT_TYPE_REMOVE = 3;
+        private static final int EVENT_TYPE_DISMISS = 4;
+
+        private static long sLastPruneMs;
+        private static long sNumWrites;
+
+        private final SQLiteOpenHelper mHelper;
+        private final Handler mWriteHandler;
+
+        private static final long DAY_MS = 24 * 60 * 60 * 1000;
+
+        public SQLiteLog(Context context) {
+            HandlerThread backgroundThread = new HandlerThread("notification-sqlite-log",
+                    android.os.Process.THREAD_PRIORITY_BACKGROUND);
+            backgroundThread.start();
+            mWriteHandler = new Handler(backgroundThread.getLooper()) {
+                @Override
+                public void handleMessage(Message msg) {
+                    NotificationRecord r = (NotificationRecord) msg.obj;
+                    long nowMs = System.currentTimeMillis();
+                    switch (msg.what) {
+                        case MSG_POST:
+                            writeEvent(r.sbn.getPostTime(), EVENT_TYPE_POST, r, true);
+                            break;
+                        case MSG_CLICK:
+                            writeEvent(nowMs, EVENT_TYPE_CLICK, r, false);
+                            break;
+                        case MSG_REMOVE:
+                            writeEvent(nowMs, EVENT_TYPE_REMOVE, r, false);
+                            break;
+                        case MSG_DISMISS:
+                            writeEvent(nowMs, EVENT_TYPE_DISMISS, r, false);
+                            break;
+                        default:
+                            Log.wtf(TAG, "Unknown message type: " + msg.what);
+                            break;
+                    }
+                }
+            };
+            mHelper = new SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {
+                @Override
+                public void onCreate(SQLiteDatabase db) {
+                    db.execSQL("CREATE TABLE " + TAB_LOG + " (" +
+                            "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
+                            COL_EVENT_USER_ID + " INT," +
+                            COL_EVENT_TYPE + " INT," +
+                            COL_EVENT_TIME + " INT," +
+                            COL_KEY + " TEXT," +
+                            COL_PKG + " TEXT," +
+                            COL_NOTIFICATION_ID + " INT," +
+                            COL_TAG + " TEXT," +
+                            COL_WHEN_MS + " INT," +
+                            COL_DEFAULTS + " INT," +
+                            COL_FLAGS + " INT," +
+                            COL_PRIORITY + " INT," +
+                            COL_CATEGORY + " TEXT," +
+                            COL_ACTION_COUNT + " INT" +
+                            ")");
+                }
+
+                @Override
+                public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+                    db.execSQL("DROP TABLE IF EXISTS " + TAB_LOG);
+                    onCreate(db);
+                }
+            };
+        }
+
+        public void logPosted(NotificationRecord notification) {
+            mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_POST, notification));
+        }
+
+        public void logClicked(NotificationRecord notification) {
+            mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_CLICK, notification));
+        }
+
+        public void logRemoved(NotificationRecord notification) {
+            mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_REMOVE, notification));
+        }
+
+        public void logDismissed(NotificationRecord notification) {
+            mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_DISMISS, notification));
+        }
+
+        public void printPostFrequencies(PrintWriter pw, String indent) {
+            SQLiteDatabase db = mHelper.getReadableDatabase();
+            long nowMs = System.currentTimeMillis();
+            String q = "SELECT " +
+                    COL_EVENT_USER_ID + ", " +
+                    COL_PKG + ", " +
+                    // Bucket by day by looking at 'floor((nowMs - eventTimeMs) / dayMs)'
+                    "CAST(((" + nowMs + " - " + COL_EVENT_TIME + ") / " + DAY_MS + ") AS int) " +
+                        "AS day, " +
+                    "COUNT(*) AS cnt " +
+                    "FROM " + TAB_LOG + " " +
+                    "WHERE " +
+                    COL_EVENT_TYPE + "=" + EVENT_TYPE_POST + " " +
+                    "GROUP BY " + COL_EVENT_USER_ID + ", day, " + COL_PKG;
+            Cursor cursor = db.rawQuery(q, null);
+            try {
+                for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
+                    int userId = cursor.getInt(0);
+                    String pkg = cursor.getString(1);
+                    int day = cursor.getInt(2);
+                    int count = cursor.getInt(3);
+                    pw.println(indent + "post_frequency{user_id=" + userId + ",pkg=" + pkg +
+                            ",day=" + day + ",count=" + count + "}");
+                }
+            } finally {
+                cursor.close();
+            }
+        }
+
+        private void writeEvent(long eventTimeMs, int eventType, NotificationRecord r,
+                boolean populateNotificationDetails) {
+            ContentValues cv = new ContentValues();
+            cv.put(COL_EVENT_USER_ID, r.sbn.getUser().getIdentifier());
+            cv.put(COL_EVENT_TIME, eventTimeMs);
+            cv.put(COL_EVENT_TYPE, eventType);
+            putNotificationIdentifiers(r, cv);
+            if (populateNotificationDetails) {
+                putNotificationDetails(r, cv);
+            }
+            SQLiteDatabase db = mHelper.getWritableDatabase();
+            if (db.insert(TAB_LOG, null, cv) < 0) {
+                Log.wtf(TAG, "Error while trying to insert values: " + cv);
+            }
+            sNumWrites++;
+            pruneIfNecessary(db);
+        }
+
+        private void pruneIfNecessary(SQLiteDatabase db) {
+            // Prune if we haven't in a while.
+            long nowMs = System.currentTimeMillis();
+            if (sNumWrites > PRUNE_MIN_WRITES ||
+                    nowMs - sLastPruneMs > PRUNE_MIN_DELAY_MS) {
+                sNumWrites = 0;
+                sLastPruneMs = nowMs;
+                long horizonStartMs = nowMs - HORIZON_MS;
+                int deletedRows = db.delete(TAB_LOG, COL_EVENT_TIME + " < ?",
+                        new String[] { String.valueOf(horizonStartMs) });
+                Log.d(TAG, "Pruned event entries: " + deletedRows);
+            }
+        }
+
+        private static void putNotificationIdentifiers(NotificationRecord r, ContentValues outCv) {
+            outCv.put(COL_KEY, r.sbn.getKey());
+            outCv.put(COL_PKG, r.sbn.getPackageName());
+        }
+
+        private static void putNotificationDetails(NotificationRecord r, ContentValues outCv) {
+            outCv.put(COL_NOTIFICATION_ID, r.sbn.getId());
+            if (r.sbn.getTag() != null) {
+                outCv.put(COL_TAG, r.sbn.getTag());
+            }
+            outCv.put(COL_WHEN_MS, r.sbn.getPostTime());
+            outCv.put(COL_FLAGS, r.getNotification().flags);
+            outCv.put(COL_PRIORITY, r.getNotification().priority);
+            if (r.getNotification().category != null) {
+                outCv.put(COL_CATEGORY, r.getNotification().category);
+            }
+            outCv.put(COL_ACTION_COUNT, r.getNotification().actions != null ?
+                    r.getNotification().actions.length : 0);
+        }
+
+        public void dump(PrintWriter pw, String indent) {
+            printPostFrequencies(pw, indent);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/notification/RankingFuture.java b/services/core/java/com/android/server/notification/RankingFuture.java
new file mode 100644
index 0000000..d711d02
--- /dev/null
+++ b/services/core/java/com/android/server/notification/RankingFuture.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.notification;
+
+import java.util.concurrent.Delayed;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public abstract class RankingFuture
+        implements ScheduledFuture<NotificationManagerService.NotificationRecord> {
+    private static final long IMMEDIATE = 0l;
+
+    private static final int START = 0;
+    private static final int RUNNING = 1;
+    private static final int DONE = 2;
+    private static final int CANCELLED = 3;
+
+    private int mState;
+    private long mDelay;
+    protected NotificationManagerService.NotificationRecord mRecord;
+
+    public RankingFuture(NotificationManagerService.NotificationRecord record) {
+        this(record, IMMEDIATE);
+    }
+
+    public RankingFuture(NotificationManagerService.NotificationRecord record, long delay) {
+        mDelay = delay;
+        mRecord = record;
+        mState = START;
+    }
+
+    public void run() {
+        if (mState == START) {
+            mState = RUNNING;
+
+            work();
+
+            mState = DONE;
+            synchronized (this) {
+                notifyAll();
+            }
+        }
+    }
+
+    @Override
+    public long getDelay(TimeUnit unit) {
+        return unit.convert(mDelay, TimeUnit.MILLISECONDS);
+    }
+
+    @Override
+    public int compareTo(Delayed another) {
+        return Long.compare(getDelay(TimeUnit.MILLISECONDS),
+                another.getDelay(TimeUnit.MILLISECONDS));
+    }
+
+    @Override
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        if (mState == START) {  // can't cancel if running or done
+            mState = CANCELLED;
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean isCancelled() {
+        return mState == CANCELLED;
+    }
+
+    @Override
+    public boolean isDone() {
+        return mState == DONE;
+    }
+
+    @Override
+    public NotificationManagerService.NotificationRecord get()
+            throws InterruptedException, ExecutionException {
+        while (!isDone()) {
+            synchronized (this) {
+                this.wait();
+            }
+        }
+        return mRecord;
+    }
+
+    @Override
+    public NotificationManagerService.NotificationRecord get(long timeout, TimeUnit unit)
+            throws InterruptedException, ExecutionException, TimeoutException {
+        long timeoutMillis = unit.convert(timeout, TimeUnit.MILLISECONDS);
+        long start = System.currentTimeMillis();
+        long now = System.currentTimeMillis();
+        while (!isDone() && (now - start) < timeoutMillis) {
+            try {
+                wait(timeoutMillis - (now - start));
+            } catch (InterruptedException e) {
+                now = System.currentTimeMillis();
+            }
+        }
+        return mRecord;
+    }
+
+    public abstract void work();
+}
diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
new file mode 100644
index 0000000..8cd2f9b2
--- /dev/null
+++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
@@ -0,0 +1,298 @@
+/*
+* Copyright (C) 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES 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.notification;
+
+import android.app.Notification;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.LruCache;
+import android.util.Slog;
+
+import com.android.server.notification.NotificationManagerService.NotificationRecord;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+
+/**
+ * This {@link NotificationSignalExtractor} attempts to validate
+ * people references. Also elevates the priority of real people.
+ */
+public class ValidateNotificationPeople implements NotificationSignalExtractor {
+    private static final String TAG = "ValidateNotificationPeople";
+    private static final boolean INFO = true;
+    private static final boolean DEBUG = false;
+
+    private static final boolean ENABLE_PEOPLE_VALIDATOR = true;
+    private static final String SETTING_ENABLE_PEOPLE_VALIDATOR =
+            "validate_notification_people_enabled";
+    private static final String[] LOOKUP_PROJECTION = { Contacts._ID };
+    private static final int MAX_PEOPLE = 10;
+    private static final int PEOPLE_CACHE_SIZE = 200;
+
+    private static final float NONE = 0f;
+    private static final float VALID_CONTACT = 0.5f;
+    // TODO private static final float STARRED_CONTACT = 1f;
+
+    protected boolean mEnabled;
+    private Context mContext;
+
+    // maps raw person handle to resolved person object
+    private LruCache<String, LookupResult> mPeopleCache;
+
+    private RankingFuture validatePeople(NotificationRecord record) {
+        float affinity = NONE;
+        Bundle extras = record.getNotification().extras;
+        if (extras == null) {
+            return null;
+        }
+
+        final String[] people = getExtraPeople(extras);
+        if (people == null || people.length == 0) {
+            return null;
+        }
+
+        if (INFO) Slog.i(TAG, "Validating: " + record.sbn.getKey());
+        final LinkedList<String> pendingLookups = new LinkedList<String>();
+        for (int personIdx = 0; personIdx < people.length && personIdx < MAX_PEOPLE; personIdx++) {
+            final String handle = people[personIdx];
+            if (TextUtils.isEmpty(handle)) continue;
+
+            synchronized (mPeopleCache) {
+                LookupResult lookupResult = mPeopleCache.get(handle);
+                if (lookupResult == null || lookupResult.isExpired()) {
+                    pendingLookups.add(handle);
+                } else {
+                    if (DEBUG) Slog.d(TAG, "using cached lookupResult: " + lookupResult.mId);
+                }
+                if (lookupResult != null) {
+                    affinity = Math.max(affinity, lookupResult.getAffinity());
+                }
+            }
+        }
+
+        // record the best available data, so far:
+        record.setContactAffinity(affinity);
+
+        if (pendingLookups.isEmpty()) {
+            if (INFO) Slog.i(TAG, "final affinity: " + affinity);
+            return null;
+        }
+
+        if (DEBUG) Slog.d(TAG, "Pending: future work scheduled for: " + record.sbn.getKey());
+        return new RankingFuture(record) {
+            @Override
+            public void work() {
+                if (INFO) Slog.i(TAG, "Executing: validation for: " + mRecord.sbn.getKey());
+                float affinity = NONE;
+                LookupResult lookupResult = null;
+                for (final String handle: pendingLookups) {
+                    final Uri uri = Uri.parse(handle);
+                    if ("tel".equals(uri.getScheme())) {
+                        if (DEBUG) Slog.d(TAG, "checking telephone URI: " + handle);
+                        lookupResult = resolvePhoneContact(handle, uri.getSchemeSpecificPart());
+                    } else if (handle.startsWith(Contacts.CONTENT_LOOKUP_URI.toString())) {
+                        if (DEBUG) Slog.d(TAG, "checking lookup URI: " + handle);
+                        lookupResult = resolveContactsUri(handle, uri);
+                    } else {
+                        Slog.w(TAG, "unsupported URI " + handle);
+                    }
+                }
+                if (lookupResult != null) {
+                    affinity = Math.max(affinity, lookupResult.getAffinity());
+                }
+
+                float affinityBound = mRecord.getContactAffinity();
+                affinity = Math.max(affinity, affinityBound);
+                mRecord.setContactAffinity(affinity);
+                if (INFO) Slog.i(TAG, "final affinity: " + affinity);
+            }
+        };
+    }
+
+    private String[] getExtraPeople(Bundle extras) {
+        String[] people = extras.getStringArray(Notification.EXTRA_PEOPLE);
+        if (people != null) {
+            return people;
+        }
+
+        ArrayList<String> stringArray = extras.getStringArrayList(Notification.EXTRA_PEOPLE);
+        if (stringArray != null) {
+            return (String[]) stringArray.toArray();
+        }
+
+        String string = extras.getString(Notification.EXTRA_PEOPLE);
+        if (string != null) {
+            people = new String[1];
+            people[0] = string;
+            return people;
+        }
+        char[] charArray = extras.getCharArray(Notification.EXTRA_PEOPLE);
+        if (charArray != null) {
+            people = new String[1];
+            people[0] = new String(charArray);
+            return people;
+        }
+
+        CharSequence charSeq = extras.getCharSequence(Notification.EXTRA_PEOPLE);
+        if (charSeq != null) {
+            people = new String[1];
+            people[0] = charSeq.toString();
+            return people;
+        }
+
+        CharSequence[] charSeqArray = extras.getCharSequenceArray(Notification.EXTRA_PEOPLE);
+        if (charSeqArray != null) {
+            final int N = charSeqArray.length;
+            people = new String[N];
+            for (int i = 0; i < N; i++) {
+                people[i] = charSeqArray[i].toString();
+            }
+            return people;
+        }
+
+        ArrayList<CharSequence> charSeqList =
+                extras.getCharSequenceArrayList(Notification.EXTRA_PEOPLE);
+        if (charSeqList != null) {
+            final int N = charSeqList.size();
+            people = new String[N];
+            for (int i = 0; i < N; i++) {
+                people[i] = charSeqList.get(i).toString();
+            }
+            return people;
+        }
+        return null;
+    }
+
+    private LookupResult resolvePhoneContact(final String handle, final String number) {
+        LookupResult lookupResult = null;
+        Cursor c = null;
+        try {
+            Uri numberUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
+                    Uri.encode(number));
+            c = mContext.getContentResolver().query(numberUri, LOOKUP_PROJECTION, null, null, null);
+            if (c != null && c.getCount() > 0) {
+                c.moveToFirst();
+                final int idIdx = c.getColumnIndex(Contacts._ID);
+                final int id = c.getInt(idIdx);
+                if (DEBUG) Slog.d(TAG, "is valid: " + id);
+                lookupResult = new LookupResult(id);
+            }
+        } catch(Throwable t) {
+            Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t);
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+        if (lookupResult == null) {
+            lookupResult = new LookupResult(LookupResult.INVALID_ID);
+        }
+        synchronized (mPeopleCache) {
+            mPeopleCache.put(handle, lookupResult);
+        }
+        return lookupResult;
+    }
+
+    private LookupResult resolveContactsUri(String handle, final Uri personUri) {
+        LookupResult lookupResult = null;
+        Cursor c = null;
+        try {
+            c = mContext.getContentResolver().query(personUri, LOOKUP_PROJECTION, null, null, null);
+            if (c != null && c.getCount() > 0) {
+                c.moveToFirst();
+                final int idIdx = c.getColumnIndex(Contacts._ID);
+                final int id = c.getInt(idIdx);
+                if (DEBUG) Slog.d(TAG, "is valid: " + id);
+                lookupResult = new LookupResult(id);
+            }
+        } catch(Throwable t) {
+            Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t);
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+        if (lookupResult == null) {
+            lookupResult = new LookupResult(LookupResult.INVALID_ID);
+        }
+        synchronized (mPeopleCache) {
+            mPeopleCache.put(handle, lookupResult);
+        }
+        return lookupResult;
+    }
+
+    public void initialize(Context context) {
+        if (DEBUG) Slog.d(TAG, "Initializing  " + getClass().getSimpleName() + ".");
+        mContext = context;
+        mPeopleCache = new LruCache<String, LookupResult>(PEOPLE_CACHE_SIZE);
+        mEnabled = ENABLE_PEOPLE_VALIDATOR && 1 == Settings.Global.getInt(
+                mContext.getContentResolver(), SETTING_ENABLE_PEOPLE_VALIDATOR, 1);
+    }
+
+    public RankingFuture process(NotificationManagerService.NotificationRecord record) {
+        if (!mEnabled) {
+            if (INFO) Slog.i(TAG, "disabled");
+            return null;
+        }
+        if (record == null || record.getNotification() == null) {
+            if (INFO) Slog.i(TAG, "skipping empty notification");
+            return null;
+        }
+        return validatePeople(record);
+    }
+
+    private static class LookupResult {
+        private static final long CONTACT_REFRESH_MILLIS = 60 * 60 * 1000;  // 1hr
+        public static final int INVALID_ID = -1;
+
+        private final long mExpireMillis;
+        private int mId;
+
+        public LookupResult(int id) {
+            mId = id;
+            mExpireMillis = System.currentTimeMillis() + CONTACT_REFRESH_MILLIS;
+        }
+
+        public boolean isExpired() {
+            return mExpireMillis < System.currentTimeMillis();
+        }
+
+        public boolean isInvalid() {
+            return mId == INVALID_ID || isExpired();
+        }
+
+        public float getAffinity() {
+            if (isInvalid()) {
+                return NONE;
+            } else {
+                return VALID_CONTACT;  // TODO: finer grained result: stars
+            }
+        }
+
+        public LookupResult setId(int id) {
+            mId = id;
+            return this;
+        }
+    }
+}
+
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
new file mode 100644
index 0000000..f2db791
--- /dev/null
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Log;
+
+import java.util.HashSet;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * {@hide}
+ */
+public class BackgroundDexOptService {
+
+    static final String TAG = "BackgroundDexOptService";
+
+    private final BroadcastReceiver mIdleMaintenanceReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action)) {
+                onIdleStart();
+            } else if (Intent.ACTION_IDLE_MAINTENANCE_END.equals(action)) {
+                onIdleStop();
+            }
+        }
+    };
+
+    final PackageManagerService mPackageManager;
+
+    final AtomicBoolean mIdleTime = new AtomicBoolean(false);
+
+    public BackgroundDexOptService(Context context) {
+        mPackageManager = (PackageManagerService)ServiceManager.getService("package");
+
+        IntentFilter idleMaintenanceFilter = new IntentFilter();
+        idleMaintenanceFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_START);
+        idleMaintenanceFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_END);
+        context.registerReceiverAsUser(mIdleMaintenanceReceiver, UserHandle.ALL,
+                                       idleMaintenanceFilter, null, null);
+    }
+
+    public boolean onIdleStart() {
+        Log.i(TAG, "onIdleStart");
+        if (mPackageManager.isStorageLow()) {
+            return false;
+        }
+        final HashSet<String> pkgs = mPackageManager.getPackagesThatNeedDexOpt();
+        if (pkgs == null) {
+            return false;
+        }
+        mIdleTime.set(true);
+        new Thread("BackgroundDexOptService_DexOpter") {
+            @Override
+            public void run() {
+                for (String pkg : pkgs) {
+                    if (!mIdleTime.get()) {
+                        break;
+                    }
+                    mPackageManager.performDexOpt(pkg, false);
+                }
+            }
+        }.start();
+        return true;
+    }
+
+    public void onIdleStop() {
+        Log.i(TAG, "onIdleStop");
+        mIdleTime.set(false);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ForwardingIntentFilter.java b/services/core/java/com/android/server/pm/ForwardingIntentFilter.java
new file mode 100644
index 0000000..85bde98
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ForwardingIntentFilter.java
@@ -0,0 +1,114 @@
+/*
+ * 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 com.android.server.pm;
+
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+import android.content.IntentFilter;
+import android.util.Log;
+import java.io.IOException;
+import android.os.UserHandle;
+
+/**
+ * The {@link PackageManagerService} maintains some {@link ForwardingIntentFilter}s for every user.
+ * If an {@link Intent} matches the {@link ForwardingIntentFilter}, then it can be forwarded to the
+ * {@link #mUserIdDest}.
+ */
+class ForwardingIntentFilter extends IntentFilter {
+    private static final String ATTR_USER_ID_DEST = "userIdDest";
+    private static final String ATTR_REMOVABLE = "removable";
+    private static final String ATTR_FILTER = "filter";
+
+    private static final String TAG = "ForwardingIntentFilter";
+
+    // If the intent matches the IntentFilter, then it can be forwarded to this userId.
+    final int mUserIdDest;
+    boolean mRemovable;
+
+    ForwardingIntentFilter(IntentFilter filter, boolean removable, int userIdDest) {
+        super(filter);
+        mUserIdDest = userIdDest;
+        mRemovable = removable;
+    }
+
+    public int getUserIdDest() {
+        return mUserIdDest;
+    }
+
+    public boolean isRemovable() {
+        return mRemovable;
+    }
+
+    ForwardingIntentFilter(XmlPullParser parser) throws XmlPullParserException, IOException {
+        String userIdDestString = parser.getAttributeValue(null, ATTR_USER_ID_DEST);
+        if (userIdDestString == null) {
+            String msg = "Missing element under " + TAG +": " + ATTR_USER_ID_DEST + " at " +
+                    parser.getPositionDescription();
+            PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+            mUserIdDest = UserHandle.USER_NULL;
+        } else {
+            mUserIdDest = Integer.parseInt(userIdDestString);
+        }
+        String removableString = parser.getAttributeValue(null, ATTR_REMOVABLE);
+        if (removableString != null) {
+            mRemovable = Boolean.parseBoolean(removableString);
+        }
+        int outerDepth = parser.getDepth();
+        String tagName = parser.getName();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            tagName = parser.getName();
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            } else if (type == XmlPullParser.START_TAG) {
+                if (tagName.equals(ATTR_FILTER)) {
+                    break;
+                } else {
+                    String msg = "Unknown element under " + Settings.TAG_FORWARDING_INTENT_FILTERS
+                            + ": " + tagName + " at " + parser.getPositionDescription();
+                    PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+                    XmlUtils.skipCurrentTag(parser);
+                }
+            }
+        }
+        if (tagName.equals(ATTR_FILTER)) {
+            readFromXml(parser);
+        } else {
+            String msg = "Missing element under " + TAG + ": " + ATTR_FILTER +
+                    " at " + parser.getPositionDescription();
+            PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+            XmlUtils.skipCurrentTag(parser);
+        }
+    }
+
+    public void writeToXml(XmlSerializer serializer) throws IOException {
+        serializer.attribute(null, ATTR_USER_ID_DEST, Integer.toString(mUserIdDest));
+        serializer.attribute(null, ATTR_REMOVABLE, Boolean.toString(mRemovable));
+        serializer.startTag(null, ATTR_FILTER);
+            super.writeToXml(serializer);
+        serializer.endTag(null, ATTR_FILTER);
+    }
+
+    @Override
+    public String toString() {
+        return "ForwardingIntentFilter{0x" + Integer.toHexString(System.identityHashCode(this))
+                + " " + Integer.toString(mUserIdDest) + "}";
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ForwardingIntentResolver.java b/services/core/java/com/android/server/pm/ForwardingIntentResolver.java
new file mode 100644
index 0000000..1616395
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ForwardingIntentResolver.java
@@ -0,0 +1,44 @@
+/*
+ * 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 com.android.server.pm;
+
+
+import java.io.PrintWriter;
+import com.android.server.IntentResolver;
+import java.util.List;
+
+/**
+ * Used to find a list of {@link ForwardingIntentFilter}s that match an intent.
+ */
+class ForwardingIntentResolver
+        extends IntentResolver<ForwardingIntentFilter, ForwardingIntentFilter> {
+    @Override
+    protected ForwardingIntentFilter[] newArray(int size) {
+        return new ForwardingIntentFilter[size];
+    }
+
+    @Override
+    protected boolean isPackageForFilter(String packageName, ForwardingIntentFilter filter) {
+        return false;
+    }
+
+    @Override
+    protected void sortResults(List<ForwardingIntentFilter> results) {
+        //We don't sort the results
+    }
+}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 6030d4d..5e3325c 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -16,14 +16,16 @@
 
 package com.android.server.pm;
 
-import android.content.BroadcastReceiver;
+import android.app.AppGlobals;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
 import android.content.pm.ILauncherApps;
 import android.content.pm.IOnAppsChangedListener;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.graphics.Rect;
@@ -34,6 +36,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.Log;
 import android.util.Slog;
 
 import com.android.internal.content.PackageMonitor;
@@ -46,7 +49,7 @@
  * managed profiles. 
  */
 public class LauncherAppsService extends ILauncherApps.Stub {
-
+    private static final boolean DEBUG = false;
     private static final String TAG = "LauncherAppsService";
     private final Context mContext;
     private final PackageManager mPm;
@@ -69,11 +72,17 @@
     @Override
     public void addOnAppsChangedListener(IOnAppsChangedListener listener) throws RemoteException {
         synchronized (mListeners) {
+            if (DEBUG) {
+                Log.d(TAG, "Adding listener from " + Binder.getCallingUserHandle());
+            }
             if (mListeners.getRegisteredCallbackCount() == 0) {
+                if (DEBUG) {
+                    Log.d(TAG, "Starting package monitoring");
+                }
                 startWatchingPackageBroadcasts();
             }
             mListeners.unregister(listener);
-            mListeners.register(listener);
+            mListeners.register(listener, Binder.getCallingUserHandle());
         }
     }
 
@@ -85,6 +94,9 @@
     public void removeOnAppsChangedListener(IOnAppsChangedListener listener)
             throws RemoteException {
         synchronized (mListeners) {
+            if (DEBUG) {
+                Log.d(TAG, "Removing listener from " + Binder.getCallingUserHandle());
+            }
             mListeners.unregister(listener);
             if (mListeners.getRegisteredCallbackCount() == 0) {
                 stopWatchingPackageBroadcasts();
@@ -103,11 +115,17 @@
      * Unregister package broadcast receiver
      */
     private void stopWatchingPackageBroadcasts() {
+        if (DEBUG) {
+            Log.d(TAG, "Stopped watching for packages");
+        }
         mPackageMonitor.unregister();
     }
 
     void checkCallbackCount() {
-        synchronized (LauncherAppsService.this) {
+        synchronized (mListeners) {
+            if (DEBUG) {
+                Log.d(TAG, "Callback count = " + mListeners.getRegisteredCallbackCount());
+            }
             if (mListeners.getRegisteredCallbackCount() == 0) {
                 stopWatchingPackageBroadcasts();
             }
@@ -137,10 +155,26 @@
         }
     }
 
+    /**
+     * Checks if the user is enabled.
+     */
+    private boolean isUserEnabled(UserHandle user) {
+        long ident = Binder.clearCallingIdentity();
+        try {
+            UserInfo targetUserInfo = mUm.getUserInfo(user.getIdentifier());
+            return targetUserInfo != null && targetUserInfo.isEnabled();
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
     @Override
     public List<ResolveInfo> getLauncherActivities(String packageName, UserHandle user)
             throws RemoteException {
         ensureInUserProfiles(user, "Cannot retrieve activities for unrelated profile " + user);
+        if (!isUserEnabled(user)) {
+            return new ArrayList<ResolveInfo>();
+        }
 
         final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
         mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
@@ -159,6 +193,9 @@
     public ResolveInfo resolveActivity(Intent intent, UserHandle user)
             throws RemoteException {
         ensureInUserProfiles(user, "Cannot resolve activity for unrelated profile " + user);
+        if (!isUserEnabled(user)) {
+            return null;
+        }
 
         long ident = Binder.clearCallingIdentity();
         try {
@@ -170,9 +207,48 @@
     }
 
     @Override
+    public boolean isPackageEnabled(String packageName, UserHandle user)
+            throws RemoteException {
+        ensureInUserProfiles(user, "Cannot check package for unrelated profile " + user);
+        if (!isUserEnabled(user)) {
+            return false;
+        }
+
+        long ident = Binder.clearCallingIdentity();
+        try {
+            IPackageManager pm = AppGlobals.getPackageManager();
+            PackageInfo info = pm.getPackageInfo(packageName, 0, user.getIdentifier());
+            return info != null && info.applicationInfo.enabled;
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
+    public boolean isActivityEnabled(ComponentName component, UserHandle user)
+            throws RemoteException {
+        ensureInUserProfiles(user, "Cannot check component for unrelated profile " + user);
+        if (!isUserEnabled(user)) {
+            return false;
+        }
+
+        long ident = Binder.clearCallingIdentity();
+        try {
+            IPackageManager pm = AppGlobals.getPackageManager();
+            ActivityInfo info = pm.getActivityInfo(component, 0, user.getIdentifier());
+            return info != null && info.isEnabled();
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
     public void startActivityAsUser(ComponentName component, Rect sourceBounds,
             Bundle opts, UserHandle user) throws RemoteException {
         ensureInUserProfiles(user, "Cannot start activity for unrelated profile " + user);
+        if (!isUserEnabled(user)) {
+            throw new IllegalStateException("Cannot start activity for disabled profile "  + user);
+        }
 
         Intent launchIntent = new Intent(Intent.ACTION_MAIN);
         launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
@@ -180,7 +256,6 @@
         launchIntent.setSourceBounds(sourceBounds);
         launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
-        final int callingUserId = UserHandle.getCallingUserId();
         long ident = Binder.clearCallingIdentity();
         try {
             mContext.startActivityAsUser(launchIntent, opts, user);
@@ -191,13 +266,47 @@
 
     private class MyPackageMonitor extends PackageMonitor {
 
+        /** Checks if user is a profile of or same as listeningUser.
+          * and the user is enabled. */
+        private boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser,
+                String debugMsg) {
+            if (user.getIdentifier() == listeningUser.getIdentifier()) {
+                if (DEBUG) Log.d(TAG, "Delivering msg to same user " + debugMsg);
+                return true;
+            }
+            long ident = Binder.clearCallingIdentity();
+            try {
+                UserInfo userInfo = mUm.getUserInfo(user.getIdentifier());
+                UserInfo listeningUserInfo = mUm.getUserInfo(listeningUser.getIdentifier());
+                if (userInfo == null || listeningUserInfo == null
+                        || userInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID
+                        || userInfo.profileGroupId != listeningUserInfo.profileGroupId
+                        || !userInfo.isEnabled()) {
+                    if (DEBUG) {
+                        Log.d(TAG, "Not delivering msg from " + user + " to " + listeningUser + ":"
+                                + debugMsg);
+                    }
+                    return false;
+                } else {
+                    if (DEBUG) {
+                        Log.d(TAG, "Delivering msg from " + user + " to " + listeningUser + ":"
+                                + debugMsg);
+                    }
+                    return true;
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
         @Override
         public void onPackageAdded(String packageName, int uid) {
             UserHandle user = new UserHandle(getChangingUserId());
-            // TODO: if (!isProfile(user)) return;
             final int n = mListeners.beginBroadcast();
             for (int i = 0; i < n; i++) {
                 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+                UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
+                if (!isEnabledProfileOf(user, listeningUser, "onPackageAdded")) continue;
                 try {
                     listener.onPackageAdded(user, packageName);
                 } catch (RemoteException re) {
@@ -212,10 +321,11 @@
         @Override
         public void onPackageRemoved(String packageName, int uid) {
             UserHandle user = new UserHandle(getChangingUserId());
-            // TODO: if (!isCurrentProfile(user)) return;
             final int n = mListeners.beginBroadcast();
             for (int i = 0; i < n; i++) {
                 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+                UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
+                if (!isEnabledProfileOf(user, listeningUser, "onPackageRemoved")) continue;
                 try {
                     listener.onPackageRemoved(user, packageName);
                 } catch (RemoteException re) {
@@ -230,10 +340,11 @@
         @Override
         public void onPackageModified(String packageName) {
             UserHandle user = new UserHandle(getChangingUserId());
-            // TODO: if (!isProfile(user)) return;
             final int n = mListeners.beginBroadcast();
             for (int i = 0; i < n; i++) {
                 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+                UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
+                if (!isEnabledProfileOf(user, listeningUser, "onPackageModified")) continue;
                 try {
                     listener.onPackageChanged(user, packageName);
                 } catch (RemoteException re) {
@@ -248,10 +359,11 @@
         @Override
         public void onPackagesAvailable(String[] packages) {
             UserHandle user = new UserHandle(getChangingUserId());
-            // TODO: if (!isProfile(user)) return;
             final int n = mListeners.beginBroadcast();
             for (int i = 0; i < n; i++) {
                 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+                UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
+                if (!isEnabledProfileOf(user, listeningUser, "onPackagesAvailable")) continue;
                 try {
                     listener.onPackagesAvailable(user, packages, isReplacing());
                 } catch (RemoteException re) {
@@ -266,10 +378,11 @@
         @Override
         public void onPackagesUnavailable(String[] packages) {
             UserHandle user = new UserHandle(getChangingUserId());
-            // TODO: if (!isProfile(user)) return;
             final int n = mListeners.beginBroadcast();
             for (int i = 0; i < n; i++) {
                 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+                UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
+                if (!isEnabledProfileOf(user, listeningUser, "onPackagesUnavailable")) continue;
                 try {
                     listener.onPackagesUnavailable(user, packages, isReplacing());
                 } catch (RemoteException re) {
@@ -284,7 +397,6 @@
     }
 
     class PackageCallbackList<T extends IInterface> extends RemoteCallbackList<T> {
-
         @Override
         public void onCallbackDied(T callback, Object cookie) {
             checkCallbackCount();
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
new file mode 100644
index 0000000..5fdfce4
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 static android.content.pm.PackageManager.INSTALL_ALL_USERS;
+import static android.content.pm.PackageManager.INSTALL_FROM_ADB;
+import static android.content.pm.PackageManager.INSTALL_REPLACE_EXISTING;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.IPackageInstaller;
+import android.content.pm.IPackageInstallerSession;
+import android.content.pm.PackageInstallerParams;
+import android.os.Binder;
+import android.os.FileUtils;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.IoThread;
+import com.google.android.collect.Sets;
+
+import java.io.File;
+
+public class PackageInstallerService extends IPackageInstaller.Stub {
+    private static final String TAG = "PackageInstaller";
+
+    // TODO: destroy sessions with old timestamps
+    // TODO: remove outstanding sessions when installer package goes away
+
+    private final Context mContext;
+    private final PackageManagerService mPm;
+    private final AppOpsManager mAppOps;
+
+    private final File mStagingDir;
+
+    private final HandlerThread mInstallThread = new HandlerThread(TAG);
+    private final Callback mCallback = new Callback();
+
+    @GuardedBy("mSessions")
+    private int mNextSessionId;
+    @GuardedBy("mSessions")
+    private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
+
+    public PackageInstallerService(Context context, PackageManagerService pm, File stagingDir) {
+        mContext = context;
+        mPm = pm;
+        mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+
+        mStagingDir = stagingDir;
+        mStagingDir.mkdirs();
+
+        synchronized (mSessions) {
+            readSessionsLocked();
+
+            // Clean up orphaned staging directories
+            final ArraySet<String> dirs = Sets.newArraySet(mStagingDir.list());
+            for (int i = 0; i < mSessions.size(); i++) {
+                dirs.remove(Integer.toString(mSessions.keyAt(i)));
+            }
+            for (String dirName : dirs) {
+                Slog.w(TAG, "Deleting orphan session " + dirName);
+                final File dir = new File(mStagingDir, dirName);
+                FileUtils.deleteContents(dir);
+                dir.delete();
+            }
+        }
+    }
+
+    private void readSessionsLocked() {
+        // TODO: implement persisting
+        mSessions.clear();
+        mNextSessionId = 1;
+    }
+
+    private void writeSessionsLocked() {
+        // TODO: implement persisting
+    }
+
+    private void writeSessionsAsync() {
+        IoThread.getHandler().post(new Runnable() {
+            @Override
+            public void run() {
+                synchronized (mSessions) {
+                    writeSessionsLocked();
+                }
+            }
+        });
+    }
+
+    @Override
+    public int createSession(int userId, String installerPackageName,
+            PackageInstallerParams params) {
+        final int callingUid = Binder.getCallingUid();
+        mPm.enforceCrossUserPermission(callingUid, userId, false, TAG);
+        mAppOps.checkPackage(callingUid, installerPackageName);
+
+        if (mPm.isUserRestricted(UserHandle.getUserId(callingUid),
+                UserManager.DISALLOW_INSTALL_APPS)) {
+            throw new SecurityException("User restriction prevents installing");
+        }
+
+        if ((callingUid == Process.SHELL_UID) || (callingUid == 0)) {
+            params.installFlags |= INSTALL_FROM_ADB;
+        } else {
+            params.installFlags &= ~INSTALL_FROM_ADB;
+            params.installFlags &= ~INSTALL_ALL_USERS;
+            params.installFlags |= INSTALL_REPLACE_EXISTING;
+        }
+
+        synchronized (mSessions) {
+            final int sessionId = allocateSessionIdLocked();
+            final long createdMillis = System.currentTimeMillis();
+            final File sessionDir = new File(mStagingDir, Integer.toString(sessionId));
+            sessionDir.mkdirs();
+
+            final PackageInstallerSession session = new PackageInstallerSession(mCallback, mPm,
+                    sessionId, userId, installerPackageName, callingUid, params, createdMillis,
+                    sessionDir, mInstallThread.getLooper());
+            mSessions.put(sessionId, session);
+
+            writeSessionsAsync();
+            return sessionId;
+        }
+    }
+
+    @Override
+    public IPackageInstallerSession openSession(int sessionId) {
+        synchronized (mSessions) {
+            final PackageInstallerSession session = mSessions.get(sessionId);
+            if (session == null) {
+                throw new IllegalStateException("Missing session " + sessionId);
+            }
+            if (Binder.getCallingUid() != session.installerUid) {
+                throw new SecurityException("Caller has no access to session " + sessionId);
+            }
+            return session;
+        }
+    }
+
+    private int allocateSessionIdLocked() {
+        if (mSessions.get(mNextSessionId) != null) {
+            throw new IllegalStateException("Next session already allocated");
+        }
+        return mNextSessionId++;
+    }
+
+    @Override
+    public int[] getSessions(int userId, String installerPackageName) {
+        final int callingUid = Binder.getCallingUid();
+        mPm.enforceCrossUserPermission(callingUid, userId, false, TAG);
+        mAppOps.checkPackage(callingUid, installerPackageName);
+
+        int[] matching = new int[0];
+        synchronized (mSessions) {
+            for (int i = 0; i < mSessions.size(); i++) {
+                final int key = mSessions.keyAt(i);
+                final PackageInstallerSession session = mSessions.valueAt(i);
+                if (session.userId == userId
+                        && session.installerPackageName.equals(installerPackageName)) {
+                    matching = ArrayUtils.appendInt(matching, key);
+                }
+            }
+        }
+        return matching;
+    }
+
+    @Override
+    public void uninstall(int userId, String basePackageName, IPackageDeleteObserver observer) {
+        mPm.deletePackageAsUser(basePackageName, observer, userId, 0);
+    }
+
+    @Override
+    public void uninstallSplit(int userId, String basePackageName, String overlayName,
+            IPackageDeleteObserver observer) {
+        // TODO: flesh out once PM has split support
+        throw new UnsupportedOperationException();
+    }
+
+    class Callback {
+        public void onProgressChanged(PackageInstallerSession session) {
+            // TODO: notify listeners
+        }
+
+        public void onSessionInvalid(PackageInstallerSession session) {
+            writeSessionsAsync();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
new file mode 100644
index 0000000..f90d7ab
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -0,0 +1,539 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
+import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
+import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
+import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageInstallObserver2;
+import android.content.pm.IPackageInstallerSession;
+import android.content.pm.PackageInstallerParams;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.PackageLite;
+import android.content.pm.Signature;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.SELinux;
+import android.system.ErrnoException;
+import android.system.OsConstants;
+import android.system.StructStat;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Preconditions;
+
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+import libcore.io.Streams;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+public class PackageInstallerSession extends IPackageInstallerSession.Stub {
+    private static final String TAG = "PackageInstaller";
+
+    private final PackageInstallerService.Callback mCallback;
+    private final PackageManagerService mPm;
+    private final Handler mHandler;
+
+    public final int sessionId;
+    public final int userId;
+    public final String installerPackageName;
+    /** UID not persisted */
+    public final int installerUid;
+    public final PackageInstallerParams params;
+    public final long createdMillis;
+    public final File sessionDir;
+
+    private static final int MSG_INSTALL = 0;
+
+    private Handler.Callback mHandlerCallback = new Handler.Callback() {
+        @Override
+        public boolean handleMessage(Message msg) {
+            synchronized (mLock) {
+                if (msg.obj != null) {
+                    mRemoteObserver = (IPackageInstallObserver2) msg.obj;
+                }
+
+                try {
+                    installLocked();
+                } catch (InstallFailedException e) {
+                    Slog.e(TAG, "Install failed: " + e);
+                    try {
+                        mRemoteObserver.packageInstalled(mPackageName, null, e.error);
+                    } catch (RemoteException ignored) {
+                    }
+                }
+
+                return true;
+            }
+        }
+    };
+
+    private final Object mLock = new Object();
+
+    private int mProgress;
+
+    private String mPackageName;
+    private int mVersionCode;
+    private Signature[] mSignatures;
+
+    private boolean mMutationsAllowed;
+    private boolean mVerifierConfirmed;
+    private boolean mPermissionsConfirmed;
+    private boolean mInvalid;
+
+    private ArrayList<WritePipe> mPipes = new ArrayList<>();
+
+    private IPackageInstallObserver2 mRemoteObserver;
+
+    public PackageInstallerSession(PackageInstallerService.Callback callback,
+            PackageManagerService pm, int sessionId, int userId, String installerPackageName,
+            int installerUid, PackageInstallerParams params, long createdMillis, File sessionDir,
+            Looper looper) {
+        mCallback = callback;
+        mPm = pm;
+        mHandler = new Handler(looper, mHandlerCallback);
+
+        this.sessionId = sessionId;
+        this.userId = userId;
+        this.installerPackageName = installerPackageName;
+        this.installerUid = installerUid;
+        this.params = params;
+        this.createdMillis = createdMillis;
+        this.sessionDir = sessionDir;
+
+        // Check against any explicitly provided signatures
+        mSignatures = params.signatures;
+
+        // TODO: splice in flag when restoring persisted session
+        mMutationsAllowed = true;
+
+        if (pm.checkPermission(android.Manifest.permission.INSTALL_PACKAGES, installerPackageName)
+                == PackageManager.PERMISSION_GRANTED) {
+            mPermissionsConfirmed = true;
+        }
+    }
+
+    @Override
+    public void updateProgress(int progress) {
+        mProgress = progress;
+        mCallback.onProgressChanged(this);
+    }
+
+    @Override
+    public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
+        // TODO: relay over to DCS when installing to ASEC
+
+        // Quick sanity check of state, and allocate a pipe for ourselves. We
+        // then do heavy disk allocation outside the lock, but this open pipe
+        // will block any attempted install transitions.
+        final WritePipe pipe;
+        synchronized (mLock) {
+            if (!mMutationsAllowed) {
+                throw new IllegalStateException("Mutations not allowed");
+            }
+
+            pipe = new WritePipe();
+            mPipes.add(pipe);
+        }
+
+        try {
+            // Use installer provided name for now; we always rename later
+            if (!FileUtils.isValidExtFilename(name)) {
+                throw new IllegalArgumentException("Invalid name: " + name);
+            }
+            final File target = new File(sessionDir, name);
+
+            final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(),
+                    OsConstants.O_CREAT | OsConstants.O_WRONLY, 00700);
+
+            // If caller specified a total length, allocate it for them. Free up
+            // cache space to grow, if needed.
+            if (lengthBytes > 0) {
+                final StructStat stat = Libcore.os.fstat(targetFd);
+                final long deltaBytes = lengthBytes - stat.st_size;
+                if (deltaBytes > 0) {
+                    mPm.freeStorage(deltaBytes);
+                }
+                Libcore.os.posix_fallocate(targetFd, 0, lengthBytes);
+            }
+
+            if (offsetBytes > 0) {
+                Libcore.os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
+            }
+
+            pipe.setTargetFd(targetFd);
+            pipe.start();
+            return pipe.getWriteFd();
+
+        } catch (ErrnoException e) {
+            throw new IllegalStateException("Failed to write", e);
+        } catch (IOException e) {
+            throw new IllegalStateException("Failed to write", e);
+        }
+    }
+
+    @Override
+    public void install(IPackageInstallObserver2 observer) {
+        Preconditions.checkNotNull(observer);
+        mHandler.obtainMessage(MSG_INSTALL, observer).sendToTarget();
+    }
+
+    private void installLocked() throws InstallFailedException {
+        if (mInvalid) {
+            throw new InstallFailedException(INSTALL_FAILED_ALREADY_EXISTS, "Invalid session");
+        }
+
+        // Verify that all writers are hands-off
+        if (mMutationsAllowed) {
+            for (WritePipe pipe : mPipes) {
+                if (!pipe.isClosed()) {
+                    throw new InstallFailedException(INSTALL_FAILED_PACKAGE_CHANGED,
+                            "Files still open");
+                }
+            }
+            mMutationsAllowed = false;
+
+            // TODO: persist disabled mutations before going forward, since
+            // beyond this point we may have hardlinks to the valid install
+        }
+
+        // Verify that stage looks sane with respect to existing application.
+        // This currently only ensures packageName, versionCode, and certificate
+        // consistency.
+        validateInstallLocked();
+
+        Preconditions.checkNotNull(mPackageName);
+        Preconditions.checkNotNull(mSignatures);
+
+        if (!mVerifierConfirmed) {
+            // TODO: async communication with verifier
+            // when they confirm, we'll kick off another install() pass
+            mVerifierConfirmed = true;
+        }
+
+        if (!mPermissionsConfirmed) {
+            // TODO: async confirm permissions with user
+            // when they confirm, we'll kick off another install() pass
+            mPermissionsConfirmed = true;
+        }
+
+        // Unpack any native libraries contained in this session
+        unpackNativeLibraries();
+
+        // Inherit any packages and native libraries from existing install that
+        // haven't been overridden.
+        if (!params.fullInstall) {
+            spliceExistingFilesIntoStage();
+        }
+
+        // TODO: for ASEC based applications, grow and stream in packages
+
+        // We've reached point of no return; call into PMS to install the stage.
+        // Regardless of success or failure we always destroy session.
+        final IPackageInstallObserver2 remoteObserver = mRemoteObserver;
+        final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
+            @Override
+            public void packageInstalled(String basePackageName, Bundle extras, int returnCode)
+                    throws RemoteException {
+                destroy();
+                remoteObserver.packageInstalled(basePackageName, extras, returnCode);
+            }
+        };
+
+        mPm.installStage(mPackageName, this.sessionDir, localObserver, params.installFlags);
+    }
+
+    /**
+     * Validate install by confirming that all application packages are have
+     * consistent package name, version code, and signing certificates.
+     * <p>
+     * Renames package files in stage to match split names defined inside.
+     */
+    private void validateInstallLocked() throws InstallFailedException {
+        mPackageName = null;
+        mVersionCode = -1;
+        mSignatures = null;
+
+        final File[] files = sessionDir.listFiles();
+        if (ArrayUtils.isEmpty(files)) {
+            throw new InstallFailedException(INSTALL_FAILED_INVALID_APK, "No packages staged");
+        }
+
+        final ArraySet<String> seenSplits = new ArraySet<>();
+
+        // Verify that all staged packages are internally consistent
+        for (File file : files) {
+            final PackageLite info = PackageParser.parsePackageLite(file.getAbsolutePath(),
+                    PackageParser.PARSE_GET_SIGNATURES);
+            if (info == null) {
+                throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
+                        "Failed to parse " + file);
+            }
+
+            if (!seenSplits.add(info.splitName)) {
+                throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
+                        "Split " + info.splitName + " was defined multiple times");
+            }
+
+            // Use first package to define unknown values
+            if (mPackageName != null) {
+                mPackageName = info.packageName;
+                mVersionCode = info.versionCode;
+            }
+            if (mSignatures != null) {
+                mSignatures = info.signatures;
+            }
+
+            assertPackageConsistent(String.valueOf(file), info.packageName, info.versionCode,
+                    info.signatures);
+
+            // Take this opportunity to enforce uniform naming
+            final String name;
+            if (info.splitName == null) {
+                name = info.packageName + ".apk";
+            } else {
+                name = info.packageName + "-" + info.splitName + ".apk";
+            }
+            if (!FileUtils.isValidExtFilename(name)) {
+                throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
+                        "Invalid filename: " + name);
+            }
+            if (!file.getName().equals(name)) {
+                file.renameTo(new File(file.getParentFile(), name));
+            }
+        }
+
+        // TODO: shift package signature verification to installer; we're
+        // currently relying on PMS to do this.
+        // TODO: teach about compatible upgrade keysets.
+
+        if (params.fullInstall) {
+            // Full installs must include a base package
+            if (!seenSplits.contains(null)) {
+                throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
+                        "Full install must include a base package");
+            }
+
+        } else {
+            // Partial installs must be consistent with existing install.
+            final ApplicationInfo app = mPm.getApplicationInfo(mPackageName, 0, userId);
+            if (app == null) {
+                throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
+                        "Missing existing base package for " + mPackageName);
+            }
+
+            final PackageLite info = PackageParser.parsePackageLite(app.sourceDir,
+                    PackageParser.PARSE_GET_SIGNATURES);
+            if (info == null) {
+                throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
+                        "Failed to parse existing base " + app.sourceDir);
+            }
+
+            assertPackageConsistent("Existing base", info.packageName, info.versionCode,
+                    info.signatures);
+        }
+    }
+
+    private void assertPackageConsistent(String tag, String packageName, int versionCode,
+            Signature[] signatures) throws InstallFailedException {
+        if (!mPackageName.equals(packageName)) {
+            throw new InstallFailedException(INSTALL_FAILED_INVALID_APK, tag + " package "
+                    + packageName + " inconsistent with " + mPackageName);
+        }
+        if (mVersionCode != versionCode) {
+            throw new InstallFailedException(INSTALL_FAILED_INVALID_APK, tag
+                    + " version code " + versionCode + " inconsistent with "
+                    + mVersionCode);
+        }
+        if (!Signature.areExactMatch(mSignatures, signatures)) {
+            throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
+                    tag + " signatures are inconsistent");
+        }
+    }
+
+    /**
+     * Application is already installed; splice existing files that haven't been
+     * overridden into our stage.
+     */
+    private void spliceExistingFilesIntoStage() throws InstallFailedException {
+        final ApplicationInfo app = mPm.getApplicationInfo(mPackageName, 0, userId);
+        final File existingDir = new File(app.sourceDir).getParentFile();
+
+        try {
+            linkTreeIgnoringExisting(existingDir, sessionDir);
+        } catch (ErrnoException e) {
+            throw new InstallFailedException(INSTALL_FAILED_INTERNAL_ERROR,
+                    "Failed to splice into stage");
+        }
+    }
+
+    /**
+     * Recursively hard link all files from source directory tree to target.
+     * When a file already exists in the target tree, it leaves that file
+     * intact.
+     */
+    private void linkTreeIgnoringExisting(File sourceDir, File targetDir) throws ErrnoException {
+        final File[] sourceContents = sourceDir.listFiles();
+        if (ArrayUtils.isEmpty(sourceContents)) return;
+
+        for (File sourceFile : sourceContents) {
+            final File targetFile = new File(targetDir, sourceFile.getName());
+
+            if (sourceFile.isDirectory()) {
+                targetFile.mkdir();
+                linkTreeIgnoringExisting(sourceFile, targetFile);
+            } else {
+                Libcore.os.link(sourceFile.getAbsolutePath(), targetFile.getAbsolutePath());
+            }
+        }
+    }
+
+    private void unpackNativeLibraries() throws InstallFailedException {
+        final File libDir = new File(sessionDir, "lib");
+
+        if (!libDir.mkdir()) {
+            throw new InstallFailedException(INSTALL_FAILED_INTERNAL_ERROR,
+                    "Failed to create " + libDir);
+        }
+
+        try {
+            Libcore.os.chmod(libDir.getAbsolutePath(), 0755);
+        } catch (ErrnoException e) {
+            throw new InstallFailedException(INSTALL_FAILED_INTERNAL_ERROR,
+                    "Failed to prepare " + libDir + ": " + e);
+        }
+
+        if (!SELinux.restorecon(libDir)) {
+            throw new InstallFailedException(INSTALL_FAILED_INTERNAL_ERROR,
+                    "Failed to set context on " + libDir);
+        }
+
+        // Unpack all native libraries under stage
+        final File[] files = sessionDir.listFiles();
+        if (ArrayUtils.isEmpty(files)) {
+            throw new InstallFailedException(INSTALL_FAILED_INVALID_APK, "No packages staged");
+        }
+
+        for (File file : files) {
+            final NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(file);
+            try {
+                final int abiIndex = NativeLibraryHelper.findSupportedAbi(handle,
+                        Build.SUPPORTED_ABIS);
+                if (abiIndex >= 0) {
+                    int copyRet = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle, libDir,
+                            Build.SUPPORTED_ABIS[abiIndex]);
+                    if (copyRet != INSTALL_SUCCEEDED) {
+                        throw new InstallFailedException(copyRet,
+                                "Failed to copy native libraries for " + file);
+                    }
+                } else if (abiIndex != PackageManager.NO_NATIVE_LIBRARIES) {
+                    throw new InstallFailedException(abiIndex,
+                            "Failed to copy native libraries for " + file);
+                }
+            } finally {
+                handle.close();
+            }
+        }
+    }
+
+    @Override
+    public void destroy() {
+        try {
+            synchronized (mLock) {
+                mInvalid = true;
+            }
+            FileUtils.deleteContents(sessionDir);
+            sessionDir.delete();
+        } finally {
+            mCallback.onSessionInvalid(this);
+        }
+    }
+
+    private static class WritePipe extends Thread {
+        private final ParcelFileDescriptor[] mPipe;
+
+        private FileDescriptor mTargetFd;
+
+        private volatile boolean mClosed;
+
+        public WritePipe() {
+            try {
+                mPipe = ParcelFileDescriptor.createPipe();
+            } catch (IOException e) {
+                throw new IllegalStateException("Failed to create pipe");
+            }
+        }
+
+        public boolean isClosed() {
+            return mClosed;
+        }
+
+        public void setTargetFd(FileDescriptor targetFd) {
+            mTargetFd = targetFd;
+        }
+
+        public ParcelFileDescriptor getWriteFd() {
+            return mPipe[1];
+        }
+
+        @Override
+        public void run() {
+            FileInputStream in = null;
+            FileOutputStream out = null;
+            try {
+                // TODO: look at switching to sendfile(2) to speed up
+                in = new FileInputStream(mPipe[0].getFileDescriptor());
+                out = new FileOutputStream(mTargetFd);
+                Streams.copy(in, out);
+            } catch (IOException e) {
+                Slog.w(TAG, "Failed to stream data: " + e);
+            } finally {
+                IoUtils.closeQuietly(mPipe[0]);
+                IoUtils.closeQuietly(mTargetFd);
+                mClosed = true;
+            }
+        }
+    }
+
+    private class InstallFailedException extends Exception {
+        private final int error;
+
+        public InstallFailedException(int error, String detailMessage) {
+            super(detailMessage);
+            this.error = error;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fffce8c..a3ecc05 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -18,20 +18,25 @@
 
 import static android.Manifest.permission.GRANT_REVOKE_PERMISSIONS;
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.Manifest.permission.INSTALL_PACKAGES;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-import static android.system.OsConstants.S_IRWXU;
+import static android.os.Process.PACKAGE_INFO_GID;
+import static android.os.Process.SYSTEM_UID;
 import static android.system.OsConstants.S_IRGRP;
-import static android.system.OsConstants.S_IXGRP;
 import static android.system.OsConstants.S_IROTH;
+import static android.system.OsConstants.S_IRWXU;
+import static android.system.OsConstants.S_IXGRP;
 import static android.system.OsConstants.S_IXOTH;
+import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
+import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_USER_OWNER;
 import static com.android.internal.util.ArrayUtils.appendInt;
 import static com.android.internal.util.ArrayUtils.removeInt;
 
-import android.content.pm.PackageParser.*;
+import com.android.internal.R;
 import com.android.internal.app.IMediaContainerService;
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.NativeLibraryHelper;
@@ -41,10 +46,13 @@
 import com.android.internal.util.XmlUtils;
 import com.android.server.EventLogTags;
 import com.android.server.IntentResolver;
-import com.android.server.ServiceThread;
-
 import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
 import com.android.server.Watchdog;
+import com.android.server.pm.Settings.DatabaseVersion;
+import com.android.server.storage.DeviceStorageMonitorInternal;
+import com.android.server.storage.DeviceStorageMonitorInternal;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -52,6 +60,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
+import android.app.PackageInstallObserver;
 import android.app.admin.IDevicePolicyManager;
 import android.app.backup.IBackupManager;
 import android.content.BroadcastReceiver;
@@ -71,6 +80,7 @@
 import android.content.pm.IPackageDeleteObserver;
 import android.content.pm.IPackageInstallObserver;
 import android.content.pm.IPackageInstallObserver2;
+import android.content.pm.IPackageInstaller;
 import android.content.pm.IPackageManager;
 import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
@@ -79,7 +89,9 @@
 import android.content.pm.PackageCleanItem;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInfoLite;
+import android.content.pm.PackageInstallerParams;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageParser.ActivityIntentInfo;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageStats;
 import android.content.pm.PackageUserState;
@@ -123,6 +135,7 @@
 import android.system.Os;
 import android.system.StructStat;
 import android.text.TextUtils;
+import android.util.AtomicFile;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
@@ -133,6 +146,7 @@
 import android.util.Xml;
 import android.view.Display;
 
+import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileDescriptor;
@@ -142,7 +156,9 @@
 import java.io.FileReader;
 import java.io.FilenameFilter;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
 import java.security.NoSuchAlgorithmException;
 import java.security.PublicKey;
 import java.security.cert.Certificate;
@@ -161,13 +177,14 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
 
+import dalvik.system.DexFile;
+import dalvik.system.StaleDexCacheError;
 import dalvik.system.VMRuntime;
-import libcore.io.IoUtils;
 
-import com.android.internal.R;
-import com.android.server.pm.Settings.DatabaseVersion;
-import com.android.server.storage.DeviceStorageMonitorInternal;
+import libcore.io.IoUtils;
 
 /**
  * Keep track of all those .apks everywhere.
@@ -195,6 +212,7 @@
     private static final boolean DEBUG_PACKAGE_SCANNING = false;
     private static final boolean DEBUG_APP_DIR_OBSERVER = false;
     private static final boolean DEBUG_VERIFY = false;
+    private static final boolean DEBUG_DEXOPT = false;
 
     private static final int RADIO_UID = Process.PHONE_UID;
     private static final int LOG_UID = Process.LOG_UID;
@@ -285,7 +303,6 @@
     final Context mContext;
     final boolean mFactoryTest;
     final boolean mOnlyCore;
-    final boolean mNoDexOpt;
     final DisplayMetrics mMetrics;
     final int mDefParseFlags;
     final String[] mSeparateProcesses;
@@ -339,6 +356,8 @@
     // apps.
     final File mDrmAppPrivateInstallDir;
 
+    final File mAppStagingDir;
+
     // ----------------------------------------------------------------
 
     // Lock for state used when installing and doing other long running
@@ -445,6 +464,8 @@
     final SparseArray<PackageVerificationState> mPendingVerification
             = new SparseArray<PackageVerificationState>();
 
+    final PackageInstallerService mInstallerService;
+
     HashSet<PackageParser.Package> mDeferredDexOpt = null;
 
     /** Token for keys in mPendingVerification. */
@@ -591,6 +612,146 @@
 
     private final String mRequiredVerifierPackage;
 
+    private final PackageUsage mPackageUsage = new PackageUsage();
+
+    private class PackageUsage {
+        private static final int WRITE_INTERVAL
+            = (DEBUG_DEXOPT) ? 0 : 30*60*1000; // 30m in ms
+
+        private final Object mFileLock = new Object();
+        private final AtomicLong mLastWritten = new AtomicLong(0);
+        private final AtomicBoolean mBackgroundWriteRunning = new AtomicBoolean(false);
+
+        private boolean mIsFirstBoot = false;
+
+        boolean isFirstBoot() {
+            return mIsFirstBoot;
+        }
+
+        void write(boolean force) {
+            if (force) {
+                writeInternal();
+                return;
+            }
+            if (SystemClock.elapsedRealtime() - mLastWritten.get() < WRITE_INTERVAL
+                && !DEBUG_DEXOPT) {
+                return;
+            }
+            if (mBackgroundWriteRunning.compareAndSet(false, true)) {
+                new Thread("PackageUsage_DiskWriter") {
+                    @Override
+                    public void run() {
+                        try {
+                            writeInternal();
+                        } finally {
+                            mBackgroundWriteRunning.set(false);
+                        }
+                    }
+                }.start();
+            }
+        }
+
+        private void writeInternal() {
+            synchronized (mPackages) {
+                synchronized (mFileLock) {
+                    AtomicFile file = getFile();
+                    FileOutputStream f = null;
+                    try {
+                        f = file.startWrite();
+                        BufferedOutputStream out = new BufferedOutputStream(f);
+                        FileUtils.setPermissions(file.getBaseFile().getPath(), 0660, SYSTEM_UID, PACKAGE_INFO_GID);
+                        StringBuilder sb = new StringBuilder();
+                        for (PackageParser.Package pkg : mPackages.values()) {
+                            if (pkg.mLastPackageUsageTimeInMills == 0) {
+                                continue;
+                            }
+                            sb.setLength(0);
+                            sb.append(pkg.packageName);
+                            sb.append(' ');
+                            sb.append((long)pkg.mLastPackageUsageTimeInMills);
+                            sb.append('\n');
+                            out.write(sb.toString().getBytes(StandardCharsets.US_ASCII));
+                        }
+                        out.flush();
+                        file.finishWrite(f);
+                    } catch (IOException e) {
+                        if (f != null) {
+                            file.failWrite(f);
+                        }
+                        Log.e(TAG, "Failed to write package usage times", e);
+                    }
+                }
+            }
+            mLastWritten.set(SystemClock.elapsedRealtime());
+        }
+
+        void readLP() {
+            synchronized (mFileLock) {
+                AtomicFile file = getFile();
+                BufferedInputStream in = null;
+                try {
+                    in = new BufferedInputStream(file.openRead());
+                    StringBuffer sb = new StringBuffer();
+                    while (true) {
+                        String packageName = readToken(in, sb, ' ');
+                        if (packageName == null) {
+                            break;
+                        }
+                        String timeInMillisString = readToken(in, sb, '\n');
+                        if (timeInMillisString == null) {
+                            throw new IOException("Failed to find last usage time for package "
+                                                  + packageName);
+                        }
+                        PackageParser.Package pkg = mPackages.get(packageName);
+                        if (pkg == null) {
+                            continue;
+                        }
+                        long timeInMillis;
+                        try {
+                            timeInMillis = Long.parseLong(timeInMillisString.toString());
+                        } catch (NumberFormatException e) {
+                            throw new IOException("Failed to parse " + timeInMillisString
+                                                  + " as a long.", e);
+                        }
+                        pkg.mLastPackageUsageTimeInMills = timeInMillis;
+                    }
+                } catch (FileNotFoundException expected) {
+                    mIsFirstBoot = true;
+                } catch (IOException e) {
+                    Log.w(TAG, "Failed to read package usage times", e);
+                } finally {
+                    IoUtils.closeQuietly(in);
+                }
+            }
+            mLastWritten.set(SystemClock.elapsedRealtime());
+        }
+
+        private String readToken(InputStream in, StringBuffer sb, char endOfToken)
+                throws IOException {
+            sb.setLength(0);
+            while (true) {
+                int ch = in.read();
+                if (ch == -1) {
+                    if (sb.length() == 0) {
+                        return null;
+                    }
+                    throw new IOException("Unexpected EOF");
+                }
+                if (ch == endOfToken) {
+                    return sb.toString();
+                }
+                sb.append((char)ch);
+            }
+        }
+
+        private AtomicFile getFile() {
+            File dataDir = Environment.getDataDirectory();
+            File systemDir = new File(dataDir, "system");
+            File fname = new File(systemDir, "package-usage.list");
+            return new AtomicFile(fname);
+        }
+    }
+
     class PackageHandler extends Handler {
         private boolean mBound = false;
         final ArrayList<HandlerParams> mPendingInstalls =
@@ -1135,7 +1296,6 @@
         mContext = context;
         mFactoryTest = factoryTest;
         mOnlyCore = onlyCore;
-        mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
         mMetrics = new DisplayMetrics();
         mSettings = new Settings(context);
         mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
@@ -1188,6 +1348,7 @@
             mAsecInternalPath = new File(dataDir, "app-asec").getPath();
             mUserAppDataDir = new File(dataDir, "user");
             mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
+            mAppStagingDir = new File(dataDir, "app-staging");
 
             sUserManager = new UserManagerService(context, this,
                     mInstallLock, mPackages);
@@ -1221,10 +1382,6 @@
             // Set flag to monitor and not change apk file paths when
             // scanning install directories.
             int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;
-            if (mNoDexOpt) {
-                Slog.w(TAG, "Running ENG build: no pre-dexopt!");
-                scanMode |= SCAN_NO_DEX;
-            }
 
             final HashSet<String> alreadyDexOpted = new HashSet<String>();
 
@@ -1243,7 +1400,7 @@
                 Slog.w(TAG, "No BOOTCLASSPATH found!");
             }
 
-            boolean didDexOpt = false;
+            boolean didDexOptLibraryOrTool = false;
 
             final List<String> instructionSets = getAllInstructionSets();
 
@@ -1263,13 +1420,12 @@
                         }
 
                         try {
-                            if (dalvik.system.DexFile.isDexOptNeededInternal(
-                                    lib, null, instructionSet, false)) {
+                            if (DexFile.isDexOptNeededInternal(lib, null, instructionSet, false)) {
                                 alreadyDexOpted.add(lib);
 
                                 // The list of "shared libraries" we have at this point is
                                 mInstaller.dexopt(lib, Process.SYSTEM_UID, true, instructionSet);
-                                didDexOpt = true;
+                                didDexOptLibraryOrTool = true;
                             }
                         } catch (FileNotFoundException e) {
                             Slog.w(TAG, "Library not found: " + lib);
@@ -1315,9 +1471,9 @@
                             continue;
                         }
                         try {
-                            if (dalvik.system.DexFile.isDexOptNeededInternal(path, null, instructionSet, false)) {
+                            if (DexFile.isDexOptNeededInternal(path, null, instructionSet, false)) {
                                 mInstaller.dexopt(path, Process.SYSTEM_UID, true, instructionSet);
-                                didDexOpt = true;
+                                didDexOptLibraryOrTool = true;
                             }
                         } catch (FileNotFoundException e) {
                             Slog.w(TAG, "Jar not found: " + path);
@@ -1328,7 +1484,7 @@
                 }
             }
 
-            if (didDexOpt) {
+            if (didDexOptLibraryOrTool) {
                 pruneDexFiles(new File(dataDir, "dalvik-cache"));
             }
 
@@ -1507,12 +1663,15 @@
             // the correct library paths.
             updateAllSharedLibrariesLPw();
 
-
             for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
                 adjustCpuAbisForSharedUserLPw(setting.packages, true /* do dexopt */,
                         false /* force dexopt */, false /* defer dexopt */);
             }
 
+            // Now that we know all the packages we are keeping,
+            // read and update their last usage times.
+            mPackageUsage.readLP();
+
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
                     SystemClock.uptimeMillis());
             Slog.i(TAG, "Time to scan packages: "
@@ -1552,14 +1711,17 @@
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
                     SystemClock.uptimeMillis());
 
-            // Now after opening every single application zip, make sure they
-            // are all flushed.  Not really needed, but keeps things nice and
-            // tidy.
-            Runtime.getRuntime().gc();
 
             mRequiredVerifierPackage = getRequiredVerifierLPr();
         } // synchronized (mPackages)
         } // synchronized (mInstallLock)
+
+        mInstallerService = new PackageInstallerService(context, this, mAppStagingDir);
+
+        // Now after opening every single application zip, make sure they
+        // are all flushed.  Not really needed, but keeps things nice and
+        // tidy.
+        Runtime.getRuntime().gc();
     }
 
     private static void pruneDexFiles(File cacheDir) {
@@ -1571,6 +1733,14 @@
         //
         // Additionally, delete all dex files from the root directory
         // since there shouldn't be any there anyway.
+        //
+        // Note: This isn't as good an indicator as it used to be. It
+        // used to include the boot classpath but at some point
+        // DexFile.isDexOptNeeded started returning false for the boot
+        // class path files in all cases. It is very possible in a
+        // small maintenance release update that the library and tool
+        // jars may be unchanged but APK could be removed resulting in
+        // unused dalvik-cache files.
         File[] files = cacheDir.listFiles();
         if (files != null) {
             for (File file : files) {
@@ -1593,10 +1763,12 @@
         }
     }
 
+    @Override
     public boolean isFirstBoot() {
-        return !mRestoredSettings;
+        return !mRestoredSettings || mPackageUsage.isFirstBoot();
     }
 
+    @Override
     public boolean isOnlyCoreApps() {
         return mOnlyCore;
     }
@@ -1893,6 +2065,7 @@
                 state, userId);
     }
 
+    @Override
     public boolean isPackageAvailable(String packageName, int userId) {
         if (!sUserManager.exists(userId)) return false;
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "is package available");
@@ -1930,6 +2103,7 @@
         return null;
     }
 
+    @Override
     public String[] currentToCanonicalPackageNames(String[] names) {
         String[] out = new String[names.length];
         // reader
@@ -1942,6 +2116,7 @@
         return out;
     }
     
+    @Override
     public String[] canonicalToCurrentPackageNames(String[] names) {
         String[] out = new String[names.length];
         // reader
@@ -2002,6 +2177,7 @@
         return pi;
     }
     
+    @Override
     public PermissionInfo getPermissionInfo(String name, int flags) {
         // reader
         synchronized (mPackages) {
@@ -2013,6 +2189,7 @@
         }
     }
 
+    @Override
     public List<PermissionInfo> queryPermissionsByGroup(String group, int flags) {
         // reader
         synchronized (mPackages) {
@@ -2036,6 +2213,7 @@
         }
     }
 
+    @Override
     public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) {
         // reader
         synchronized (mPackages) {
@@ -2044,6 +2222,7 @@
         }
     }
 
+    @Override
     public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
         // reader
         synchronized (mPackages) {
@@ -2086,7 +2265,8 @@
                 if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) == 0) {
                     return null;
                 }
-                pkg = new PackageParser.Package(packageName);
+                // TODO: teach about reading split name
+                pkg = new PackageParser.Package(packageName, null);
                 pkg.applicationInfo.packageName = packageName;
                 pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
                 pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
@@ -2129,6 +2309,7 @@
     }
 
 
+    @Override
     public void freeStorageAndNotify(final long freeStorageSize, final IPackageDataObserver observer) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CLEAR_APP_CACHE, null);
@@ -2154,6 +2335,7 @@
         });
     }
 
+    @Override
     public void freeStorage(final long freeStorageSize, final IntentSender pi) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CLEAR_APP_CACHE, null);
@@ -2182,6 +2364,14 @@
         });
     }
 
+    void freeStorage(long freeStorageSize) throws IOException {
+        synchronized (mInstallLock) {
+            if (mInstaller.freeCache(freeStorageSize) < 0) {
+                throw new IOException("Failed to free enough space");
+            }
+        }
+    }
+
     @Override
     public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
@@ -2275,6 +2465,7 @@
         return null;
     }
 
+    @Override
     public String[] getSystemSharedLibraryNames() {
         Set<String> libSet;
         synchronized (mPackages) {
@@ -2289,6 +2480,7 @@
         return null;
     }
 
+    @Override
     public FeatureInfo[] getSystemAvailableFeatures() {
         Collection<FeatureInfo> featSet;
         synchronized (mPackages) {
@@ -2307,6 +2499,7 @@
         return null;
     }
 
+    @Override
     public boolean hasSystemFeature(String name) {
         synchronized (mPackages) {
             return mAvailableFeatures.containsKey(name);
@@ -2321,6 +2514,7 @@
                 + " is not privileged to communicate with user=" + userId);
     }
 
+    @Override
     public int checkPermission(String permName, String pkgName) {
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(pkgName);
@@ -2338,6 +2532,7 @@
         return PackageManager.PERMISSION_DENIED;
     }
 
+    @Override
     public int checkUidPermission(String permName, int uid) {
         synchronized (mPackages) {
             Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
@@ -2360,10 +2555,9 @@
      * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS
      * or INTERACT_ACROSS_USERS_FULL permissions, if the userid is not for the caller.
      * @param message the message to log on security exception
-     * @return
      */
-    private void enforceCrossUserPermission(int callingUid, int userId,
-            boolean requireFullPermission, String message) {
+    void enforceCrossUserPermission(int callingUid, int userId, boolean requireFullPermission,
+            String message) {
         if (userId < 0) {
             throw new IllegalArgumentException("Invalid userId " + userId);
         }
@@ -2512,18 +2706,21 @@
         return added;
     }
 
+    @Override
     public boolean addPermission(PermissionInfo info) {
         synchronized (mPackages) {
             return addPermissionLocked(info, false);
         }
     }
 
+    @Override
     public boolean addPermissionAsync(PermissionInfo info) {
         synchronized (mPackages) {
             return addPermissionLocked(info, true);
         }
     }
 
+    @Override
     public void removePermission(String name) {
         synchronized (mPackages) {
             checkPermissionTreeLP(name);
@@ -2568,6 +2765,7 @@
         }
     }
 
+    @Override
     public void grantPermission(String packageName, String permissionName) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.GRANT_REVOKE_PERMISSIONS, null);
@@ -2597,6 +2795,7 @@
         }
     }
 
+    @Override
     public void revokePermission(String packageName, String permissionName) {
         int changedAppId = -1;
 
@@ -2655,12 +2854,14 @@
         }
     }
 
+    @Override
     public boolean isProtectedBroadcast(String actionName) {
         synchronized (mPackages) {
             return mProtectedBroadcasts.contains(actionName);
         }
     }
 
+    @Override
     public int checkSignatures(String pkg1, String pkg2) {
         synchronized (mPackages) {
             final PackageParser.Package p1 = mPackages.get(pkg1);
@@ -2673,6 +2874,7 @@
         }
     }
 
+    @Override
     public int checkUidSignatures(int uid1, int uid2) {
         // Map to base uids.
         uid1 = UserHandle.getAppId(uid1);
@@ -2812,6 +3014,7 @@
         return PackageManager.SIGNATURE_NO_MATCH;
     }
 
+    @Override
     public String[] getPackagesForUid(int uid) {
         uid = UserHandle.getAppId(uid);
         // reader
@@ -2835,6 +3038,7 @@
         return null;
     }
 
+    @Override
     public String getNameForUid(int uid) {
         // reader
         synchronized (mPackages) {
@@ -2850,6 +3054,7 @@
         return null;
     }
 
+    @Override
     public int getUidForSharedUser(String sharedUserName) {
         if(sharedUserName == null) {
             return -1;
@@ -2864,6 +3069,7 @@
         }
     }
 
+    @Override
     public int getFlagsForUid(int uid) {
         synchronized (mPackages) {
             Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
@@ -3162,6 +3368,33 @@
         return null;
     }
 
+    /*
+     * Returns if intent can be forwarded from the userId from to dest
+     */
+    @Override
+    public boolean canForwardTo(Intent intent, String resolvedType, int userIdFrom, int userIdDest) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+        List<ForwardingIntentFilter> matches =
+                getMatchingForwardingIntentFilters(intent, resolvedType, userIdFrom);
+        if (matches != null) {
+            int size = matches.size();
+            for (int i = 0; i < size; i++) {
+                if (matches.get(i).getUserIdDest() == userIdDest) return true;
+            }
+        }
+        return false;
+    }
+
+    private List<ForwardingIntentFilter> getMatchingForwardingIntentFilters(Intent intent,
+            String resolvedType, int userId) {
+        ForwardingIntentResolver fir = mSettings.mForwardingIntentResolvers.get(userId);
+        if (fir != null) {
+            return fir.queryIntent(intent, resolvedType, false, userId);
+        }
+        return null;
+    }
+
     @Override
     public List<ResolveInfo> queryIntentActivities(Intent intent,
             String resolvedType, int flags, int userId) {
@@ -3190,7 +3423,38 @@
         synchronized (mPackages) {
             final String pkgName = intent.getPackage();
             if (pkgName == null) {
-                return mActivities.queryIntent(intent, resolvedType, flags, userId);
+                List<ResolveInfo> result =
+                        mActivities.queryIntent(intent, resolvedType, flags, userId);
+                // Checking if we can forward the intent to another user
+                List<ForwardingIntentFilter> fifs =
+                        getMatchingForwardingIntentFilters(intent, resolvedType, userId);
+                if (fifs != null) {
+                    ForwardingIntentFilter forwardingIntentFilterWithResult = null;
+                    HashSet<Integer> alreadyTriedUserIds = new HashSet<Integer>();
+                    for (ForwardingIntentFilter fif : fifs) {
+                        int userIdDest = fif.getUserIdDest();
+                        // Two {@link ForwardingIntentFilter}s can have the same userIdDest and
+                        // match the same an intent. For performance reasons, it is better not to
+                        // run queryIntent twice for the same userId
+                        if (!alreadyTriedUserIds.contains(userIdDest)) {
+                            List<ResolveInfo> resultUser = mActivities.queryIntent(intent,
+                                    resolvedType, flags, userIdDest);
+                            if (resultUser != null) {
+                                forwardingIntentFilterWithResult = fif;
+                                // As soon as there is a match in another user, we add the
+                                // intentForwarderActivity to the list of ResolveInfo.
+                                break;
+                            }
+                            alreadyTriedUserIds.add(userIdDest);
+                        }
+                    }
+                    if (forwardingIntentFilterWithResult != null) {
+                        ResolveInfo forwardingResolveInfo = createForwardingResolveInfo(
+                                forwardingIntentFilterWithResult, userId);
+                        result.add(forwardingResolveInfo);
+                    }
+                }
+                return result;
             }
             final PackageParser.Package pkg = mPackages.get(pkgName);
             if (pkg != null) {
@@ -3201,6 +3465,28 @@
         }
     }
 
+    private ResolveInfo createForwardingResolveInfo(ForwardingIntentFilter fif, int userIdFrom) {
+        String className;
+        int userIdDest = fif.getUserIdDest();
+        if (userIdDest == UserHandle.USER_OWNER) {
+            className = FORWARD_INTENT_TO_USER_OWNER;
+        } else {
+            className = FORWARD_INTENT_TO_MANAGED_PROFILE;
+        }
+        ComponentName forwardingActivityComponentName = new ComponentName(
+                mAndroidApplication.packageName, className);
+        ActivityInfo forwardingActivityInfo = getActivityInfo(forwardingActivityComponentName, 0,
+                userIdFrom);
+        ResolveInfo forwardingResolveInfo = new ResolveInfo();
+        forwardingResolveInfo.activityInfo = forwardingActivityInfo;
+        forwardingResolveInfo.priority = 0;
+        forwardingResolveInfo.preferredOrder = 0;
+        forwardingResolveInfo.match = 0;
+        forwardingResolveInfo.isDefault = true;
+        forwardingResolveInfo.filter = fif;
+        return forwardingResolveInfo;
+    }
+
     @Override
     public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
             Intent[] specifics, String[] specificTypes, Intent intent,
@@ -3715,6 +4001,7 @@
         }
     }
 
+    @Override
     public List<ProviderInfo> queryContentProviders(String processName,
             int uid, int flags) {
         ArrayList<ProviderInfo> finalList = null;
@@ -3752,6 +4039,7 @@
         return finalList;
     }
 
+    @Override
     public InstrumentationInfo getInstrumentationInfo(ComponentName name,
             int flags) {
         // reader
@@ -3761,6 +4049,7 @@
         }
     }
 
+    @Override
     public List<InstrumentationInfo> queryInstrumentation(String targetPackage,
             int flags) {
         ArrayList<InstrumentationInfo> finalList =
@@ -4207,21 +4496,60 @@
         }
 
         if (pkgs != null) {
+            // Filter out packages that aren't recently used.
+            //
+            // The exception is first boot of a non-eng device, which
+            // should do a full dexopt.
+            boolean eng = "eng".equals(SystemProperties.get("ro.build.type"));
+            if (eng || !isFirstBoot()) {
+                // TODO: add a property to control this?
+                long dexOptLRUThresholdInMinutes;
+                if (eng) {
+                    dexOptLRUThresholdInMinutes = 30; // only last 30 minutes of apps for eng builds.
+                } else {
+                    dexOptLRUThresholdInMinutes = 7 * 24 * 60; // apps used in the 7 days for users.
+                }
+                long dexOptLRUThresholdInMills = dexOptLRUThresholdInMinutes * 60 * 1000;
+
+                int total = pkgs.size();
+                int skipped = 0;
+                long now = System.currentTimeMillis();
+                for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) {
+                    PackageParser.Package pkg = i.next();
+                    long then = pkg.mLastPackageUsageTimeInMills;
+                    if (then + dexOptLRUThresholdInMills < now) {
+                        if (DEBUG_DEXOPT) {
+                            Log.i(TAG, "Skipping dexopt of " + pkg.packageName + " last resumed: " +
+                                  ((then == 0) ? "never" : new Date(then)));
+                        }
+                        i.remove();
+                        skipped++;
+                    }
+                }
+                if (DEBUG_DEXOPT) {
+                    Log.i(TAG, "Skipped optimizing " + skipped + " of " + total);
+                }
+            }
+
             int i = 0;
             for (PackageParser.Package pkg : pkgs) {
+                i++;
+                if (DEBUG_DEXOPT) {
+                    Log.i(TAG, "Optimizing app " + i + " of " + pkgs.size()
+                          + ": " + pkg.packageName);
+                }
                 if (!isFirstBoot()) {
-                    i++;
                     try {
                         ActivityManagerNative.getDefault().showBootMessage(
                                 mContext.getResources().getString(
-                                        com.android.internal.R.string.android_upgrading_apk,
+                                        R.string.android_upgrading_apk,
                                         i, pkgs.size()), true);
                     } catch (RemoteException e) {
                     }
                 }
                 PackageParser.Package p = pkg;
                 synchronized (mInstallLock) {
-                    if (!p.mDidDexOpt) {
+                    if (p.mDexOptNeeded) {
                         performDexOptLI(p, false /* force dex */, false /* defer */,
                                 true /* include dependencies */);
                     }
@@ -4233,25 +4561,57 @@
     @Override
     public boolean performDexOpt(String packageName) {
         enforceSystemOrRoot("Only the system can request dexopt be performed");
-        if (!mNoDexOpt) {
-            return false;
-        }
+        return performDexOpt(packageName, true);
+    }
+
+    public boolean performDexOpt(String packageName, boolean updateUsage) {
 
         PackageParser.Package p;
         synchronized (mPackages) {
             p = mPackages.get(packageName);
-            if (p == null || p.mDidDexOpt) {
+            if (p == null) {
+                return false;
+            }
+            if (updateUsage) {
+                p.mLastPackageUsageTimeInMills = System.currentTimeMillis();
+            }
+            mPackageUsage.write(false);
+            if (!p.mDexOptNeeded) {
                 return false;
             }
         }
+
         synchronized (mInstallLock) {
             return performDexOptLI(p, false /* force dex */, false /* defer */,
                     true /* include dependencies */) == DEX_OPT_PERFORMED;
         }
     }
 
-    private void performDexOptLibsLI(ArrayList<String> libs, String instructionSet, boolean forceDex,
-            boolean defer, HashSet<String> done) {
+    public HashSet<String> getPackagesThatNeedDexOpt() {
+        HashSet<String> pkgs = null;
+        synchronized (mPackages) {
+            for (PackageParser.Package p : mPackages.values()) {
+                if (DEBUG_DEXOPT) {
+                    Log.i(TAG, p.packageName + " mDexOptNeeded=" + p.mDexOptNeeded);
+                }
+                if (!p.mDexOptNeeded) {
+                    continue;
+                }
+                if (pkgs == null) {
+                    pkgs = new HashSet<String>();
+                }
+                pkgs.add(p.packageName);
+            }
+        }
+        return pkgs;
+    }
+
+    public void shutdown() {
+        mPackageUsage.write(true);
+    }
+
+    private void performDexOptLibsLI(ArrayList<String> libs, String instructionSet,
+             boolean forceDex, boolean defer, HashSet<String> done) {
         for (int i=0; i<libs.size(); i++) {
             PackageParser.Package libPkg;
             String libName;
@@ -4276,8 +4636,7 @@
     static final int DEX_OPT_FAILED = -1;
 
     private int performDexOptLI(PackageParser.Package pkg, String instructionSetOverride,
-            boolean forceDex,
-            boolean defer, HashSet<String> done) {
+            boolean forceDex, boolean defer, HashSet<String> done) {
         final String instructionSet = instructionSetOverride != null ?
                 instructionSetOverride : getAppInstructionSet(pkg.applicationInfo);
 
@@ -4294,47 +4653,52 @@
         boolean performed = false;
         if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
             String path = pkg.mScanPath;
-            int ret = 0;
             try {
-                if (forceDex || dalvik.system.DexFile.isDexOptNeededInternal(path,
-                        pkg.packageName, instructionSet, defer)) {
-                    if (!forceDex && defer) {
-                        if (mDeferredDexOpt == null) {
-                            mDeferredDexOpt = new HashSet<PackageParser.Package>();
-                        }
-                        mDeferredDexOpt.add(pkg);
-                        return DEX_OPT_DEFERRED;
-                    } else {
-                        Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName +
-                                " (instructionSet=" + instructionSet + ")");
-
-                        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
-                        ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
+                boolean isDexOptNeededInternal = DexFile.isDexOptNeededInternal(path,
+                                                                                pkg.packageName,
+                                                                                instructionSet,
+                                                                                defer);
+                // There are three basic cases here:
+                // 1.) we need to dexopt, either because we are forced or it is needed
+                // 2.) we are defering a needed dexopt
+                // 3.) we are skipping an unneeded dexopt
+                if (forceDex || (!defer && isDexOptNeededInternal)) {
+                    Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName);
+                    final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+                    int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
                                                 pkg.packageName, instructionSet);
-                        pkg.mDidDexOpt = true;
-                        performed = true;
+                    // Note that we ran dexopt, since rerunning will
+                    // probably just result in an error again.
+                    pkg.mDexOptNeeded = false;
+                    if (ret < 0) {
+                        return DEX_OPT_FAILED;
                     }
+                    return DEX_OPT_PERFORMED;
                 }
+                if (defer && isDexOptNeededInternal) {
+                    if (mDeferredDexOpt == null) {
+                        mDeferredDexOpt = new HashSet<PackageParser.Package>();
+                    }
+                    mDeferredDexOpt.add(pkg);
+                    return DEX_OPT_DEFERRED;
+                }
+                pkg.mDexOptNeeded = false;
+                return DEX_OPT_SKIPPED;
             } catch (FileNotFoundException e) {
                 Slog.w(TAG, "Apk not found for dexopt: " + path);
-                ret = -1;
+                return DEX_OPT_FAILED;
             } catch (IOException e) {
                 Slog.w(TAG, "IOException reading apk: " + path, e);
-                ret = -1;
-            } catch (dalvik.system.StaleDexCacheError e) {
+                return DEX_OPT_FAILED;
+            } catch (StaleDexCacheError e) {
                 Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
-                ret = -1;
+                return DEX_OPT_FAILED;
             } catch (Exception e) {
                 Slog.w(TAG, "Exception when doing dexopt : ", e);
-                ret = -1;
-            }
-            if (ret < 0) {
-                //error from installer
                 return DEX_OPT_FAILED;
             }
         }
-
-        return performed ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
+        return DEX_OPT_SKIPPED;
     }
 
     private String getAppInstructionSet(ApplicationInfo info) {
@@ -4623,7 +4987,7 @@
                     mResolveActivity.processName = "system:ui";
                     mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
                     mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
-                    mResolveActivity.theme = com.android.internal.R.style.Theme_Holo_Dialog_Alert;
+                    mResolveActivity.theme = R.style.Theme_Holo_Dialog_Alert;
                     mResolveActivity.exported = true;
                     mResolveActivity.enabled = true;
                     mResolveInfo.activityInfo = mResolveActivity;
@@ -6982,6 +7346,7 @@
         return mMediaMounted || Environment.isExternalStorageEmulated();
     }
 
+    @Override
     public PackageCleanItem nextPackageToClean(PackageCleanItem lastPackage) {
         // writer
         synchronized (mPackages) {
@@ -7167,6 +7532,7 @@
     }
 
     /* Called when a downloaded package installation has been confirmed by the user */
+    @Override
     public void installPackage(
             final Uri packageURI, final IPackageInstallObserver observer, final int flags,
             final String installerPackageName) {
@@ -7184,6 +7550,7 @@
                 installerPackageName, verificationParams, encryptionParams);
     }
 
+    @Override
     public void installPackageWithVerificationAndEncryption(Uri packageURI,
             IPackageInstallObserver observer, int flags, String installerPackageName,
             VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
@@ -7388,6 +7755,16 @@
         }
     }
 
+    void installStage(String basePackageName, File stageDir, IPackageInstallObserver2 observer,
+            int flags) {
+        // TODO: install stage!
+        try {
+            observer.packageInstalled(basePackageName, null,
+                    PackageManager.INSTALL_FAILED_INTERNAL_ERROR);
+        } catch (RemoteException ignored) {
+        }
+    }
+
     /**
      * @hide
      */
@@ -7397,11 +7774,7 @@
                 null);
         PackageSetting pkgSetting;
         final int uid = Binder.getCallingUid();
-        if (UserHandle.getUserId(uid) != userId) {
-            mContext.enforceCallingPermission(
-                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
-                    "installExistingPackage for user " + userId);
-        }
+        enforceCrossUserPermission(uid, userId, true, "installExistingPackage for user " + userId);
         if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
             return PackageManager.INSTALL_FAILED_USER_RESTRICTED;
         }
@@ -7435,7 +7808,7 @@
         return PackageManager.INSTALL_SUCCEEDED;
     }
 
-    private boolean isUserRestricted(int userId, String restrictionKey) {
+    boolean isUserRestricted(int userId, String restrictionKey) {
         Bundle restrictions = sUserManager.getUserRestrictions(userId);
         if (restrictions.getBoolean(restrictionKey, false)) {
             Log.w(TAG, "User is restricted: " + restrictionKey);
@@ -7597,6 +7970,7 @@
         }
     }
 
+    @Override
     public void finishPackageInstall(int token) {
         enforceSystemOrRoot("Only the system is allowed to finish installs");
 
@@ -7668,6 +8042,7 @@
                 -1);
     }
 
+    @Override
     public void setInstallerPackageName(String targetPackage, String installerPackageName) {
         final int uid = Binder.getCallingUid();
         // writer
@@ -9623,22 +9998,22 @@
 
     // Utility method used to move dex files during install.
     private int moveDexFilesLI(PackageParser.Package newPackage) {
-        int retCode;
         if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
-            retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath,
-                    getAppInstructionSet(newPackage.applicationInfo));
+            final String instructionSet = getAppInstructionSet(newPackage.applicationInfo);
+            int retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath,
+                                             instructionSet);
             if (retCode != 0) {
-                if (mNoDexOpt) {
-                    /*
-                     * If we're in an engineering build, programs are lazily run
-                     * through dexopt. If the .dex file doesn't exist yet, it
-                     * will be created when the program is run next.
-                     */
-                    Slog.i(TAG, "dex file doesn't exist, skipping move: " + newPackage.mPath);
-                } else {
-                    Slog.e(TAG, "Couldn't rename dex file: " + newPackage.mPath);
-                    return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-                }
+                /*
+                 * Programs may be lazily run through dexopt, so the
+                 * source may not exist. However, something seems to
+                 * have gone wrong, so note that dexopt needs to be
+                 * run again and remove the source file. In addition,
+                 * remove the target to make sure there isn't a stale
+                 * file from a previous version of the package.
+                 */
+                newPackage.mDexOptNeeded = true;
+                mInstaller.rmdex(newPackage.mScanPath, instructionSet);
+                mInstaller.rmdex(newPackage.mPath, instructionSet);
             }
         }
         return PackageManager.INSTALL_SUCCEEDED;
@@ -10602,6 +10977,7 @@
         }
     }
 
+    @Override
     public void deleteApplicationCacheFiles(final String packageName,
             final IPackageDataObserver observer) {
         mContext.enforceCallingOrSelfPermission(
@@ -10654,6 +11030,7 @@
         return true;
     }
 
+    @Override
     public void getPackageSizeInfo(final String packageName, int userHandle,
             final IPackageStatsObserver observer) {
         mContext.enforceCallingOrSelfPermission(
@@ -10733,14 +11110,17 @@
     }
 
 
+    @Override
     public void addPackageToPreferred(String packageName) {
         Slog.w(TAG, "addPackageToPreferred: this is now a no-op");
     }
 
+    @Override
     public void removePackageFromPreferred(String packageName) {
         Slog.w(TAG, "removePackageFromPreferred: this is now a no-op");
     }
 
+    @Override
     public List<PackageInfo> getPreferredPackages(int flags) {
         return new ArrayList<PackageInfo>();
     }
@@ -10768,6 +11148,7 @@
         return Build.VERSION_CODES.CUR_DEVELOPMENT;
     }
 
+    @Override
     public void addPreferredActivity(IntentFilter filter, int match,
             ComponentName[] set, ComponentName activity, int userId) {
         addPreferredActivityInternal(filter, match, set, activity, true, userId);
@@ -10804,6 +11185,7 @@
         }
     }
 
+    @Override
     public void replacePreferredActivity(IntentFilter filter, int match,
             ComponentName[] set, ComponentName activity) {
         if (filter.countActions() != 1) {
@@ -10860,6 +11242,7 @@
         }
     }
 
+    @Override
     public void clearPackagePreferredActivities(String packageName) {
         final int uid = Binder.getCallingUid();
         // writer
@@ -10923,6 +11306,7 @@
         return changed;
     }
 
+    @Override
     public void resetPreferredActivities(int userId) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
@@ -10936,6 +11320,7 @@
         }
     }
 
+    @Override
     public int getPreferredActivities(List<IntentFilter> outFilters,
             List<ComponentName> outActivities, String packageName) {
 
@@ -11031,6 +11416,37 @@
     }
 
     @Override
+    public void addForwardingIntentFilter(IntentFilter filter, boolean removable, int userIdOrig,
+            int userIdDest) {
+        mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+        if (filter.countActions() == 0) {
+            Slog.w(TAG, "Cannot set a forwarding intent filter with no filter actions");
+            return;
+        }
+        synchronized (mPackages) {
+            mSettings.editForwardingIntentResolverLPw(userIdOrig).addFilter(
+                    new ForwardingIntentFilter(filter, removable, userIdDest));
+            mSettings.writePackageRestrictionsLPr(userIdOrig);
+        }
+    }
+
+    @Override
+    public void clearForwardingIntentFilters(int userIdOrig) {
+        mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+        synchronized (mPackages) {
+            ForwardingIntentResolver fir = mSettings.editForwardingIntentResolverLPw(userIdOrig);
+            HashSet<ForwardingIntentFilter> set =
+                    new HashSet<ForwardingIntentFilter>(fir.filterSet());
+            for (ForwardingIntentFilter fif : set) {
+                if (fif.isRemovable()) fir.removeFilter(fif);
+            }
+            mSettings.writePackageRestrictionsLPr(userIdOrig);
+        }
+    }
+
+    @Override
     public ComponentName getHomeActivities(List<ResolveInfo> allHomeCandidates) {
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.addCategory(Intent.CATEGORY_HOME);
@@ -11212,6 +11628,7 @@
                 new int[] {UserHandle.getUserId(packageUid)});
     }
 
+    @Override
     public void setPackageStoppedState(String packageName, boolean stopped, int userId) {
         if (!sUserManager.exists(userId)) return;
         final int uid = Binder.getCallingUid();
@@ -11228,6 +11645,7 @@
         }
     }
 
+    @Override
     public String getInstallerPackageName(String packageName) {
         // reader
         synchronized (mPackages) {
@@ -11257,6 +11675,7 @@
         }
     }
 
+    @Override
     public void enterSafeMode() {
         enforceSystemOrRoot("Only the system can request entering safe mode");
 
@@ -11265,6 +11684,7 @@
         }
     }
 
+    @Override
     public void systemReady() {
         mSystemReady = true;
 
@@ -11310,10 +11730,12 @@
         sUserManager.systemReady();
     }
 
+    @Override
     public boolean isSafeMode() {
         return mSafeMode;
     }
 
+    @Override
     public boolean hasSystemUidErrors() {
         return mHasSystemUidErrors;
     }
@@ -11811,6 +12233,7 @@
     /*
      * Update media status on PackageManager.
      */
+    @Override
     public void updateExternalMediaStatus(final boolean mediaStatus, final boolean reportStatus) {
         int callingUid = Binder.getCallingUid();
         if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
@@ -12405,6 +12828,7 @@
         });
     }
 
+    @Override
     public boolean setInstallLocation(int loc) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
                 null);
@@ -12420,6 +12844,7 @@
         return false;
    }
 
+    @Override
     public int getInstallLocation() {
         return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
                 android.provider.Settings.Global.DEFAULT_INSTALL_LOCATION,
@@ -12506,4 +12931,9 @@
             Binder.restoreCallingIdentity(token);
         }
     }
+
+    @Override
+    public IPackageInstaller getPackageInstaller() {
+        return mInstallerService;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 678fc92..599d2a7 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -131,6 +131,8 @@
     private static final String TAG_PACKAGE = "pkg";
     private static final String TAG_PERSISTENT_PREFERRED_ACTIVITIES =
             "persistent-preferred-activities";
+    static final String TAG_FORWARDING_INTENT_FILTERS =
+            "forwarding-intent-filters";
 
     private static final String ATTR_NAME = "name";
     private static final String ATTR_USER = "user";
@@ -185,6 +187,10 @@
     final SparseArray<PersistentPreferredIntentResolver> mPersistentPreferredActivities =
             new SparseArray<PersistentPreferredIntentResolver>();
 
+    // For every user, it is used to find to which other users the intent can be forwarded.
+    final SparseArray<ForwardingIntentResolver> mForwardingIntentResolvers =
+            new SparseArray<ForwardingIntentResolver>();
+
     final HashMap<String, SharedUserSetting> mSharedUsers =
             new HashMap<String, SharedUserSetting>();
     private final ArrayList<Object> mUserIds = new ArrayList<Object>();
@@ -837,6 +843,15 @@
         return ppir;
     }
 
+    ForwardingIntentResolver editForwardingIntentResolverLPw(int userId) {
+        ForwardingIntentResolver fir = mForwardingIntentResolvers.get(userId);
+        if (fir == null) {
+            fir = new ForwardingIntentResolver();
+            mForwardingIntentResolvers.put(userId, fir);
+        }
+        return fir;
+    }
+
     private File getUserPackagesStateFile(int userId) {
         return new File(Environment.getUserSystemDirectory(userId), "package-restrictions.xml");
     }
@@ -952,6 +967,28 @@
         }
     }
 
+    private void readForwardingIntentFiltersLPw(XmlPullParser parser, int userId)
+            throws XmlPullParserException, IOException {
+        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(TAG_ITEM)) {
+                ForwardingIntentFilter fif = new ForwardingIntentFilter(parser);
+                editForwardingIntentResolverLPw(userId).addFilter(fif);
+            } else {
+                String msg = "Unknown element under " +  TAG_FORWARDING_INTENT_FILTERS + ": " +
+                        parser.getName();
+                PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+                XmlUtils.skipCurrentTag(parser);
+            }
+        }
+    }
+
     void readPackageRestrictionsLPr(int userId) {
         if (DEBUG_MU) {
             Log.i(TAG, "Reading package restrictions for user=" + userId);
@@ -1080,6 +1117,8 @@
                     readPreferredActivitiesLPw(parser, userId);
                 } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
                     readPersistentPreferredActivitiesLPw(parser, userId);
+                } else if (tagName.equals(TAG_FORWARDING_INTENT_FILTERS)) {
+                    readForwardingIntentFiltersLPw(parser, userId);
                 } else {
                     Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
                           + parser.getName());
@@ -1157,6 +1196,20 @@
         serializer.endTag(null, TAG_PERSISTENT_PREFERRED_ACTIVITIES);
     }
 
+    void writeForwardingIntentFiltersLPr(XmlSerializer serializer, int userId)
+            throws IllegalArgumentException, IllegalStateException, IOException {
+        serializer.startTag(null, TAG_FORWARDING_INTENT_FILTERS);
+        ForwardingIntentResolver fir = mForwardingIntentResolvers.get(userId);
+        if (fir != null) {
+            for (final ForwardingIntentFilter fif : fir.filterSet()) {
+                serializer.startTag(null, TAG_ITEM);
+                fif.writeToXml(serializer);
+                serializer.endTag(null, TAG_ITEM);
+            }
+        }
+        serializer.endTag(null, TAG_FORWARDING_INTENT_FILTERS);
+    }
+
     void writePackageRestrictionsLPr(int userId) {
         if (DEBUG_MU) {
             Log.i(TAG, "Writing package restrictions for user=" + userId);
@@ -1255,6 +1308,8 @@
 
             writePersistentPreferredActivitiesLPr(serializer, userId);
 
+            writeForwardingIntentFiltersLPr(serializer, userId);
+
             serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
 
             serializer.endDocument();
@@ -1872,6 +1927,10 @@
                     // TODO: check whether this is okay! as it is very
                     // similar to how preferred-activities are treated
                     readPersistentPreferredActivitiesLPw(parser, 0);
+                } else if (tagName.equals(TAG_FORWARDING_INTENT_FILTERS)) {
+                    // TODO: check whether this is okay! as it is very
+                    // similar to how preferred-activities are treated
+                    readForwardingIntentFiltersLPw(parser, 0);
                 } else if (tagName.equals("updated-package")) {
                     readDisabledSysPackageLPw(parser);
                 } else if (tagName.equals("cleaning-package")) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index f8103de..60212bf 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -23,7 +23,6 @@
 import android.app.ActivityManagerNative;
 import android.app.ActivityThread;
 import android.app.IStopUserCallback;
-import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -274,16 +273,6 @@
 
     /** Assume permissions already checked and caller's identity cleared */
     private List<UserInfo> getProfilesLocked(int userId, boolean enabledOnly) {
-        // Getting the service here is not good for testing purposes.
-        // However, this service is not available when UserManagerService starts
-        // up so we need a lazy load.
-
-        DevicePolicyManager dpm = null;
-        if (enabledOnly) {
-            dpm = (DevicePolicyManager)
-                    mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        }
-
         UserInfo user = getUserInfoLocked(userId);
         ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
         for (int i = 0; i < mUsers.size(); i++) {
@@ -291,29 +280,28 @@
             if (!isProfileOf(user, profile)) {
                 continue;
             }
-
-            if (enabledOnly && profile.isManagedProfile()) {
-                if (dpm != null) {
-                    if (!dpm.isProfileEnabled(profile.id)) {
-                        continue;
-                    }
-                } else {
-                    Log.w(LOG_TAG,
-                            "Attempting to reach DevicePolicyManager before it is started");
-                    // TODO: There might be system apps that need to call this.
-                    // Make sure that DevicePolicyManagerService is ready at that
-                    // time (otherwise, any default value is a bad one).
-                    throw new IllegalArgumentException(String.format(
-                            "Attempting to get enabled profiles for %d before "
-                                    + "DevicePolicyManagerService has been started.",
-                            userId));
-                }
+            if (enabledOnly && !profile.isEnabled()) {
+                continue;
             }
             users.add(profile);
         }
         return users;
     }
 
+    @Override
+    public UserInfo getProfileParent(int userHandle) {
+        checkManageUsersPermission("get the profile parent");
+        synchronized (mPackagesLock) {
+            UserInfo profile = getUserInfoLocked(userHandle);
+            int parentUserId = profile.profileGroupId;
+            if (parentUserId == UserInfo.NO_PROFILE_GROUP_ID) {
+                return null;
+            } else {
+                return getUserInfoLocked(parentUserId);
+            }
+        }
+    }
+
     private boolean isProfileOf(UserInfo user, UserInfo profile) {
         return user.id == profile.id ||
                 (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
@@ -321,6 +309,18 @@
     }
 
     @Override
+    public void setUserEnabled(int userId) {
+        checkManageUsersPermission("enable user");
+        synchronized (mPackagesLock) {
+            UserInfo info = getUserInfoLocked(userId);
+            if (info != null && !info.isEnabled()) {
+                info.flags ^= UserInfo.FLAG_DISABLED;
+                writeUserLocked(info);
+            }
+        }
+    }
+
+    @Override
     public UserInfo getUserInfo(int userId) {
         checkManageUsersPermission("query user");
         synchronized (mPackagesLock) {
@@ -748,6 +748,18 @@
                 writeBoolean(serializer, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER);
                 writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_CREDENTIALS);
                 writeBoolean(serializer, restrictions, UserManager.DISALLOW_REMOVE_USER);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_DEBUGGING_FEATURES);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_VPN);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_TETHERING);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_FACTORY_RESET);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_ADD_USER);
+                writeBoolean(serializer, restrictions, UserManager.ENSURE_VERIFY_APPS);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_CELL_BROADCASTS);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_APPS);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_UNMUTE_MICROPHONE);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_ADJUST_VOLUME);
                 serializer.endTag(null, TAG_RESTRICTIONS);
             }
             serializer.endTag(null, TAG_USER);
@@ -887,6 +899,19 @@
                         readBoolean(parser, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER);
                         readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_CREDENTIALS);
                         readBoolean(parser, restrictions, UserManager.DISALLOW_REMOVE_USER);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_DEBUGGING_FEATURES);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_VPN);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_TETHERING);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_FACTORY_RESET);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_ADD_USER);
+                        readBoolean(parser, restrictions, UserManager.ENSURE_VERIFY_APPS);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_CELL_BROADCASTS);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_APPS);
+                        readBoolean(parser, restrictions,
+                                UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_UNMUTE_MICROPHONE);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_ADJUST_VOLUME);
                     }
                 }
             }
@@ -1011,17 +1036,6 @@
         }
     }
 
-    private int getNextProfileGroupIdLocked() {
-        int maxGroupId = UserInfo.NO_PROFILE_GROUP_ID;
-        for (int i = 0; i < mUsers.size(); i++) {
-            UserInfo ui = mUsers.valueAt(i);
-            if (maxGroupId < ui.profileGroupId) {
-                maxGroupId = ui.profileGroupId;
-            }
-        }
-        return maxGroupId + 1;
-    }
-
     @Override
     public UserInfo createProfileForUser(String name, int flags, int userId) {
         checkManageUsersPermission("Only the system can create users");
@@ -1038,16 +1052,16 @@
         return createUserInternal(name, flags, UserHandle.USER_NULL);
     }
 
-    private UserInfo createUserInternal(String name, int flags, int profileId) {
+    private UserInfo createUserInternal(String name, int flags, int parentId) {
         final long ident = Binder.clearCallingIdentity();
         UserInfo userInfo = null;
         try {
             synchronized (mInstallLock) {
                 synchronized (mPackagesLock) {
-                    UserInfo profile = null;
-                    if (profileId != UserHandle.USER_NULL) {
-                        profile = getUserInfoLocked(profileId);
-                        if (profile == null) return null;
+                    UserInfo parent = null;
+                    if (parentId != UserHandle.USER_NULL) {
+                        parent = getUserInfoLocked(parentId);
+                        if (parent == null) return null;
                     }
                     if (isUserLimitReachedLocked()) return null;
                     int userId = getNextAvailableIdLocked();
@@ -1060,12 +1074,12 @@
                     Environment.getUserSystemDirectory(userInfo.id).mkdirs();
                     mUsers.put(userId, userInfo);
                     writeUserListLocked();
-                    if (profile != null) {
-                        if (profile.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
-                            profile.profileGroupId = getNextProfileGroupIdLocked();
-                            writeUserLocked(profile);
+                    if (parent != null) {
+                        if (parent.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
+                            parent.profileGroupId = parent.id;
+                            writeUserLocked(parent);
                         }
-                        userInfo.profileGroupId = profile.profileGroupId;
+                        userInfo.profileGroupId = parent.profileGroupId;
                     }
                     writeUserLocked(userInfo);
                     mPm.createNewUserLILPw(userId, userPath);
@@ -1106,6 +1120,9 @@
             // on next startup, in case the runtime stops now before stopping and
             // removing the user completely.
             user.partial = true;
+            // Mark it as disabled, so that it isn't returned any more when
+            // profiles are queried.
+            user.flags |= UserInfo.FLAG_DISABLED;
             writeUserLocked(user);
         }
         if (DBG) Slog.i(LOG_TAG, "Stopping user " + userHandle);
@@ -1134,6 +1151,7 @@
         // wiping the user's system directory and removing from the user list
         long ident = Binder.clearCallingIdentity();
         try {
+            final boolean isManaged = getUserInfo(userHandle).isManagedProfile();
             Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
             addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
             mContext.sendOrderedBroadcastAsUser(addedIntent, UserHandle.ALL,
@@ -1154,6 +1172,11 @@
                                             removeUserStateLocked(userHandle);
                                         }
                                     }
+                                    // Send broadcast to notify system that the user removed was a
+                                    // managed user.
+                                    if (isManaged) {
+                                        sendProfileRemovedBroadcast(userHandle);
+                                    }
                                 }
                             }.start();
                         }
@@ -1205,6 +1228,13 @@
         parent.delete();
     }
 
+    private void sendProfileRemovedBroadcast(int userHandle) {
+        Intent managedProfileIntent = new Intent(Intent.ACTION_MANAGED_PROFILE_REMOVED);
+        managedProfileIntent.putExtra(Intent.EXTRA_USER, new UserHandle(userHandle));
+        // Note: This makes an assumption that the parent owner is user 0.
+        mContext.sendBroadcastAsUser(managedProfileIntent, UserHandle.OWNER, null);
+    }
+
     @Override
     public Bundle getApplicationRestrictions(String packageName) {
         return getApplicationRestrictionsForUser(packageName, UserHandle.getCallingUserId());
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index d84e8e1..2d6cc7c 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -132,6 +132,11 @@
         mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
         mScreenOffIntent.addFlags(
                 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
+
+        // Initialize interactive state for battery stats.
+        try {
+            mBatteryStats.noteInteractive(true);
+        } catch (RemoteException ex) { }
     }
 
     /**
@@ -259,7 +264,14 @@
                 // Going to sleep...
                 mLastGoToSleepReason = reason;
             }
-            mInputManagerInternal.setInteractive(interactive);
+        }
+
+        mInputManagerInternal.setInteractive(interactive);
+
+        if (interactive) {
+            try {
+                mBatteryStats.noteInteractive(true);
+            } catch (RemoteException ex) { }
         }
     }
 
@@ -289,6 +301,12 @@
                 }
             }
         }
+
+        if (!interactive) {
+            try {
+                mBatteryStats.noteInteractive(false);
+            } catch (RemoteException ex) { }
+        }
     }
 
     /**
@@ -409,7 +427,7 @@
 
         EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
 
-        mPolicy.screenTurningOn(mScreenOnListener);
+        mPolicy.wakingUp(mScreenOnListener);
         mActivityManagerInternal.wakingUp();
 
         if (ActivityManagerNative.isSystemReady()) {
@@ -460,7 +478,7 @@
 
         EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);
 
-        mPolicy.screenTurnedOff(why);
+        mPolicy.goingToSleep(why);
         mActivityManagerInternal.goingToSleep();
 
         if (ActivityManagerNative.isSystemReady()) {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index cfe24fe..03941c6 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -168,9 +168,9 @@
     // Poll interval in milliseconds for watching boot animation finished.
     private static final int BOOT_ANIMATION_POLL_INTERVAL = 200;
 
-    //powerHint
+    // Used to send the hint to the PowerHAL indicating transitions
+    // from and to the low power mode.
     private static final int POWER_HINT_LOW_POWER_MODE = 5;
-    private static boolean mLowPowerModeEnabled;
 
     private final Context mContext;
     private LightsManager mLightsManager;
@@ -399,6 +399,9 @@
     // Time when we last logged a warning about calling userActivity() without permission.
     private long mLastWarningAboutUserActivityPermission = Long.MIN_VALUE;
 
+    // If true, the device is in low power mode.
+    private static boolean mLowPowerModeEnabled;
+
     private native void nativeInit();
 
     private static native void nativeAcquireSuspendBlocker(String name);
@@ -496,6 +499,7 @@
 
             filter = new IntentFilter();
             filter.addAction(Intent.ACTION_BOOT_COMPLETED);
+            filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
             mContext.registerReceiver(new BootCompletedReceiver(), filter, null, mHandler);
 
             filter = new IntentFilter();
@@ -534,6 +538,9 @@
             resolver.registerContentObserver(Settings.System.getUriFor(
                     Settings.System.SCREEN_BRIGHTNESS_MODE),
                     false, mSettingsObserver, UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.System.getUriFor(
+                    Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ),
+                    false, mSettingsObserver, UserHandle.USER_ALL);
             resolver.registerContentObserver(Settings.Global.getUriFor(
                     Settings.Global.LOW_POWER_MODE),
                     false, mSettingsObserver, UserHandle.USER_ALL);
@@ -616,12 +623,11 @@
                 Settings.System.SCREEN_BRIGHTNESS_MODE,
                 Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT);
 
-        boolean mIsEnabled = Settings.Global.getInt(resolver,
-            Settings.Global.LOW_POWER_MODE, 0) != 0;
-        if (mIsEnabled != mLowPowerModeEnabled) {
-            BinderService bs = new BinderService();
-            bs.powerHint(POWER_HINT_LOW_POWER_MODE, mIsEnabled ? 1 : 0);
-            mLowPowerModeEnabled = mIsEnabled;
+        boolean lowPowerModeEnabled = Settings.Global.getInt(resolver,
+                Settings.Global.LOW_POWER_MODE, 0) != 0;
+        if (lowPowerModeEnabled != mLowPowerModeEnabled) {
+            powerHintInternal(POWER_HINT_LOW_POWER_MODE, lowPowerModeEnabled ? 1 : 0);
+            mLowPowerModeEnabled = lowPowerModeEnabled;
         }
 
         mDirty |= DIRTY_SETTINGS;
@@ -1633,6 +1639,8 @@
 
             mDisplayPowerRequest.blockScreenOn = mScreenOnBlocker.isHeld();
 
+            mDisplayPowerRequest.lowPowerMode = mLowPowerModeEnabled;
+
             mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
                     mRequestWaitForNegativeProximity);
             mRequestWaitForNegativeProximity = false;
@@ -2017,6 +2025,10 @@
         }
     }
 
+    private void powerHintInternal(int hintId, int data) {
+        nativeSendPowerHint(hintId, data);
+    }
+
     /**
      * Low-level function turn the device off immediately, without trying
      * to be clean.  Most people should use {@link ShutdownThread} for a clean shutdown.
@@ -2526,7 +2538,7 @@
         @Override // Binder call
         public void powerHint(int hintId, int data) {
             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-            nativeSendPowerHint(hintId, data);
+            powerHintInternal(hintId, data);
         }
 
         @Override // Binder call
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 8fed79f..956e3e6 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -45,6 +45,7 @@
 import android.os.storage.IMountShutdownObserver;
 
 import com.android.internal.telephony.ITelephony;
+import com.android.server.pm.PackageManagerService;
 
 import android.util.Log;
 import android.view.WindowManager;
@@ -329,6 +330,14 @@
             }
         }
 
+        Log.i(TAG, "Shutting down package manager...");
+
+        final PackageManagerService pm = (PackageManagerService)
+            ServiceManager.getService("package");
+        if (pm != null) {
+            pm.shutdown();
+        }
+
         // Shutdown radios.
         shutdownRadios(MAX_RADIO_WAIT_TIME);
 
diff --git a/services/core/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java
index 486477a..5deb2b8 100644
--- a/services/core/java/com/android/server/search/SearchManagerService.java
+++ b/services/core/java/com/android/server/search/SearchManagerService.java
@@ -70,8 +70,9 @@
      */
     public SearchManagerService(Context context)  {
         mContext = context;
-        mContext.registerReceiver(new BootCompletedReceiver(),
-                new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+        IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
+        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+        mContext.registerReceiver(new BootCompletedReceiver(), filter);
         mContext.registerReceiver(new UserReceiver(),
                 new IntentFilter(Intent.ACTION_USER_REMOVED));
         new MyPackageMonitor().register(context, null, UserHandle.ALL, true);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 91f796b..738ad32 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -74,6 +74,7 @@
     private boolean mMenuVisible = false;
     private int mImeWindowVis = 0;
     private int mImeBackDisposition;
+    private boolean mShowImeSwitcher;
     private IBinder mImeToken = null;
     private int mCurrentUserId;
 
@@ -346,7 +347,8 @@
     }
 
     @Override
-    public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition) {
+    public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition,
+            final boolean showImeSwitcher) {
         enforceStatusBar();
 
         if (SPEW) {
@@ -360,11 +362,12 @@
             mImeWindowVis = vis;
             mImeBackDisposition = backDisposition;
             mImeToken = token;
+            mShowImeSwitcher = showImeSwitcher;
             mHandler.post(new Runnable() {
                 public void run() {
                     if (mBar != null) {
                         try {
-                            mBar.setImeWindowStatus(token, vis, backDisposition);
+                            mBar.setImeWindowStatus(token, vis, backDisposition, showImeSwitcher);
                         } catch (RemoteException ex) {
                         }
                     }
@@ -512,6 +515,7 @@
             switches[2] = mMenuVisible ? 1 : 0;
             switches[3] = mImeWindowVis;
             switches[4] = mImeBackDisposition;
+            switches[7] = mShowImeSwitcher ? 1 : 0;
             binders.add(mImeToken);
         }
         switches[5] = mWindowManager.isHardKeyboardAvailable() ? 1 : 0;
@@ -546,13 +550,13 @@
     }
 
     @Override
-    public void onNotificationClick(String pkg, String tag, int id, int userId) {
+    public void onNotificationClick(String key) {
         enforceStatusBarService();
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
         long identity = Binder.clearCallingIdentity();
         try {
-            mNotificationDelegate.onNotificationClick(callingUid, callingPid, pkg, tag, id, userId);
+            mNotificationDelegate.onNotificationClick(callingUid, callingPid, key);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/services/core/java/com/android/server/task/StateChangedListener.java b/services/core/java/com/android/server/task/StateChangedListener.java
new file mode 100644
index 0000000..a87bf95
--- /dev/null
+++ b/services/core/java/com/android/server/task/StateChangedListener.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.task;
+
+import com.android.server.task.controllers.TaskStatus;
+
+/**
+ * Interface through which a {@link StateController} informs the
+ * {@link com.android.server.task.TaskManagerService} that there are some tasks potentially ready
+ * to be run.
+ */
+public interface StateChangedListener {
+    /**
+     * Called by the controller to notify the TaskManager that it should check on the state of a
+     * task.
+     * @param taskStatus The state of the task which has changed.
+     */
+    public void onTaskStateChanged(TaskStatus taskStatus);
+
+    /**
+     * Called by the controller to notify the TaskManager that regardless of the state of the task,
+     * it must be run immediately.
+     * @param taskStatus The state of the task which is to be run immediately.
+     */
+    public void onTaskDeadlineExpired(TaskStatus taskStatus);
+}
diff --git a/services/core/java/com/android/server/task/TaskList.java b/services/core/java/com/android/server/task/TaskList.java
new file mode 100644
index 0000000..d2b8440
--- /dev/null
+++ b/services/core/java/com/android/server/task/TaskList.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.task;
+
+import android.content.ComponentName;
+import android.content.Task;
+
+import com.android.server.task.controllers.TaskStatus;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Maintain a list of classes, and accessor methods/logic for these tasks.
+ * This class offers the following functionality:
+ *     - When a task is added, it will determine if the task requirements have changed (update) and
+ *       whether the controllers need to be updated.
+ *     - Persists Tasks, figures out when to to rewrite the Task to disk.
+ *     - Is threadsafe.
+ *     - Handles rescheduling of tasks.
+ *       - When a periodic task is executed and must be re-added.
+ *       - When a task fails and the client requests that it be retried with backoff.
+ */
+public class TaskList {
+
+    final List<TaskStatus> mTasks;
+
+    TaskList() {
+        mTasks = intialiseTaskMapFromDisk();
+    }
+
+    /**
+     * Add a task to the master list, persisting it if necessary.
+     * @param task Task to add.
+     * @param persistable true if the TaskQueue should persist this task to the disk.
+     * @return true if this operation was successful. If false, this task was neither added nor
+     * persisted.
+     */
+    // TODO: implement this when i decide whether i want to key by TaskStatus
+    public boolean add(Task task, boolean persistable) {
+        return true;
+    }
+
+    /**
+     * Remove the provided task. Will also delete the task if it was persisted. Note that this
+     * function does not return the validity of the operation, as we assume a delete will always
+     * succeed.
+     * @param task Task to remove.
+     */
+    public void remove(Task task) {
+
+    }
+
+    /**
+     *
+     * @return
+     */
+    // TODO: Implement this.
+    private List<TaskStatus> intialiseTaskMapFromDisk() {
+        return new ArrayList<TaskStatus>();
+    }
+}
diff --git a/services/core/java/com/android/server/task/TaskManagerService.java b/services/core/java/com/android/server/task/TaskManagerService.java
new file mode 100644
index 0000000..5df4b2a
--- /dev/null
+++ b/services/core/java/com/android/server/task/TaskManagerService.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.task;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.SparseArray;
+
+import com.android.server.task.controllers.TaskStatus;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Responsible for taking tasks representing work to be performed by a client app, and determining
+ * based on the criteria specified when that task should be run against the client application's
+ * endpoint.
+ * @hide
+ */
+public class TaskManagerService extends com.android.server.SystemService
+        implements StateChangedListener {
+
+    /** Master list of tasks. */
+    private final TaskList mTaskList;
+
+    /**
+     * Track Services that have currently active or pending tasks. The index is provided by
+     * {@link TaskStatus#getServiceToken()}
+     */
+    private final SparseArray<TaskServiceContext> mPendingTaskServices =
+            new SparseArray<TaskServiceContext>();
+
+    private final TaskHandler mHandler;
+
+    private class TaskHandler extends Handler {
+        /** Check the pending queue and start any tasks. */
+        static final int MSG_RUN_PENDING = 0;
+        /** Initiate the stop task flow. */
+        static final int MSG_STOP_TASK = 1;
+
+        public TaskHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message message) {
+            switch (message.what) {
+                case MSG_RUN_PENDING:
+
+                    break;
+                case MSG_STOP_TASK:
+
+                    break;
+            }
+        }
+
+        /**
+         * Helper to post a message to this handler that will run through the pending queue and
+         * start any tasks it can.
+         */
+        void sendRunPendingTasksMessage() {
+            Message m = Message.obtain(this, MSG_RUN_PENDING);
+            m.sendToTarget();
+        }
+
+        void sendOnStopMessage(TaskStatus taskStatus) {
+
+        }
+    }
+
+    /**
+     * Initializes the system service.
+     * <p>
+     * Subclasses must define a single argument constructor that accepts the context
+     * and passes it to super.
+     * </p>
+     *
+     * @param context The system server context.
+     */
+    public TaskManagerService(Context context) {
+        super(context);
+        mTaskList = new TaskList();
+        mHandler = new TaskHandler(context.getMainLooper());
+    }
+
+    @Override
+    public void onStart() {
+
+    }
+
+    /**
+     * Offboard work to our handler thread as quickly as possible, b/c this call is probably being
+     * made on the main thread.
+     * @param taskStatus The state of the task which has changed.
+     */
+    @Override
+    public void onTaskStateChanged(TaskStatus taskStatus) {
+        if (taskStatus.isReady()) {
+
+        } else {
+            if (mPendingTaskServices.get(taskStatus.getServiceToken()) != null) {
+                // The task is either pending or being executed, which we have to cancel.
+            }
+        }
+
+    }
+
+    @Override
+    public void onTaskDeadlineExpired(TaskStatus taskStatus) {
+
+    }
+}
diff --git a/services/core/java/com/android/server/task/TaskServiceContext.java b/services/core/java/com/android/server/task/TaskServiceContext.java
new file mode 100644
index 0000000..65c6fa5
--- /dev/null
+++ b/services/core/java/com/android/server/task/TaskServiceContext.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.task;
+
+import android.app.task.ITaskCallback;
+import android.app.task.ITaskService;
+import android.content.ComponentName;
+import android.content.ServiceConnection;
+import android.content.Task;
+import android.os.IBinder;
+
+import com.android.server.task.controllers.TaskStatus;
+
+/**
+ * Maintains information required to bind to a {@link android.app.task.TaskService}. This binding
+ * can then be reused to start concurrent tasks on the TaskService. Information here is unique
+ * within this service.
+ * Functionality provided by this class:
+ *     - Managages wakelock for the service.
+ *     - Sends onStartTask() and onStopTask() messages to client app, and handles callbacks.
+ *     -
+ */
+public class TaskServiceContext extends ITaskCallback.Stub implements ServiceConnection {
+
+    final ComponentName component;
+    int uid;
+    ITaskService service;
+
+    /** Whether this service is actively bound. */
+    boolean mBound;
+
+    TaskServiceContext(Task task) {
+        this.component = task.getService();
+    }
+
+    public void stopTask() {
+
+    }
+
+    public void startTask(Task task) {
+
+    }
+
+    @Override
+    public void taskFinished(int taskId, boolean reschedule) {
+
+    }
+
+    @Override
+    public void acknowledgeStopMessage(int taskId) {
+
+    }
+
+    @Override
+    public void acknowledgeStartMessage(int taskId) {
+
+    }
+
+    /**
+     * @return true if this task is pending or active within this context.
+     */
+    public boolean hasTaskPending(TaskStatus taskStatus) {
+        return true;
+    }
+
+    public boolean isBound() {
+        return mBound;
+    }
+
+    @Override
+    public void onServiceConnected(ComponentName name, IBinder service) {
+
+        mBound = true;
+    }
+
+    @Override
+    public void onServiceDisconnected(ComponentName name) {
+        mBound = false;
+    }
+}
diff --git a/services/core/java/com/android/server/task/controllers/ConnectivityController.java b/services/core/java/com/android/server/task/controllers/ConnectivityController.java
new file mode 100644
index 0000000..5cca77c
--- /dev/null
+++ b/services/core/java/com/android/server/task/controllers/ConnectivityController.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.task.controllers;
+
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.UserHandle;
+import android.util.Log;
+
+import com.android.server.task.TaskManagerService;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ *
+ */
+public class ConnectivityController extends StateController {
+    private static final String TAG = "TaskManager.Connectivity";
+
+    private final List<TaskStatus> mTrackedTasks = new LinkedList<TaskStatus>();
+    private final BroadcastReceiver mConnectivityChangedReceiver =
+            new ConnectivityChangedReceiver();
+
+    public ConnectivityController(TaskManagerService service) {
+        super(service);
+        // Register connectivity changed BR.
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+        mContext.registerReceiverAsUser(
+                mConnectivityChangedReceiver, UserHandle.ALL, intentFilter, null, null);
+    }
+
+    @Override
+    public void maybeTrackTaskState(TaskStatus taskStatus) {
+        if (taskStatus.hasConnectivityConstraint() || taskStatus.hasMeteredConstraint()) {
+            mTrackedTasks.add(taskStatus);
+        }
+    }
+
+    @Override
+    public void removeTaskStateIfTracked(TaskStatus taskStatus) {
+        mTrackedTasks.remove(taskStatus);
+    }
+
+    /**
+     * @param isConnected Whether the active network is connected for the given uid
+     * @param isMetered Whether the active network is metered for the given uid. This is
+     *                  necessarily false if <code>isConnected</code> is false.
+     * @param userId Id of the user for whom we are updating the connectivity state.
+     */
+    private void updateTrackedTasks(boolean isConnected, boolean isMetered, int userId) {
+        for (TaskStatus ts : mTrackedTasks) {
+            if (ts.userId != userId) {
+                continue;
+            }
+            boolean prevIsConnected = ts.connectivityConstraintSatisfied.getAndSet(isConnected);
+            boolean prevIsMetered = ts.meteredConstraintSatisfied.getAndSet(isMetered);
+            if (prevIsConnected != isConnected || prevIsMetered != isMetered) {
+                    mStateChangedListener.onTaskStateChanged(ts);
+            }
+        }
+    }
+
+    class ConnectivityChangedReceiver extends BroadcastReceiver {
+        /**
+         * We'll receive connectivity changes for each user here, which we'll process independently.
+         * We are only interested in the active network here. We're only interested in the active
+         * network, b/c the end result of this will be for apps to try to hit the network.
+         * @param context The Context in which the receiver is running.
+         * @param intent The Intent being received.
+         */
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+                final int networkType =
+                        intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE,
+                                ConnectivityManager.TYPE_NONE);
+                // Connectivity manager for THIS context - important!
+                final ConnectivityManager connManager = (ConnectivityManager)
+                        context.getSystemService(Context.CONNECTIVITY_SERVICE);
+                final NetworkInfo activeNetwork = connManager.getActiveNetworkInfo();
+                // This broadcast gets sent a lot, only update if the active network has changed.
+                if (activeNetwork.getType() == networkType) {
+                    final int userid = context.getUserId();
+                    boolean isMetered = false;
+                    boolean isConnected =
+                            !intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
+                    if (isConnected) {  // No point making the call if we know there's no conn.
+                        isMetered = connManager.isActiveNetworkMetered();
+                    }
+                    updateTrackedTasks(isConnected, isMetered, userid);
+                }
+            } else {
+                Log.w(TAG, "Unrecognised action in intent: " + action);
+            }
+        }
+    };
+}
diff --git a/services/core/java/com/android/server/task/controllers/StateController.java b/services/core/java/com/android/server/task/controllers/StateController.java
new file mode 100644
index 0000000..e1cd662
--- /dev/null
+++ b/services/core/java/com/android/server/task/controllers/StateController.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.task.controllers;
+
+import android.content.Context;
+
+import com.android.server.task.StateChangedListener;
+import com.android.server.task.TaskManagerService;
+
+/**
+ * Incorporates shared controller logic between the various controllers of the TaskManager.
+ * These are solely responsible for tracking a list of tasks, and notifying the TM when these
+ * are ready to run, or whether they must be stopped.
+ */
+public abstract class StateController {
+
+    protected Context mContext;
+    protected StateChangedListener mStateChangedListener;
+
+    public StateController(TaskManagerService service) {
+        mStateChangedListener = service;
+        mContext = service.getContext();
+    }
+
+    /**
+     * Implement the logic here to decide whether a task should be tracked by this controller.
+     * This logic is put here so the TaskManger can be completely agnostic of Controller logic.
+     * Also called when updating a task, so implementing controllers have to be aware of
+     * preexisting tasks.
+     */
+    public abstract void maybeTrackTaskState(TaskStatus taskStatus);
+    /**
+     * Remove task - this will happen if the task is cancelled, completed, etc.
+     */
+    public abstract void removeTaskStateIfTracked(TaskStatus taskStatus);
+
+}
diff --git a/services/core/java/com/android/server/task/controllers/TaskStatus.java b/services/core/java/com/android/server/task/controllers/TaskStatus.java
new file mode 100644
index 0000000..230b049
--- /dev/null
+++ b/services/core/java/com/android/server/task/controllers/TaskStatus.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.task.controllers;
+
+import android.content.ComponentName;
+import android.content.Task;
+import android.os.SystemClock;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Uniquely identifies a task internally.
+ * Created from the public {@link android.content.Task} object when it lands on the scheduler.
+ * Contains current state of the requirements of the task, as well as a function to evaluate
+ * whether it's ready to run.
+ * This object is shared among the various controllers - hence why the different fields are atomic.
+ * This isn't strictly necessary because each controller is only interested in a specific field,
+ * and the receivers that are listening for global state change will all run on the main looper,
+ * but we don't enforce that so this is safer.
+ * @hide
+ */
+public class TaskStatus {
+    final int taskId;
+    final int userId;
+    ComponentName component;
+
+    final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean();
+    final AtomicBoolean timeConstraintSatisfied = new AtomicBoolean();
+    final AtomicBoolean idleConstraintSatisfied = new AtomicBoolean();
+    final AtomicBoolean meteredConstraintSatisfied = new AtomicBoolean();
+    final AtomicBoolean connectivityConstraintSatisfied = new AtomicBoolean();
+
+    private final boolean hasChargingConstraint;
+    private final boolean hasTimingConstraint;
+    private final boolean hasIdleConstraint;
+    private final boolean hasMeteredConstraint;
+    private final boolean hasConnectivityConstraint;
+
+    private long earliestRunTimeElapsedMillis;
+    private long latestRunTimeElapsedMillis;
+
+    /** Provide a unique handle to the service that this task will be run on. */
+    public int getServiceToken() {
+        return component.hashCode() + userId;
+    }
+
+    /** Generate a TaskStatus object for a given task and uid. */
+    // TODO: reimplement this to reuse these objects instead of creating a new one each time?
+    static TaskStatus getForTaskAndUid(Task task, int uId) {
+        return new TaskStatus(task, uId);
+    }
+
+    /** Set up the state of a newly scheduled task. */
+    TaskStatus(Task task, int userId) {
+        this.taskId = task.getTaskId();
+        this.userId = userId;
+        this.component = task.getService();
+
+        hasChargingConstraint = task.isRequireCharging();
+        hasIdleConstraint = task.isRequireDeviceIdle();
+
+        // Timing constraints
+        if (task.isPeriodic()) {
+            long elapsedNow = SystemClock.elapsedRealtime();
+            earliestRunTimeElapsedMillis = elapsedNow;
+            latestRunTimeElapsedMillis = elapsedNow + task.getIntervalMillis();
+            hasTimingConstraint = true;
+        } else if (task.getMinLatencyMillis() != 0L || task.getMaxExecutionDelayMillis() != 0L) {
+            earliestRunTimeElapsedMillis = task.getMinLatencyMillis() > 0L ?
+                    task.getMinLatencyMillis() : Long.MAX_VALUE;
+            latestRunTimeElapsedMillis = task.getMaxExecutionDelayMillis() > 0L ?
+                    task.getMaxExecutionDelayMillis() : Long.MAX_VALUE;
+            hasTimingConstraint = true;
+        } else {
+            hasTimingConstraint = false;
+        }
+
+        // Networking constraints
+        hasMeteredConstraint = task.getNetworkCapabilities() == Task.NetworkType.UNMETERED;
+        hasConnectivityConstraint = task.getNetworkCapabilities() == Task.NetworkType.ANY;
+    }
+
+    boolean hasConnectivityConstraint() {
+        return hasConnectivityConstraint;
+    }
+
+    boolean hasMeteredConstraint() {
+        return hasMeteredConstraint;
+    }
+
+    boolean hasChargingConstraint() {
+        return hasChargingConstraint;
+    }
+
+    boolean hasTimingConstraint() {
+        return hasTimingConstraint;
+    }
+
+    boolean hasIdleConstraint() {
+        return hasIdleConstraint;
+    }
+
+    long getEarliestRunTime() {
+        return earliestRunTimeElapsedMillis;
+    }
+
+    long getLatestRunTime() {
+        return latestRunTimeElapsedMillis;
+    }
+
+    /**
+     * @return whether this task is ready to run, based on its requirements.
+     */
+    public synchronized boolean isReady() {
+        return (!hasChargingConstraint || chargingConstraintSatisfied.get())
+                && (!hasTimingConstraint || timeConstraintSatisfied.get())
+                && (!hasConnectivityConstraint || connectivityConstraintSatisfied.get())
+                && (!hasMeteredConstraint || meteredConstraintSatisfied.get())
+                && (!hasIdleConstraint || idleConstraintSatisfied.get());
+    }
+
+    @Override
+    public int hashCode() {
+        int result = component.hashCode();
+        result = 31 * result + taskId;
+        result = 31 * result + userId;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof TaskStatus)) return false;
+
+        TaskStatus that = (TaskStatus) o;
+        return ((taskId == that.taskId)
+                && (userId == that.userId)
+                && (component.equals(that.component)));
+    }
+}
diff --git a/services/core/java/com/android/server/task/controllers/TimeController.java b/services/core/java/com/android/server/task/controllers/TimeController.java
new file mode 100644
index 0000000..6d97a53
--- /dev/null
+++ b/services/core/java/com/android/server/task/controllers/TimeController.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.task.controllers;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.SystemClock;
+import android.util.Log;
+
+import com.android.server.task.TaskManagerService;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * This class sets an alarm for the next expiring task, and determines whether a task's minimum
+ * delay has been satisfied.
+ */
+public class TimeController extends StateController {
+    private static final String TAG = "TaskManager.Time";
+    private static final String ACTION_TASK_EXPIRED =
+            "android.content.taskmanager.TASK_EXPIRED";
+    private static final String ACTION_TASK_DELAY_EXPIRED =
+            "android.content.taskmanager.TASK_DELAY_EXPIRED";
+
+    /** Set an alarm for the next task expiry. */
+    private final PendingIntent mTaskExpiredAlarmIntent;
+    /** Set an alarm for the next task delay expiry. This*/
+    private final PendingIntent mNextDelayExpiredAlarmIntent;
+
+    private long mNextTaskExpiredElapsedMillis;
+    private long mNextDelayExpiredElapsedMillis;
+
+    private AlarmManager mAlarmService = null;
+    /** List of tracked tasks, sorted asc. by deadline */
+    private final List<TaskStatus> mTrackedTasks = new LinkedList<TaskStatus>();
+
+    public TimeController(TaskManagerService service) {
+        super(service);
+        mTaskExpiredAlarmIntent =
+                PendingIntent.getBroadcast(mContext, 0 /* ignored */,
+                        new Intent(ACTION_TASK_EXPIRED), 0);
+        mNextDelayExpiredAlarmIntent =
+                PendingIntent.getBroadcast(mContext, 0 /* ignored */,
+                        new Intent(ACTION_TASK_DELAY_EXPIRED), 0);
+
+        // Register BR for these intents.
+        IntentFilter intentFilter = new IntentFilter(ACTION_TASK_EXPIRED);
+        intentFilter.addAction(ACTION_TASK_DELAY_EXPIRED);
+        mContext.registerReceiver(mAlarmExpiredReceiver, intentFilter);
+    }
+
+    /**
+     * Check if the task has a timing constraint, and if so determine where to insert it in our
+     * list.
+     */
+    @Override
+    public synchronized void maybeTrackTaskState(TaskStatus task) {
+        if (task.hasTimingConstraint()) {
+            ListIterator<TaskStatus> it = mTrackedTasks.listIterator(mTrackedTasks.size());
+            while (it.hasPrevious()) {
+                TaskStatus ts = it.previous();
+                if (ts.equals(task)) {
+                    // Update
+                    it.remove();
+                    it.add(task);
+                    break;
+                } else if (ts.getLatestRunTime() < task.getLatestRunTime()) {
+                    // Insert
+                    it.add(task);
+                    break;
+                }
+            }
+            maybeUpdateAlarms(task.getEarliestRunTime(), task.getLatestRunTime());
+        }
+    }
+
+    /**
+     * If the task passed in is being tracked, figure out if we need to update our alarms, and if
+     * so, update them.
+     */
+    @Override
+    public synchronized void removeTaskStateIfTracked(TaskStatus taskStatus) {
+        if (mTrackedTasks.remove(taskStatus)) {
+            if (mNextDelayExpiredElapsedMillis <= taskStatus.getEarliestRunTime()) {
+                handleTaskDelayExpired();
+            }
+            if (mNextTaskExpiredElapsedMillis <= taskStatus.getLatestRunTime()) {
+                handleTaskDeadlineExpired();
+            }
+        }
+    }
+
+    /**
+     * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a task's
+     * delay will expire.
+     * This alarm <b>will not</b> wake up the phone.
+     */
+    private void setDelayExpiredAlarm(long alarmTimeElapsedMillis) {
+        ensureAlarmService();
+        mAlarmService.set(AlarmManager.ELAPSED_REALTIME, alarmTimeElapsedMillis,
+                mNextDelayExpiredAlarmIntent);
+    }
+
+    /**
+     * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a task's
+     * deadline will expire.
+     * This alarm <b>will</b> wake up the phone.
+     */
+    private void setDeadlineExpiredAlarm(long alarmTimeElapsedMillis) {
+        ensureAlarmService();
+        mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTimeElapsedMillis,
+                mTaskExpiredAlarmIntent);
+    }
+
+    /**
+     * Determines whether this controller can stop tracking the given task.
+     * The controller is no longer interested in a task once its time constraint is satisfied, and
+     * the task's deadline is fulfilled - unlike other controllers a time constraint can't toggle
+     * back and forth.
+     */
+    private boolean canStopTrackingTask(TaskStatus taskStatus) {
+        final long elapsedNowMillis = SystemClock.elapsedRealtime();
+        return taskStatus.timeConstraintSatisfied.get() &&
+                (taskStatus.getLatestRunTime() == Long.MAX_VALUE ||
+                        taskStatus.getLatestRunTime() < elapsedNowMillis);
+    }
+
+    private void maybeUpdateAlarms(long delayExpiredElapsed, long deadlineExpiredElapsed) {
+        if (delayExpiredElapsed < mNextDelayExpiredElapsedMillis) {
+            mNextDelayExpiredElapsedMillis = delayExpiredElapsed;
+            setDelayExpiredAlarm(mNextDelayExpiredElapsedMillis);
+        }
+        if (deadlineExpiredElapsed < mNextTaskExpiredElapsedMillis) {
+            mNextTaskExpiredElapsedMillis = deadlineExpiredElapsed;
+            setDeadlineExpiredAlarm(mNextTaskExpiredElapsedMillis);
+        }
+    }
+
+    private void ensureAlarmService() {
+        if (mAlarmService == null) {
+            mAlarmService = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+        }
+    }
+
+    /**
+     * Handles alarm that notifies that a task has expired. When this function is called at least
+     * one task must be run.
+     */
+    private synchronized void handleTaskDeadlineExpired() {
+        long nextExpiryTime = Long.MAX_VALUE;
+        final long nowElapsedMillis = SystemClock.elapsedRealtime();
+
+        Iterator<TaskStatus> it = mTrackedTasks.iterator();
+        while (it.hasNext()) {
+            TaskStatus ts = it.next();
+            final long taskDeadline = ts.getLatestRunTime();
+
+            if (taskDeadline <= nowElapsedMillis) {
+                ts.timeConstraintSatisfied.set(true);
+                mStateChangedListener.onTaskDeadlineExpired(ts);
+                it.remove();
+            } else {  // Sorted by expiry time, so take the next one and stop.
+                nextExpiryTime = taskDeadline;
+                break;
+            }
+        }
+        maybeUpdateAlarms(Long.MAX_VALUE, nextExpiryTime);
+    }
+
+    /**
+     * Handles alarm that notifies us that a task's delay has expired. Iterates through the list of
+     * tracked tasks and marks them as ready as appropriate.
+     */
+    private synchronized void handleTaskDelayExpired() {
+        final long nowElapsedMillis = SystemClock.elapsedRealtime();
+        long nextDelayTime = Long.MAX_VALUE;
+
+        Iterator<TaskStatus> it = mTrackedTasks.iterator();
+        while (it.hasNext()) {
+            final TaskStatus ts = it.next();
+            final long taskDelayTime = ts.getEarliestRunTime();
+            if (taskDelayTime < nowElapsedMillis) {
+                ts.timeConstraintSatisfied.set(true);
+                mStateChangedListener.onTaskStateChanged(ts);
+                if (canStopTrackingTask(ts)) {
+                    it.remove();
+                }
+            } else {  // Keep going through list to get next delay time.
+                if (nextDelayTime > taskDelayTime) {
+                    nextDelayTime = taskDelayTime;
+                }
+            }
+        }
+        maybeUpdateAlarms(nextDelayTime, Long.MAX_VALUE);
+    }
+
+    private final BroadcastReceiver mAlarmExpiredReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // An task has just expired, so we run through the list of tasks that we have and
+            // notify our StateChangedListener.
+            if (ACTION_TASK_EXPIRED.equals(intent.getAction())) {
+                handleTaskDeadlineExpired();
+            } else if (ACTION_TASK_DELAY_EXPIRED.equals(intent.getAction())) {
+                handleTaskDelayExpired();
+            }
+        }
+    };
+}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 97aa4f57..9061f96 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -192,7 +192,7 @@
                 trustMayHaveChanged = true;
             }
             info.agent.unbind();
-            mObsoleteAgents.remove(info);
+            mActiveAgents.remove(info);
         }
 
         if (trustMayHaveChanged) {
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 50dd27d..8ad7fff 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -134,7 +134,7 @@
 
     private void buildTvInputListLocked(int userId) {
         UserState userState = getUserStateLocked(userId);
-        userState.inputList.clear();
+        userState.inputMap.clear();
 
         if (DEBUG) Slog.d(TAG, "buildTvInputList");
         PackageManager pm = mContext.getPackageManager();
@@ -149,7 +149,7 @@
             }
             TvInputInfo info = new TvInputInfo(ri);
             if (DEBUG) Slog.d(TAG, "add " + info.getId());
-            userState.inputList.add(info);
+            userState.inputMap.put(info.getId(), info);
         }
     }
 
@@ -179,9 +179,9 @@
             }
             // Release created sessions.
             for (SessionState state : userState.sessionStateMap.values()) {
-                if (state.session != null) {
+                if (state.mSession != null) {
                     try {
-                        state.session.release();
+                        state.mSession.release();
                     } catch (RemoteException e) {
                         Slog.e(TAG, "error in release", e);
                     }
@@ -191,15 +191,15 @@
 
             // Unregister all callbacks and unbind all services.
             for (ServiceState serviceState : userState.serviceStateMap.values()) {
-                if (serviceState.callback != null) {
+                if (serviceState.mCallback != null) {
                     try {
-                        serviceState.service.unregisterCallback(serviceState.callback);
+                        serviceState.mService.unregisterCallback(serviceState.mCallback);
                     } catch (RemoteException e) {
                         Slog.e(TAG, "error in unregisterCallback", e);
                     }
                 }
-                serviceState.clients.clear();
-                mContext.unbindService(serviceState.connection);
+                serviceState.mClients.clear();
+                mContext.unbindService(serviceState.mConnection);
             }
             userState.serviceStateMap.clear();
 
@@ -215,28 +215,33 @@
         return userState;
     }
 
-    private ServiceState getServiceStateLocked(ComponentName name, int userId) {
+    private ServiceState getServiceStateLocked(String inputId, int userId) {
         UserState userState = getUserStateLocked(userId);
-        ServiceState serviceState = userState.serviceStateMap.get(name);
+        ServiceState serviceState = userState.serviceStateMap.get(inputId);
         if (serviceState == null) {
-            throw new IllegalStateException("Service state not found for " + name + " (userId="
+            throw new IllegalStateException("Service state not found for " + inputId + " (userId="
                     + userId + ")");
         }
         return serviceState;
     }
 
-    private ITvInputSession getSessionLocked(IBinder sessionToken, int callingUid, int userId) {
+    private SessionState getSessionStateLocked(IBinder sessionToken, int callingUid, int userId) {
         UserState userState = getUserStateLocked(userId);
         SessionState sessionState = userState.sessionStateMap.get(sessionToken);
         if (sessionState == null) {
             throw new IllegalArgumentException("Session state not found for token " + sessionToken);
         }
         // Only the application that requested this session or the system can access it.
-        if (callingUid != Process.SYSTEM_UID && callingUid != sessionState.callingUid) {
+        if (callingUid != Process.SYSTEM_UID && callingUid != sessionState.mCallingUid) {
             throw new SecurityException("Illegal access to the session with token " + sessionToken
                     + " from uid " + callingUid);
         }
-        ITvInputSession session = sessionState.session;
+        return sessionState;
+    }
+
+    private ITvInputSession getSessionLocked(IBinder sessionToken, int callingUid, int userId) {
+        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
+        ITvInputSession session = sessionState.mSession;
         if (session == null) {
             throw new IllegalStateException("Session not yet created for token " + sessionToken);
         }
@@ -249,38 +254,47 @@
                 false, methodName, null);
     }
 
-    private void updateServiceConnectionLocked(ComponentName name, int userId) {
+    private void updateServiceConnectionLocked(String inputId, int userId) {
         UserState userState = getUserStateLocked(userId);
-        ServiceState serviceState = userState.serviceStateMap.get(name);
+        ServiceState serviceState = userState.serviceStateMap.get(inputId);
         if (serviceState == null) {
             return;
         }
-        boolean isStateEmpty = serviceState.clients.isEmpty()
-                && serviceState.sessionTokens.isEmpty();
-        if (serviceState.service == null && !isStateEmpty && userId == mCurrentUserId) {
+        if (serviceState.mReconnecting) {
+            if (!serviceState.mSessionTokens.isEmpty()) {
+                // wait until all the sessions are removed.
+                return;
+            }
+            serviceState.mReconnecting = false;
+        }
+        boolean isStateEmpty = serviceState.mClients.isEmpty()
+                && serviceState.mSessionTokens.isEmpty();
+        if (serviceState.mService == null && !isStateEmpty && userId == mCurrentUserId) {
             // This means that the service is not yet connected but its state indicates that we
             // have pending requests. Then, connect the service.
-            if (serviceState.bound) {
+            if (serviceState.mBound) {
                 // We have already bound to the service so we don't try to bind again until after we
                 // unbind later on.
                 return;
             }
             if (DEBUG) {
-                Slog.d(TAG, "bindServiceAsUser(name=" + name.getClassName() + ", userId=" + userId
+                Slog.d(TAG, "bindServiceAsUser(inputId=" + inputId + ", userId=" + userId
                         + ")");
             }
-            Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(name);
-            mContext.bindServiceAsUser(i, serviceState.connection, Context.BIND_AUTO_CREATE,
+
+            Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(
+                    userState.inputMap.get(inputId).getComponent());
+            mContext.bindServiceAsUser(i, serviceState.mConnection, Context.BIND_AUTO_CREATE,
                     new UserHandle(userId));
-            serviceState.bound = true;
-        } else if (serviceState.service != null && isStateEmpty) {
+            serviceState.mBound = true;
+        } else if (serviceState.mService != null && isStateEmpty) {
             // This means that the service is already connected but its state indicates that we have
             // nothing to do with it. Then, disconnect the service.
             if (DEBUG) {
-                Slog.d(TAG, "unbindService(name=" + name.getClassName() + ")");
+                Slog.d(TAG, "unbindService(inputId=" + inputId + ")");
             }
-            mContext.unbindService(serviceState.connection);
-            userState.serviceStateMap.remove(name);
+            mContext.unbindService(serviceState.mConnection);
+            userState.serviceStateMap.remove(inputId);
         }
     }
 
@@ -289,8 +303,7 @@
         final SessionState sessionState =
                 getUserStateLocked(userId).sessionStateMap.get(sessionToken);
         if (DEBUG) {
-            Slog.d(TAG, "createSessionInternalLocked(name=" + sessionState.name.getClassName()
-                    + ")");
+            Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.mInputId + ")");
         }
 
         final InputChannel[] channels = InputChannel.openInputChannelPair(sessionToken.toString());
@@ -300,17 +313,22 @@
             @Override
             public void onSessionCreated(ITvInputSession session) {
                 if (DEBUG) {
-                    Slog.d(TAG, "onSessionCreated(name=" + sessionState.name.getClassName() + ")");
+                    Slog.d(TAG, "onSessionCreated(inputId=" + sessionState.mInputId + ")");
                 }
                 synchronized (mLock) {
-                    sessionState.session = session;
+                    sessionState.mSession = session;
                     if (session == null) {
                         removeSessionStateLocked(sessionToken, userId);
-                        sendSessionTokenToClientLocked(sessionState.client, sessionState.name, null,
-                                null, sessionState.seq, userId);
+                        sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInputId,
+                                null, null, sessionState.mSeq, userId);
                     } else {
-                        sendSessionTokenToClientLocked(sessionState.client, sessionState.name,
-                                sessionToken, channels[0], sessionState.seq, userId);
+                        try {
+                            session.asBinder().linkToDeath(sessionState, 0);
+                        } catch (RemoteException e) {
+                            Slog.e(TAG, "Session is already died.");
+                        }
+                        sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInputId,
+                                sessionToken, channels[0], sessionState.mSeq, userId);
                     }
                     channels[0].dispose();
                 }
@@ -323,24 +341,32 @@
         } catch (RemoteException e) {
             Slog.e(TAG, "error in createSession", e);
             removeSessionStateLocked(sessionToken, userId);
-            sendSessionTokenToClientLocked(sessionState.client, sessionState.name, null, null,
-                    sessionState.seq, userId);
+            sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInputId, null, null,
+                    sessionState.mSeq, userId);
         }
         channels[1].dispose();
     }
 
-    private void sendSessionTokenToClientLocked(ITvInputClient client, ComponentName name,
+    private void sendSessionTokenToClientLocked(ITvInputClient client, String inputId,
             IBinder sessionToken, InputChannel channel, int seq, int userId) {
         try {
-            client.onSessionCreated(name, sessionToken, channel, seq);
+            client.onSessionCreated(inputId, sessionToken, channel, seq);
         } catch (RemoteException exception) {
             Slog.e(TAG, "error in onSessionCreated", exception);
         }
+    }
 
-        if (sessionToken == null) {
-            // This means that the session creation failed. We might want to disconnect the service.
-            updateServiceConnectionLocked(name, userId);
+    private void releaseSessionLocked(IBinder sessionToken, int callingUid, int userId) {
+        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
+        if (sessionState.mSession != null) {
+            try {
+                sessionState.mSession.release();
+            } catch (RemoteException e) {
+                Slog.w(TAG, "session is already disapeared", e);
+            }
+            sessionState.mSession = null;
         }
+        removeSessionStateLocked(sessionToken, userId);
     }
 
     private void removeSessionStateLocked(IBinder sessionToken, int userId) {
@@ -349,19 +375,31 @@
         SessionState sessionState = userState.sessionStateMap.remove(sessionToken);
 
         // Close the open log entry, if any.
-        if (sessionState.logUri != null) {
+        if (sessionState.mLogUri != null) {
             SomeArgs args = SomeArgs.obtain();
-            args.arg1 = sessionState.logUri;
+            args.arg1 = sessionState.mLogUri;
             args.arg2 = System.currentTimeMillis();
             mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args).sendToTarget();
         }
 
         // Also remove the session token from the session token list of the current service.
-        ServiceState serviceState = userState.serviceStateMap.get(sessionState.name);
+        ServiceState serviceState = userState.serviceStateMap.get(sessionState.mInputId);
         if (serviceState != null) {
-            serviceState.sessionTokens.remove(sessionToken);
+            serviceState.mSessionTokens.remove(sessionToken);
         }
-        updateServiceConnectionLocked(sessionState.name, userId);
+        updateServiceConnectionLocked(sessionState.mInputId, userId);
+    }
+
+    private void broadcastServiceAvailabilityChangedLocked(ServiceState serviceState) {
+        for (IBinder iBinder : serviceState.mClients) {
+            ITvInputClient client = ITvInputClient.Stub.asInterface(iBinder);
+            try {
+                client.onAvailabilityChanged(
+                        serviceState.mTvInputInfo.getId(), serviceState.mAvailable);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "error in onAvailabilityChanged", e);
+            }
+        }
     }
 
     private final class BinderService extends ITvInputManager.Stub {
@@ -373,7 +411,7 @@
             try {
                 synchronized (mLock) {
                     UserState userState = getUserStateLocked(resolvedUserId);
-                    return new ArrayList<TvInputInfo>(userState.inputList);
+                    return new ArrayList<TvInputInfo>(userState.inputMap.values());
                 }
             } finally {
                 Binder.restoreCallingIdentity(identity);
@@ -381,7 +419,7 @@
         }
 
         @Override
-        public boolean getAvailability(final ITvInputClient client, final ComponentName name,
+        public boolean getAvailability(final ITvInputClient client, final String inputId,
                 int userId) {
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
                     Binder.getCallingUid(), userId, "getAvailability");
@@ -389,11 +427,11 @@
             try {
                 synchronized (mLock) {
                     UserState userState = getUserStateLocked(resolvedUserId);
-                    ServiceState serviceState = userState.serviceStateMap.get(name);
+                    ServiceState serviceState = userState.serviceStateMap.get(inputId);
                     if (serviceState != null) {
                         // We already know the status of this input service. Return the cached
                         // status.
-                        return serviceState.available;
+                        return serviceState.mAvailable;
                     }
                 }
             } finally {
@@ -403,7 +441,7 @@
         }
 
         @Override
-        public void registerCallback(final ITvInputClient client, final ComponentName name,
+        public void registerCallback(final ITvInputClient client, final String inputId,
                 int userId) {
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
                     Binder.getCallingUid(), userId, "registerCallback");
@@ -413,28 +451,29 @@
                     // Create a new service callback and add it to the callback map of the current
                     // service.
                     UserState userState = getUserStateLocked(resolvedUserId);
-                    ServiceState serviceState = userState.serviceStateMap.get(name);
+                    ServiceState serviceState = userState.serviceStateMap.get(inputId);
                     if (serviceState == null) {
-                        serviceState = new ServiceState(resolvedUserId);
-                        userState.serviceStateMap.put(name, serviceState);
+                        serviceState = new ServiceState(
+                                userState.inputMap.get(inputId), resolvedUserId);
+                        userState.serviceStateMap.put(inputId, serviceState);
                     }
                     IBinder iBinder = client.asBinder();
-                    if (!serviceState.clients.contains(iBinder)) {
-                        serviceState.clients.add(iBinder);
+                    if (!serviceState.mClients.contains(iBinder)) {
+                        serviceState.mClients.add(iBinder);
                     }
-                    if (serviceState.service != null) {
-                        if (serviceState.callback != null) {
+                    if (serviceState.mService != null) {
+                        if (serviceState.mCallback != null) {
                             // We already handled.
                             return;
                         }
-                        serviceState.callback = new ServiceCallback(resolvedUserId);
+                        serviceState.mCallback = new ServiceCallback(resolvedUserId);
                         try {
-                            serviceState.service.registerCallback(serviceState.callback);
+                            serviceState.mService.registerCallback(serviceState.mCallback);
                         } catch (RemoteException e) {
                             Slog.e(TAG, "error in registerCallback", e);
                         }
                     } else {
-                        updateServiceConnectionLocked(name, resolvedUserId);
+                        updateServiceConnectionLocked(inputId, resolvedUserId);
                     }
                 }
             } finally {
@@ -443,34 +482,34 @@
         }
 
         @Override
-        public void unregisterCallback(ITvInputClient client, ComponentName name, int userId) {
+        public void unregisterCallback(ITvInputClient client, String inputId, int userId) {
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
                     Binder.getCallingUid(), userId, "unregisterCallback");
             final long identity = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
                     UserState userState = getUserStateLocked(resolvedUserId);
-                    ServiceState serviceState = userState.serviceStateMap.get(name);
+                    ServiceState serviceState = userState.serviceStateMap.get(inputId);
                     if (serviceState == null) {
                         return;
                     }
 
                     // Remove this client from the client list and unregister the callback.
-                    serviceState.clients.remove(client.asBinder());
-                    if (!serviceState.clients.isEmpty()) {
+                    serviceState.mClients.remove(client.asBinder());
+                    if (!serviceState.mClients.isEmpty()) {
                         // We have other clients who want to keep the callback. Do this later.
                         return;
                     }
-                    if (serviceState.service == null || serviceState.callback == null) {
+                    if (serviceState.mService == null || serviceState.mCallback == null) {
                         return;
                     }
                     try {
-                        serviceState.service.unregisterCallback(serviceState.callback);
+                        serviceState.mService.unregisterCallback(serviceState.mCallback);
                     } catch (RemoteException e) {
                         Slog.e(TAG, "error in unregisterCallback", e);
                     } finally {
-                        serviceState.callback = null;
-                        updateServiceConnectionLocked(name, resolvedUserId);
+                        serviceState.mCallback = null;
+                        updateServiceConnectionLocked(inputId, resolvedUserId);
                     }
                 }
             } finally {
@@ -479,7 +518,7 @@
         }
 
         @Override
-        public void createSession(final ITvInputClient client, final ComponentName name,
+        public void createSession(final ITvInputClient client, final String inputId,
                 int seq, int userId) {
             final int callingUid = Binder.getCallingUid();
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
@@ -487,28 +526,35 @@
             final long identity = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
+                    UserState userState = getUserStateLocked(resolvedUserId);
+                    ServiceState serviceState = userState.serviceStateMap.get(inputId);
+                    if (serviceState == null) {
+                        serviceState = new ServiceState(
+                                userState.inputMap.get(inputId), resolvedUserId);
+                        userState.serviceStateMap.put(inputId, serviceState);
+                    }
+                    // Send a null token immediately while reconnecting.
+                    if (serviceState.mReconnecting == true) {
+                        sendSessionTokenToClientLocked(client, inputId, null, null, seq, userId);
+                        return;
+                    }
+
                     // Create a new session token and a session state.
                     IBinder sessionToken = new Binder();
-                    SessionState sessionState = new SessionState(name, client, seq, callingUid);
-                    sessionState.session = null;
+                    SessionState sessionState = new SessionState(
+                            sessionToken, inputId, client, seq, callingUid, resolvedUserId);
 
                     // Add them to the global session state map of the current user.
-                    UserState userState = getUserStateLocked(resolvedUserId);
                     userState.sessionStateMap.put(sessionToken, sessionState);
 
                     // Also, add them to the session state map of the current service.
-                    ServiceState serviceState = userState.serviceStateMap.get(name);
-                    if (serviceState == null) {
-                        serviceState = new ServiceState(resolvedUserId);
-                        userState.serviceStateMap.put(name, serviceState);
-                    }
-                    serviceState.sessionTokens.add(sessionToken);
+                    serviceState.mSessionTokens.add(sessionToken);
 
-                    if (serviceState.service != null) {
-                        createSessionInternalLocked(serviceState.service, sessionToken,
+                    if (serviceState.mService != null) {
+                        createSessionInternalLocked(serviceState.mService, sessionToken,
                                 resolvedUserId);
                     } else {
-                        updateServiceConnectionLocked(name, resolvedUserId);
+                        updateServiceConnectionLocked(inputId, resolvedUserId);
                     }
                 }
             } finally {
@@ -524,14 +570,7 @@
             final long identity = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
-                    // Release the session.
-                    try {
-                        getSessionLocked(sessionToken, callingUid, resolvedUserId).release();
-                    } catch (RemoteException e) {
-                        Slog.e(TAG, "error in release", e);
-                    }
-
-                    removeSessionStateLocked(sessionToken, resolvedUserId);
+                    releaseSessionLocked(sessionToken, callingUid, resolvedUserId);
                 }
             } finally {
                 Binder.restoreCallingIdentity(identity);
@@ -599,9 +638,9 @@
                         // Close the open log entry first, if any.
                         UserState userState = getUserStateLocked(resolvedUserId);
                         SessionState sessionState = userState.sessionStateMap.get(sessionToken);
-                        if (sessionState.logUri != null) {
+                        if (sessionState.mLogUri != null) {
                             SomeArgs args = SomeArgs.obtain();
-                            args.arg1 = sessionState.logUri;
+                            args.arg1 = sessionState.mLogUri;
                             args.arg2 = currentTime;
                             mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args)
                                     .sendToTarget();
@@ -609,15 +648,15 @@
 
                         // Create a log entry and fill it later.
                         ContentValues values = new ContentValues();
-                        values.put(TvContract.WatchedPrograms.WATCH_START_TIME_UTC_MILLIS,
+                        values.put(TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
                                 currentTime);
-                        values.put(TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS, 0);
-                        values.put(TvContract.WatchedPrograms.CHANNEL_ID, channelId);
+                        values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, 0);
+                        values.put(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID, channelId);
 
-                        sessionState.logUri = mContentResolver.insert(
+                        sessionState.mLogUri = mContentResolver.insert(
                                 TvContract.WatchedPrograms.CONTENT_URI, values);
                         SomeArgs args = SomeArgs.obtain();
-                        args.arg1 = sessionState.logUri;
+                        args.arg1 = sessionState.mLogUri;
                         args.arg2 = ContentUris.parseId(channelUri);
                         args.arg3 = currentTime;
                         mLogHandler.obtainMessage(LogHandler.MSG_OPEN_ENTRY, args).sendToTarget();
@@ -694,12 +733,12 @@
     }
 
     private static final class UserState {
-        // A list of all known TV inputs on the system.
-        private final List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
+        // A mapping from the TV input id to its TvInputInfo.
+        private final Map<String, TvInputInfo> inputMap = new HashMap<String,TvInputInfo>();
 
         // A mapping from the name of a TV input service to its state.
-        private final Map<ComponentName, ServiceState> serviceStateMap =
-                new HashMap<ComponentName, ServiceState>();
+        private final Map<String, ServiceState> serviceStateMap =
+                new HashMap<String, ServiceState>();
 
         // A mapping from the token of a TV input session to its state.
         private final Map<IBinder, SessionState> sessionStateMap =
@@ -707,66 +746,91 @@
     }
 
     private final class ServiceState {
-        private final List<IBinder> clients = new ArrayList<IBinder>();
-        private final List<IBinder> sessionTokens = new ArrayList<IBinder>();
-        private final ServiceConnection connection;
+        // TODO: need to implement DeathRecipient for clients.
+        private final List<IBinder> mClients = new ArrayList<IBinder>();
+        private final List<IBinder> mSessionTokens = new ArrayList<IBinder>();
+        private final ServiceConnection mConnection;
+        private final TvInputInfo mTvInputInfo;
 
-        private ITvInputService service;
-        private ServiceCallback callback;
-        private boolean bound;
-        private boolean available;
+        private ITvInputService mService;
+        private ServiceCallback mCallback;
+        private boolean mBound;
+        private boolean mAvailable;
+        private boolean mReconnecting;
 
-        private ServiceState(int userId) {
-            this.connection = new InputServiceConnection(userId);
+        private ServiceState(TvInputInfo inputInfo, int userId) {
+            mTvInputInfo = inputInfo;
+            mConnection = new InputServiceConnection(inputInfo, userId);
         }
     }
 
-    private static final class SessionState {
-        private final ComponentName name;
-        private final ITvInputClient client;
-        private final int seq;
-        private final int callingUid;
+    private final class SessionState implements IBinder.DeathRecipient {
+        private final String mInputId;
+        private final ITvInputClient mClient;
+        private final int mSeq;
+        private final int mCallingUid;
+        private final int mUserId;
+        private final IBinder mToken;
+        private ITvInputSession mSession;
+        private Uri mLogUri;
 
-        private ITvInputSession session;
-        private Uri logUri;
+        private SessionState(IBinder token, String inputId, ITvInputClient client, int seq,
+                int callingUid, int userId) {
+            mToken = token;
+            mInputId = inputId;
+            mClient = client;
+            mSeq = seq;
+            mCallingUid = callingUid;
+            mUserId = userId;
+        }
 
-        private SessionState(ComponentName name, ITvInputClient client, int seq, int callingUid) {
-            this.name = name;
-            this.client = client;
-            this.seq = seq;
-            this.callingUid = callingUid;
+        @Override
+        public void binderDied() {
+            synchronized (mLock) {
+                mSession = null;
+                if (mClient != null) {
+                    try {
+                        mClient.onSessionReleased(mSeq);
+                    } catch(RemoteException e) {
+                        Slog.e(TAG, "error in onSessionReleased", e);
+                    }
+                }
+                removeSessionStateLocked(mToken, mUserId);
+            }
         }
     }
 
     private final class InputServiceConnection implements ServiceConnection {
+        private final TvInputInfo mTvInputInfo;
         private final int mUserId;
 
-        private InputServiceConnection(int userId) {
+        private InputServiceConnection(TvInputInfo inputInfo, int userId) {
             mUserId = userId;
+            mTvInputInfo = inputInfo;
         }
 
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
             if (DEBUG) {
-                Slog.d(TAG, "onServiceConnected(name=" + name.getClassName() + ")");
+                Slog.d(TAG, "onServiceConnected(inputId=" + mTvInputInfo.getId() + ")");
             }
             synchronized (mLock) {
-                ServiceState serviceState = getServiceStateLocked(name, mUserId);
-                serviceState.service = ITvInputService.Stub.asInterface(service);
+                ServiceState serviceState = getServiceStateLocked(mTvInputInfo.getId(), mUserId);
+                serviceState.mService = ITvInputService.Stub.asInterface(service);
 
                 // Register a callback, if we need to.
-                if (!serviceState.clients.isEmpty() && serviceState.callback == null) {
-                    serviceState.callback = new ServiceCallback(mUserId);
+                if (!serviceState.mClients.isEmpty() && serviceState.mCallback == null) {
+                    serviceState.mCallback = new ServiceCallback(mUserId);
                     try {
-                        serviceState.service.registerCallback(serviceState.callback);
+                        serviceState.mService.registerCallback(serviceState.mCallback);
                     } catch (RemoteException e) {
                         Slog.e(TAG, "error in registerCallback", e);
                     }
                 }
 
                 // And create sessions, if any.
-                for (IBinder sessionToken : serviceState.sessionTokens) {
-                    createSessionInternalLocked(serviceState.service, sessionToken, mUserId);
+                for (IBinder sessionToken : serviceState.mSessionTokens) {
+                    createSessionInternalLocked(serviceState.mService, sessionToken, mUserId);
                 }
             }
         }
@@ -774,7 +838,38 @@
         @Override
         public void onServiceDisconnected(ComponentName name) {
             if (DEBUG) {
-                Slog.d(TAG, "onServiceDisconnected(name=" + name.getClassName() + ")");
+                Slog.d(TAG, "onServiceDisconnected(inputId=" + mTvInputInfo.getId() + ")");
+            }
+            if (!mTvInputInfo.getComponent().equals(name)) {
+                throw new IllegalArgumentException("Mismatched ComponentName: "
+                        + mTvInputInfo.getComponent() + " (expected), " + name + " (actual).");
+            }
+            synchronized (mLock) {
+                UserState userState = getUserStateLocked(mUserId);
+                ServiceState serviceState = userState.serviceStateMap.get(mTvInputInfo.getId());
+                if (serviceState != null) {
+                    serviceState.mReconnecting = true;
+                    serviceState.mBound = false;
+                    serviceState.mService = null;
+                    serviceState.mCallback = null;
+
+                    // Send null tokens for not finishing create session events.
+                    for (IBinder sessionToken : serviceState.mSessionTokens) {
+                        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
+                        if (sessionState.mSession == null) {
+                            removeSessionStateLocked(sessionToken, sessionState.mUserId);
+                            sendSessionTokenToClientLocked(sessionState.mClient,
+                                    sessionState.mInputId, null, null, sessionState.mSeq,
+                                    sessionState.mUserId);
+                        }
+                    }
+
+                    if (serviceState.mAvailable) {
+                        serviceState.mAvailable = false;
+                        broadcastServiceAvailabilityChangedLocked(serviceState);
+                    }
+                    updateServiceConnectionLocked(mTvInputInfo.getId(), mUserId);
+                }
             }
         }
     }
@@ -787,18 +882,16 @@
         }
 
         @Override
-        public void onAvailabilityChanged(ComponentName name, boolean isAvailable)
-                throws RemoteException {
+        public void onAvailabilityChanged(String inputId, boolean isAvailable) {
             if (DEBUG) {
-                Slog.d(TAG, "onAvailabilityChanged(name=" + name.getClassName() + ", isAvailable="
+                Slog.d(TAG, "onAvailabilityChanged(inputId=" + inputId + ", isAvailable="
                         + isAvailable + ")");
             }
             synchronized (mLock) {
-                ServiceState serviceState = getServiceStateLocked(name, mUserId);
-                serviceState.available = isAvailable;
-                for (IBinder iBinder : serviceState.clients) {
-                    ITvInputClient client = ITvInputClient.Stub.asInterface(iBinder);
-                    client.onAvailabilityChanged(name, isAvailable);
+                ServiceState serviceState = getServiceStateLocked(inputId, mUserId);
+                if (serviceState.mAvailable != isAvailable) {
+                    serviceState.mAvailable = isAvailable;
+                    broadcastServiceAvailabilityChangedLocked(serviceState);
                 }
             }
         }
@@ -851,31 +944,32 @@
 
         private void onOpenEntry(Uri uri, long channelId, long watchStarttime) {
             String[] projection = {
-                    TvContract.Programs.TITLE,
-                    TvContract.Programs.START_TIME_UTC_MILLIS,
-                    TvContract.Programs.END_TIME_UTC_MILLIS,
-                    TvContract.Programs.DESCRIPTION
+                    TvContract.Programs.COLUMN_TITLE,
+                    TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS,
+                    TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS,
+                    TvContract.Programs.COLUMN_DESCRIPTION
             };
-            String selection = TvContract.Programs.CHANNEL_ID + "=? AND "
-                    + TvContract.Programs.START_TIME_UTC_MILLIS + "<=? AND "
-                    + TvContract.Programs.END_TIME_UTC_MILLIS + ">?";
+            String selection = TvContract.Programs.COLUMN_CHANNEL_ID + "=? AND "
+                    + TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS + "<=? AND "
+                    + TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS + ">?";
             String[] selectionArgs = {
                     String.valueOf(channelId),
                     String.valueOf(watchStarttime),
                     String.valueOf(watchStarttime)
             };
-            String sortOrder = TvContract.Programs.START_TIME_UTC_MILLIS + " ASC";
+            String sortOrder = TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS + " ASC";
             Cursor cursor = null;
             try {
                 cursor = mContentResolver.query(TvContract.Programs.CONTENT_URI, projection,
                         selection, selectionArgs, sortOrder);
                 if (cursor != null && cursor.moveToNext()) {
                     ContentValues values = new ContentValues();
-                    values.put(TvContract.WatchedPrograms.TITLE, cursor.getString(0));
-                    values.put(TvContract.WatchedPrograms.START_TIME_UTC_MILLIS, cursor.getLong(1));
+                    values.put(TvContract.WatchedPrograms.COLUMN_TITLE, cursor.getString(0));
+                    values.put(TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS,
+                            cursor.getLong(1));
                     long endTime = cursor.getLong(2);
-                    values.put(TvContract.WatchedPrograms.END_TIME_UTC_MILLIS, endTime);
-                    values.put(TvContract.WatchedPrograms.DESCRIPTION, cursor.getString(3));
+                    values.put(TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime);
+                    values.put(TvContract.WatchedPrograms.COLUMN_DESCRIPTION, cursor.getString(3));
                     mContentResolver.update(uri, values, null, null);
 
                     // Schedule an update when the current program ends.
@@ -895,12 +989,12 @@
 
         private void onUpdateEntry(Uri uri, long channelId, long time) {
             String[] projection = {
-                    TvContract.WatchedPrograms.WATCH_START_TIME_UTC_MILLIS,
-                    TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS,
-                    TvContract.WatchedPrograms.TITLE,
-                    TvContract.WatchedPrograms.START_TIME_UTC_MILLIS,
-                    TvContract.WatchedPrograms.END_TIME_UTC_MILLIS,
-                    TvContract.WatchedPrograms.DESCRIPTION
+                    TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
+                    TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS,
+                    TvContract.WatchedPrograms.COLUMN_TITLE,
+                    TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS,
+                    TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS,
+                    TvContract.WatchedPrograms.COLUMN_DESCRIPTION
             };
             Cursor cursor = null;
             try {
@@ -921,14 +1015,14 @@
                     // The current program has just ended. Create a (complete) log entry off the
                     // current entry.
                     ContentValues values = new ContentValues();
-                    values.put(TvContract.WatchedPrograms.WATCH_START_TIME_UTC_MILLIS,
+                    values.put(TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
                             watchStartTime);
-                    values.put(TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS, time);
-                    values.put(TvContract.WatchedPrograms.CHANNEL_ID, channelId);
-                    values.put(TvContract.WatchedPrograms.TITLE, title);
-                    values.put(TvContract.WatchedPrograms.START_TIME_UTC_MILLIS, startTime);
-                    values.put(TvContract.WatchedPrograms.END_TIME_UTC_MILLIS, endTime);
-                    values.put(TvContract.WatchedPrograms.DESCRIPTION, description);
+                    values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, time);
+                    values.put(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID, channelId);
+                    values.put(TvContract.WatchedPrograms.COLUMN_TITLE, title);
+                    values.put(TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS, startTime);
+                    values.put(TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime);
+                    values.put(TvContract.WatchedPrograms.COLUMN_DESCRIPTION, description);
                     mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values);
                 }
             } finally {
@@ -942,7 +1036,7 @@
 
         private void onCloseEntry(Uri uri, long watchEndTime) {
             ContentValues values = new ContentValues();
-            values.put(TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS, watchEndTime);
+            values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, watchEndTime);
             mContentResolver.update(uri, values, null, null);
         }
     }
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 9039236..99ec242 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -116,7 +116,8 @@
     /** Fraction of animation at which the recents thumbnail becomes completely transparent */
     private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.25f;
 
-    private static final long DEFAULT_APP_TRANSITION_DURATION = 250;
+    private static final int DEFAULT_APP_TRANSITION_DURATION = 250;
+    private static final int THUMBNAIL_APP_TRANSITION_DURATION = 225;
 
     private final Context mContext;
     private final Handler mH;
@@ -160,6 +161,7 @@
     private final int mConfigShortAnimTime;
     private final Interpolator mDecelerateInterpolator;
     private final Interpolator mThumbnailFadeoutInterpolator;
+    private final Interpolator mThumbnailCubicInterpolator;
 
     private int mCurrentUserId = 0;
 
@@ -170,6 +172,8 @@
                 com.android.internal.R.integer.config_shortAnimTime);
         mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.decelerate_cubic);
+        mThumbnailCubicInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_slow_in);
         mThumbnailFadeoutInterpolator = new Interpolator() {
             @Override
             public float getInterpolation(float input) {
@@ -401,11 +405,23 @@
     /**
      * Prepares the specified animation with a standard duration, interpolator, etc.
      */
+    Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight,
+            int duration, Interpolator interpolator) {
+        a.setDuration(duration);
+        a.setFillAfter(true);
+        a.setInterpolator(interpolator);
+        a.initialize(appWidth, appHeight, appWidth, appHeight);
+        return a;
+    }
+
+    /**
+     * Prepares the specified animation with a standard duration, interpolator, etc.
+     */
     Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit) {
         // Pick the desired duration.  If this is an inter-activity transition,
         // it  is the standard duration for that.  Otherwise we use the longer
         // task transition duration.
-        final long duration;
+        final int duration;
         switch (transit) {
             case TRANSIT_ACTIVITY_OPEN:
             case TRANSIT_ACTIVITY_CLOSE:
@@ -415,11 +431,8 @@
                 duration = DEFAULT_APP_TRANSITION_DURATION;
                 break;
         }
-        a.setDuration(duration);
-        a.setFillAfter(true);
-        a.setInterpolator(mDecelerateInterpolator);
-        a.initialize(appWidth, appHeight, appWidth, appHeight);
-        return a;
+        return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
+                mDecelerateInterpolator);
     }
 
     /**
@@ -594,7 +607,8 @@
                 throw new RuntimeException("Invalid thumbnail transition state");
         }
 
-        return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
+        return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight,
+                THUMBNAIL_APP_TRANSITION_DURATION, mThumbnailCubicInterpolator);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 637beec..836a19c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5038,6 +5038,10 @@
             throw new SecurityException("Requires DISABLE_KEYGUARD permission");
         }
 
+        if (token == null) {
+            throw new IllegalArgumentException("token == null");
+        }
+
         mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage(
                 KeyguardDisableHandler.KEYGUARD_DISABLE, new Pair<IBinder, String>(token, tag)));
     }
@@ -5049,6 +5053,10 @@
             throw new SecurityException("Requires DISABLE_KEYGUARD permission");
         }
 
+        if (token == null) {
+            throw new IllegalArgumentException("token == null");
+        }
+
         mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage(
                 KeyguardDisableHandler.KEYGUARD_REENABLE, token));
     }
@@ -5062,6 +5070,11 @@
             != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires DISABLE_KEYGUARD permission");
         }
+
+        if (callback == null) {
+            throw new IllegalArgumentException("callback == null");
+        }
+
         mPolicy.exitKeyguardSecurely(new WindowManagerPolicy.OnKeyguardExitResult() {
             @Override
             public void onKeyguardExitResult(boolean success) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4318b0e..e746c1a 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -299,6 +299,7 @@
 
     boolean mHasSurface = false;
 
+    boolean mNotOnAppsDisplay = false;
     DisplayContent  mDisplayContent;
 
     /** When true this window can be displayed on screens owther than mOwnerUid's */
@@ -430,6 +431,10 @@
         }
         mRootToken = appToken;
         mAppToken = appToken.appWindowToken;
+        if (mAppToken != null) {
+            final DisplayContent appDisplay = getDisplayContent();
+            mNotOnAppsDisplay = displayContent != appDisplay;
+        }
 
         mWinAnimator = new WindowStateAnimator(this);
         mWinAnimator.mAlpha = a.alpha;
@@ -717,7 +722,8 @@
     }
 
     public DisplayContent getDisplayContent() {
-        return mAppToken == null ? mDisplayContent : getStack().getDisplayContent();
+        return mAppToken == null || mNotOnAppsDisplay ?
+                mDisplayContent : getStack().getDisplayContent();
     }
 
     public int getDisplayId() {
diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp
index 163692b..163225e 100644
--- a/services/core/jni/com_android_server_AssetAtlasService.cpp
+++ b/services/core/jni/com_android_server_AssetAtlasService.cpp
@@ -46,33 +46,16 @@
 // ----------------------------------------------------------------------------
 
 static struct {
-    jfieldID mFinalizer;
-    jfieldID mNativeCanvas;
+    jmethodID safeCanvasSwap;
 } gCanvasClassInfo;
 
-static struct {
-    jfieldID mNativeCanvas;
-} gCanvasFinalizerClassInfo;
-
-#define GET_LONG(object, field) \
-    env->GetLongField(object, field)
-
-#define SET_LONG(object, field, value) \
-    env->SetLongField(object, field, value)
+#define INVOKEV(object, method, ...) \
+    env->CallVoidMethod(object, method, __VA_ARGS__)
 
 // ----------------------------------------------------------------------------
 // Canvas management
 // ----------------------------------------------------------------------------
 
-static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
-    jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
-    SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
-            GET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas));
-    SET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas, (long) newCanvas);
-    SET_LONG(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (long) newCanvas);
-    SkSafeUnref(previousCanvas);
-}
-
 static jlong com_android_server_AssetAtlasService_acquireCanvas(JNIEnv* env, jobject,
         jobject canvas, jint width, jint height) {
 
@@ -82,7 +65,7 @@
     bitmap->eraseColor(0);
 
     SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (*bitmap));
-    swapCanvasPtr(env, canvas, nativeCanvas);
+    INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
 
     return reinterpret_cast<jlong>(bitmap);
 }
@@ -92,7 +75,7 @@
 
     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
     SkCanvas* nativeCanvas = SkNEW(SkCanvas);
-    swapCanvasPtr(env, canvas, nativeCanvas);
+    INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
 
     delete bitmap;
 }
@@ -242,9 +225,9 @@
         var = env->FindClass(className); \
         LOG_FATAL_IF(! var, "Unable to find class " className);
 
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
-        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+        LOG_FATAL_IF(!var, "Unable to find method " methodName);
 
 const char* const kClassPathName = "com/android/server/AssetAtlasService";
 
@@ -261,12 +244,7 @@
     jclass clazz;
 
     FIND_CLASS(clazz, "android/graphics/Canvas");
-    GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer",
-            "Landroid/graphics/Canvas$CanvasFinalizer;");
-    GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
-
-    FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer");
-    GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
+    GET_METHOD_ID(gCanvasClassInfo.safeCanvasSwap, clazz, "safeCanvasSwap", "(JZ)V");
 
     return jniRegisterNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
 }
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
index f3e8f3c..27c8876 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -19,57 +19,250 @@
 #define LOG_NDEBUG 1
 
 #include "JNIHelp.h"
+#include "ScopedPrimitiveArray.h"
+
+#include <string>
 
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/Log.h>
 #include <hardware/hdmi_cec.h>
+#include <sys/param.h>
 
 namespace android {
 
 static struct {
-    jmethodID handleMessage;
+    jmethodID handleIncomingCecCommand;
+    jmethodID handleHotplug;
 } gHdmiCecControllerClassInfo;
 
-
 class HdmiCecController {
 public:
-    HdmiCecController(jobject callbacksObj);
+    HdmiCecController(hdmi_cec_device_t* device, jobject callbacksObj);
+
+    void init();
+
+    // Send message to other device. Note that it runs in IO thread.
+    int sendMessage(const cec_message_t& message);
+    // Add a logical address to device.
+    int addLogicalAddress(cec_logical_address_t address);
+    // Clear all logical address registered to the device.
+    void clearLogicaladdress();
+    // Get physical address of device.
+    int getPhysicalAddress();
+    // Get CEC version from driver.
+    int getVersion();
+    // Get vendor id used for vendor command.
+    uint32_t getVendorId();
 
 private:
-    static void onReceived(const hdmi_event_t* event, void* arg);
+    // Propagate the message up to Java layer.
+    void propagateCecCommand(const cec_message_t& message);
+    void propagateHotplugEvent(const hotplug_event_t& event);
 
+    static void onReceived(const hdmi_event_t* event, void* arg);
+    static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
+
+    hdmi_cec_device_t* mDevice;
     jobject mCallbacksObj;
 };
 
-HdmiCecController::HdmiCecController(jobject callbacksObj) :
+HdmiCecController::HdmiCecController(hdmi_cec_device_t* device, jobject callbacksObj) :
+    mDevice(device),
     mCallbacksObj(callbacksObj) {
 }
 
+void HdmiCecController::init() {
+    mDevice->register_event_callback(mDevice, HdmiCecController::onReceived, this);
+}
+
+void HdmiCecController::propagateCecCommand(const cec_message_t& message) {
+    jint srcAddr = message.initiator;
+    jint dstAddr = message.destination;
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jbyteArray body = env->NewByteArray(message.length);
+    const jbyte* bodyPtr = reinterpret_cast<const jbyte *>(message.body);
+    env->SetByteArrayRegion(body, 0, message.length, bodyPtr);
+
+    env->CallVoidMethod(mCallbacksObj,
+            gHdmiCecControllerClassInfo.handleIncomingCecCommand,
+            srcAddr, dstAddr, body);
+    env->DeleteLocalRef(body);
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+void HdmiCecController::propagateHotplugEvent(const hotplug_event_t& event) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj,
+            gHdmiCecControllerClassInfo.handleHotplug, event.connected);
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+int HdmiCecController::sendMessage(const cec_message_t& message) {
+    // TODO: propagate send_message's return value.
+    return mDevice->send_message(mDevice, &message);
+}
+
+int HdmiCecController::addLogicalAddress(cec_logical_address_t address) {
+    return mDevice->add_logical_address(mDevice, address);
+}
+
+void HdmiCecController::clearLogicaladdress() {
+    mDevice->clear_logical_address(mDevice);
+}
+
+int HdmiCecController::getPhysicalAddress() {
+    uint16_t physicalAddress = 0xFFFF;
+    if (mDevice->get_physical_address(mDevice, &physicalAddress) == 0) {
+        return physicalAddress;
+    }
+    return -1;
+}
+
+int HdmiCecController::getVersion() {
+    int version = 0;
+    mDevice->get_version(mDevice, &version);
+    return version;
+}
+
+uint32_t HdmiCecController::getVendorId() {
+    uint32_t vendorId = 0;
+    mDevice->get_vendor_id(mDevice, &vendorId);
+    return vendorId;
+}
+
+// static
+void HdmiCecController::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 HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) {
-    HdmiCecController* handler = static_cast<HdmiCecController*>(arg);
-    if (handler == NULL) {
+    HdmiCecController* controller = static_cast<HdmiCecController*>(arg);
+    if (controller == NULL) {
         return;
     }
 
-    // TODO: propagate message to Java layer.
+    switch (event->type) {
+    case HDMI_EVENT_CEC_MESSAGE:
+        controller->propagateCecCommand(event->cec);
+        break;
+    case HDMI_EVENT_HOT_PLUG:
+        controller->propagateHotplugEvent(event->hotplug);
+        break;
+    default:
+        ALOGE("Unsupported event type: %d", event->type);
+        break;
+    }
 }
 
-
 //------------------------------------------------------------------------------
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+        LOG_FATAL_IF(! var, "Unable to find method " methodName);
+
 static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj) {
-    // TODO: initialize hal and pass it to controller if ready.
+    int err;
+    // If use same hardware module id between HdmiCecService and
+    // HdmiControlSservice it may conflict and cause abnormal state of HAL.
+    // TODO: use HDMI_CEC_HARDWARE_MODULE_ID of hdmi_cec.h for module id
+    //       once migration to HdmiControlService is done.
+    hw_module_t* module;
+    err = hw_get_module("hdmi_cec_module",
+            const_cast<const hw_module_t **>(&module));
+    if (err != 0) {
+        ALOGE("Error acquiring hardware module: %d", err);
+        return 0;
+    }
+    hw_device_t* device;
+    // TODO: use HDMI_CEC_HARDWARE_INTERFACE of hdmi_cec.h for interface name
+    //       once migration to HdmiControlService is done.
+    err = module->methods->open(module, "hdmi_cec_module_hw_if", &device);
+    if (err != 0) {
+        ALOGE("Error opening hardware module: %d", err);
+        return 0;
+    }
 
     HdmiCecController* controller = new HdmiCecController(
+            reinterpret_cast<hdmi_cec_device*>(device),
             env->NewGlobalRef(callbacksObj));
+    controller->init();
+
+    GET_METHOD_ID(gHdmiCecControllerClassInfo.handleIncomingCecCommand, clazz,
+            "handleIncomingCecCommand", "(II[B)V");
+    GET_METHOD_ID(gHdmiCecControllerClassInfo.handleHotplug, clazz,
+            "handleHotplug", "(Z)V");
 
     return reinterpret_cast<jlong>(controller);
 }
 
+static jint nativeSendCecCommand(JNIEnv* env, jclass clazz, jlong controllerPtr,
+        jint srcAddr, jint dstAddr, jbyteArray body) {
+    cec_message_t message;
+    message.initiator = static_cast<cec_logical_address_t>(srcAddr);
+    message.destination = static_cast<cec_logical_address_t>(dstAddr);
+
+    jsize len = env->GetArrayLength(body);
+    message.length = MIN(len, CEC_MESSAGE_BODY_MAX_LENGTH);
+    ScopedByteArrayRO bodyPtr(env, body);
+    std::memcpy(message.body, bodyPtr.get(), len);
+
+    HdmiCecController* controller =
+            reinterpret_cast<HdmiCecController*>(controllerPtr);
+    return controller->sendMessage(message);
+}
+
+static jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz,
+        jlong controllerPtr, jint logicalAddress) {
+    HdmiCecController* controller =
+            reinterpret_cast<HdmiCecController*>(controllerPtr);
+    return controller->addLogicalAddress(
+            static_cast<cec_logical_address_t>(logicalAddress));
+}
+
+static void nativeClearLogicalAddress(JNIEnv* env, jclass clazz,
+        jlong controllerPtr) {
+    HdmiCecController* controller =
+            reinterpret_cast<HdmiCecController*>(controllerPtr);
+    controller->clearLogicaladdress();
+}
+
+static jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz,
+        jlong controllerPtr) {
+    HdmiCecController* controller =
+            reinterpret_cast<HdmiCecController*>(controllerPtr);
+    return controller->getPhysicalAddress();
+}
+
+static jint nativeGetVersion(JNIEnv* env, jclass clazz,
+        jlong controllerPtr) {
+    HdmiCecController* controller =
+            reinterpret_cast<HdmiCecController*>(controllerPtr);
+    return controller->getVersion();
+}
+
+static jint nativeGetVendorId(JNIEnv* env, jclass clazz, jlong controllerPtr) {
+    HdmiCecController* controller =
+            reinterpret_cast<HdmiCecController*>(controllerPtr);
+    return controller->getVendorId();
+}
+
 static JNINativeMethod sMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInit", "(Lcom/android/server/hdmi/HdmiCecController;)J",
             (void *) nativeInit },
+    { "nativeSendCecCommand", "(JII[B)I", (void *) nativeSendCecCommand },
+    { "nativeAddLogicalAddress", "(JI)I", (void *) nativeAddLogicalAddress },
+    { "nativeClearLogicalAddress", "(J)V", (void *) nativeClearLogicalAddress },
+    { "nativeGetPhysicalAddress", "(J)I", (void *) nativeGetPhysicalAddress },
+    { "nativeGetVersion", "(J)I", (void *) nativeGetVersion },
+    { "nativeGetVendorId", "(J)I", (void *) nativeGetVendorId },
 };
 
 #define CLASS_PATH "com/android/server/hdmi/HdmiCecController"
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index 3c46e40..1647425 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -53,7 +53,6 @@
     private static final String ATTR_NAME = "name";
     private static final String ATTR_PACKAGE = "package";
     private static final String ATTR_USERID = "userId";
-    private static final String ATTR_ENABLED = "profileEnabled";
 
     private AtomicFile fileForWriting;
 
@@ -104,8 +103,7 @@
      */
     static DeviceOwner createWithProfileOwner(String packageName, String ownerName, int userId) {
         DeviceOwner owner = new DeviceOwner();
-        owner.mProfileOwners.put(
-                userId, new OwnerInfo(ownerName, packageName, false /* disabled */));
+        owner.mProfileOwners.put(userId, new OwnerInfo(ownerName, packageName));
         return owner;
     }
 
@@ -122,7 +120,7 @@
     }
 
     void setProfileOwner(String packageName, String ownerName, int userId) {
-        mProfileOwners.put(userId, new OwnerInfo(ownerName, packageName, false /* disabled */));
+        mProfileOwners.put(userId, new OwnerInfo(ownerName, packageName));
     }
 
     void removeProfileOwner(int userId) {
@@ -139,19 +137,6 @@
         return profileOwner != null ? profileOwner.name : null;
     }
 
-    boolean isProfileEnabled(int userId) {
-        OwnerInfo profileOwner = mProfileOwners.get(userId);
-        return profileOwner != null ? profileOwner.enabled : true;
-    }
-
-    void setProfileEnabled(int userId) {
-        OwnerInfo profileOwner = mProfileOwners.get(userId);
-        if (profileOwner == null) {
-            throw new IllegalArgumentException("No profile owner exists.");
-        }
-        profileOwner.enabled = true;
-    }
-
     boolean hasDeviceOwner() {
         return mDeviceOwner != null;
     }
@@ -203,12 +188,9 @@
                 } else if (tag.equals(TAG_PROFILE_OWNER)) {
                     String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
                     String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
-                    Boolean profileEnabled = Boolean.parseBoolean(
-                            parser.getAttributeValue(null, ATTR_ENABLED));
                     int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USERID));
                     mProfileOwners.put(userId,
-                            new OwnerInfo(
-                                    profileOwnerName, profileOwnerPackageName, profileEnabled));
+                            new OwnerInfo(profileOwnerName, profileOwnerPackageName));
                 } else {
                     throw new XmlPullParserException(
                             "Unexpected tag in device owner file: " + tag);
@@ -251,7 +233,6 @@
                     out.startTag(null, TAG_PROFILE_OWNER);
                     out.attribute(null, ATTR_PACKAGE, owner.getValue().packageName);
                     out.attribute(null, ATTR_NAME, owner.getValue().name);
-                    out.attribute(null, ATTR_ENABLED, String.valueOf(owner.getValue().enabled));
                     out.attribute(null, ATTR_USERID, Integer.toString(owner.getKey()));
                     out.endTag(null, TAG_PROFILE_OWNER);
                 }
@@ -292,12 +273,6 @@
     static class OwnerInfo {
         public String name;
         public String packageName;
-        public boolean enabled = true; // only makes sense for managed profiles
-
-        public OwnerInfo(String name, String packageName, boolean enabled) {
-            this(name, packageName);
-            this.enabled = enabled;
-        }
 
         public OwnerInfo(String name, String packageName) {
             this.name = name;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f1ee280..1980d1e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -44,12 +44,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
@@ -96,9 +97,11 @@
 import java.security.cert.X509Certificate;
 import java.text.DateFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
@@ -111,6 +114,8 @@
 
     private static final String DEVICE_POLICIES_XML = "device_policies.xml";
 
+    private static final String LOCK_TASK_COMPONENTS_XML = "lock-task-component";
+
     private static final int REQUEST_EXPIRE_PASSWORD = 5571;
 
     private static final long MS_PER_DAY = 86400 * 1000;
@@ -125,6 +130,7 @@
     private static final boolean DBG = false;
 
     final Context mContext;
+    final UserManager mUserManager;
     final PowerManager.WakeLock mWakeLock;
 
     IPowerManager mIPowerManager;
@@ -180,6 +186,9 @@
         final ArrayList<ActiveAdmin> mAdminList
                 = new ArrayList<ActiveAdmin>();
 
+        // This is the list of component allowed to start lock task mode.
+        final List<ComponentName> mLockTaskComponents = new ArrayList<ComponentName>();
+
         public DevicePolicyData(int userHandle) {
             mUserHandle = userHandle;
         }
@@ -201,7 +210,7 @@
                         + action + " for user " + userHandle);
                 mHandler.post(new Runnable() {
                     public void run() {
-                        handlePasswordExpirationNotification(getUserData(userHandle));
+                        handlePasswordExpirationNotification(userHandle);
                     }
                 });
             }
@@ -231,6 +240,8 @@
     static class ActiveAdmin {
         private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features";
         private static final String TAG_DISABLE_CAMERA = "disable-camera";
+        private static final String TAG_DISABLE_ACCOUNT_MANAGEMENT = "disable-account-management";
+        private static final String TAG_ACCOUNT_TYPE = "account-type";
         private static final String TAG_ENCRYPTION_REQUESTED = "encryption-requested";
         private static final String TAG_PASSWORD_EXPIRATION_DATE = "password-expiration-date";
         private static final String TAG_PASSWORD_EXPIRATION_TIMEOUT = "password-expiration-timeout";
@@ -296,6 +307,7 @@
 
         boolean encryptionRequested = false;
         boolean disableCamera = false;
+        Set<String> accountTypesWithManagementDisabled = new HashSet<String>();
 
         // TODO: review implementation decisions with frameworks team
         boolean specifiesGlobalProxy = false;
@@ -412,6 +424,15 @@
                 out.attribute(null, ATTR_VALUE, Integer.toString(disabledKeyguardFeatures));
                 out.endTag(null, TAG_DISABLE_KEYGUARD_FEATURES);
             }
+            if (!accountTypesWithManagementDisabled.isEmpty()) {
+                out.startTag(null, TAG_DISABLE_ACCOUNT_MANAGEMENT);
+                for (String ac : accountTypesWithManagementDisabled) {
+                    out.startTag(null, TAG_ACCOUNT_TYPE);
+                    out.attribute(null, ATTR_VALUE, ac);
+                    out.endTag(null, TAG_ACCOUNT_TYPE);
+                }
+                out.endTag(null,  TAG_DISABLE_ACCOUNT_MANAGEMENT);
+            }
         }
 
         void readFromXml(XmlPullParser parser)
@@ -483,6 +504,23 @@
                 } else if (TAG_DISABLE_KEYGUARD_FEATURES.equals(tag)) {
                     disabledKeyguardFeatures = Integer.parseInt(
                             parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_DISABLE_ACCOUNT_MANAGEMENT.equals(tag)) {
+                    int outerDepthDAM = parser.getDepth();
+                    int typeDAM;
+                    while ((typeDAM=parser.next()) != XmlPullParser.END_DOCUMENT
+                            && (typeDAM != XmlPullParser.END_TAG
+                                    || parser.getDepth() > outerDepthDAM)) {
+                        if (typeDAM == XmlPullParser.END_TAG || typeDAM == XmlPullParser.TEXT) {
+                            continue;
+                        }
+                        String tagDAM = parser.getName();
+                        if (TAG_ACCOUNT_TYPE.equals(tagDAM)) {
+                            accountTypesWithManagementDisabled.add(
+                                    parser.getAttributeValue(null, ATTR_VALUE));
+                        } else {
+                            Slog.w(LOG_TAG, "Unknown tag under " + tag +  ": " + tagDAM);
+                        }
+                    }
                 } else {
                     Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
                 }
@@ -574,6 +612,7 @@
      */
     public DevicePolicyManagerService(Context context) {
         mContext = context;
+        mUserManager = UserManager.get(mContext);
         mHasFeature = context.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_DEVICE_ADMIN);
         mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
@@ -588,6 +627,7 @@
         filter.addAction(Intent.ACTION_USER_REMOVED);
         filter.addAction(Intent.ACTION_USER_STARTED);
         filter.addAction(KeyChain.ACTION_STORAGE_CHANGED);
+        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
         context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
         filter = new IntentFilter();
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
@@ -780,6 +820,9 @@
         sendAdminCommandLocked(admin, action, null);
     }
 
+    /**
+     * Send an update to one specific admin, get notified when that admin returns a result.
+     */
     void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
         Intent intent = new Intent(action);
         intent.setComponent(admin.info.getComponent());
@@ -794,12 +837,15 @@
         }
     }
 
+    /**
+     * Send an update to all admins of a user that enforce a specified policy.
+     */
     void sendAdminCommandLocked(String action, int reqPolicy, int userHandle) {
         final DevicePolicyData policy = getUserData(userHandle);
         final int count = policy.mAdminList.size();
         if (count > 0) {
             for (int i = 0; i < count; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
+                final ActiveAdmin admin = policy.mAdminList.get(i);
                 if (admin.info.usesPolicy(reqPolicy)) {
                     sendAdminCommandLocked(admin, action);
                 }
@@ -807,6 +853,19 @@
         }
     }
 
+    /**
+     * Send an update intent to all admins of a user and its profiles. Only send to admins that
+     * enforce a specified policy.
+     */
+    private void sendAdminCommandToSelfAndProfilesLocked(String action, int reqPolicy,
+            int userHandle) {
+        List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+        for (UserInfo ui : profiles) {
+            int id = ui.getUserHandle().getIdentifier();
+            sendAdminCommandLocked(action, reqPolicy, id);
+        }
+    }
+
     void removeActiveAdminLocked(final ComponentName adminReceiver, int userHandle) {
         final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
         if (admin != null) {
@@ -923,6 +982,13 @@
                 out.endTag(null, "active-password");
             }
 
+            for (int i=0; i<policy.mLockTaskComponents.size(); i++) {
+                ComponentName component = policy.mLockTaskComponents.get(i);
+                out.startTag(null, LOCK_TASK_COMPONENTS_XML);
+                out.attribute(null, "name", component.flattenToString());
+                out.endTag(null, LOCK_TASK_COMPONENTS_XML);
+            }
+
             out.endTag(null, "policies");
 
             out.endDocument();
@@ -972,6 +1038,7 @@
             }
             type = parser.next();
             int outerDepth = parser.getDepth();
+            policy.mLockTaskComponents.clear();
             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
                 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
@@ -1024,6 +1091,11 @@
                     policy.mActivePasswordNonLetter = Integer.parseInt(
                             parser.getAttributeValue(null, "nonletter"));
                     XmlUtils.skipCurrentTag(parser);
+                } else if (LOCK_TASK_COMPONENTS_XML.equals(tag)) {
+                    policy.mLockTaskComponents.add
+                        (ComponentName.unflattenFromString
+                         (parser.getAttributeValue(null, "name")));
+                    XmlUtils.skipCurrentTag(parser);
                 } else {
                     Slog.w(LOG_TAG, "Unknown tag: " + tag);
                     XmlUtils.skipCurrentTag(parser);
@@ -1139,23 +1211,29 @@
         }
     }
 
-    private void handlePasswordExpirationNotification(DevicePolicyData policy) {
+    private void handlePasswordExpirationNotification(int userHandle) {
         synchronized (this) {
             final long now = System.currentTimeMillis();
-            final int N = policy.mAdminList.size();
-            if (N <= 0) {
-                return;
-            }
-            for (int i=0; i < N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
-                        && admin.passwordExpirationTimeout > 0L
-                        && admin.passwordExpirationDate > 0L
-                        && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
-                    sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
+
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo ui : profiles) {
+                int profileUserHandle = ui.getUserHandle().getIdentifier();
+                final DevicePolicyData policy = getUserData(profileUserHandle);
+                final int count = policy.mAdminList.size();
+                if (count > 0) {
+                    for (int i = 0; i < count; i++) {
+                        final ActiveAdmin admin = policy.mAdminList.get(i);
+                        if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
+                                && admin.passwordExpirationTimeout > 0L
+                                && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS
+                                && admin.passwordExpirationDate > 0L) {
+                            sendAdminCommandLocked(admin,
+                                    DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
+                        }
+                    }
                 }
             }
-            setExpirationAlarmCheckLocked(mContext, policy);
+            setExpirationAlarmCheckLocked(mContext, getUserData(userHandle));
         }
     }
 
@@ -1165,8 +1243,7 @@
         final boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
         if (! hasCert) {
             if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
-                UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-                for (UserInfo user : um.getUsers()) {
+                for (UserInfo user : mUserManager.getUsers()) {
                     notificationManager.cancelAsUser(
                             null, MONITORING_CERT_NOTIFICATION_ID, user.getUserHandle());
                 }
@@ -1205,8 +1282,7 @@
         // If this is a boot intent, this will fire for each user. But if this is a storage changed
         // intent, it will fire once, so we need to notify all users.
         if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
-            UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-            for (UserInfo user : um.getUsers()) {
+            for (UserInfo user : mUserManager.getUsers()) {
                 notificationManager.notifyAsUser(
                         null, MONITORING_CERT_NOTIFICATION_ID, noti, user.getUserHandle());
             }
@@ -1383,18 +1459,22 @@
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
-            DevicePolicyData policy = getUserData(userHandle);
 
             if (who != null) {
                 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
                 return admin != null ? admin.passwordQuality : mode;
             }
 
-            final int N = policy.mAdminList.size();
-            for  (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (mode < admin.passwordQuality) {
-                    mode = admin.passwordQuality;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i=0; i<N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (mode < admin.passwordQuality) {
+                        mode = admin.passwordQuality;
+                    }
                 }
             }
             return mode;
@@ -1425,7 +1505,6 @@
         }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
-            DevicePolicyData policy = getUserData(userHandle);
             int length = 0;
 
             if (who != null) {
@@ -1433,11 +1512,16 @@
                 return admin != null ? admin.minimumPasswordLength : length;
             }
 
-            final int N = policy.mAdminList.size();
-            for  (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (length < admin.minimumPasswordLength) {
-                    length = admin.minimumPasswordLength;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i=0; i<N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (length < admin.minimumPasswordLength) {
+                        length = admin.minimumPasswordLength;
+                    }
                 }
             }
             return length;
@@ -1468,7 +1552,6 @@
         }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
-            DevicePolicyData policy = getUserData(userHandle);
             int length = 0;
 
             if (who != null) {
@@ -1476,11 +1559,16 @@
                 return admin != null ? admin.passwordHistoryLength : length;
             }
 
-            final int N = policy.mAdminList.size();
-            for (int i = 0; i < N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (length < admin.passwordHistoryLength) {
-                    length = admin.passwordHistoryLength;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i = 0; i < N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (length < admin.passwordHistoryLength) {
+                        length = admin.passwordHistoryLength;
+                    }
                 }
             }
             return length;
@@ -1526,19 +1614,23 @@
         }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
+            long timeout = 0L;
+
             if (who != null) {
                 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
-                return admin != null ? admin.passwordExpirationTimeout : 0L;
+                return admin != null ? admin.passwordExpirationTimeout : timeout;
             }
 
-            long timeout = 0L;
-            DevicePolicyData policy = getUserData(userHandle);
-            final int N = policy.mAdminList.size();
-            for (int i = 0; i < N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
-                        && timeout > admin.passwordExpirationTimeout)) {
-                    timeout = admin.passwordExpirationTimeout;
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i = 0; i < N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
+                            && timeout > admin.passwordExpirationTimeout)) {
+                        timeout = admin.passwordExpirationTimeout;
+                    }
                 }
             }
             return timeout;
@@ -1550,19 +1642,23 @@
      * Returns 0 if not configured.
      */
     private long getPasswordExpirationLocked(ComponentName who, int userHandle) {
+        long timeout = 0L;
+
         if (who != null) {
             ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
-            return admin != null ? admin.passwordExpirationDate : 0L;
+            return admin != null ? admin.passwordExpirationDate : timeout;
         }
 
-        long timeout = 0L;
-        DevicePolicyData policy = getUserData(userHandle);
-        final int N = policy.mAdminList.size();
-        for (int i = 0; i < N; i++) {
-            ActiveAdmin admin = policy.mAdminList.get(i);
-            if (timeout == 0L || (admin.passwordExpirationDate != 0
-                    && timeout > admin.passwordExpirationDate)) {
-                timeout = admin.passwordExpirationDate;
+        List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+        for (UserInfo userInfo : profiles) {
+            DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+            final int N = policy.mAdminList.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = policy.mAdminList.get(i);
+                if (timeout == 0L || (admin.passwordExpirationDate != 0
+                        && timeout > admin.passwordExpirationDate)) {
+                    timeout = admin.passwordExpirationDate;
+                }
             }
         }
         return timeout;
@@ -1609,12 +1705,16 @@
                 return admin != null ? admin.minimumPasswordUpperCase : length;
             }
 
-            DevicePolicyData policy = getUserData(userHandle);
-            final int N = policy.mAdminList.size();
-            for (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (length < admin.minimumPasswordUpperCase) {
-                    length = admin.minimumPasswordUpperCase;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i=0; i<N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (length < admin.minimumPasswordUpperCase) {
+                        length = admin.minimumPasswordUpperCase;
+                    }
                 }
             }
             return length;
@@ -1649,12 +1749,16 @@
                 return admin != null ? admin.minimumPasswordLowerCase : length;
             }
 
-            DevicePolicyData policy = getUserData(userHandle);
-            final int N = policy.mAdminList.size();
-            for (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (length < admin.minimumPasswordLowerCase) {
-                    length = admin.minimumPasswordLowerCase;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i=0; i<N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (length < admin.minimumPasswordLowerCase) {
+                        length = admin.minimumPasswordLowerCase;
+                    }
                 }
             }
             return length;
@@ -1692,12 +1796,16 @@
                 return admin != null ? admin.minimumPasswordLetters : length;
             }
 
-            DevicePolicyData policy = getUserData(userHandle);
-            final int N = policy.mAdminList.size();
-            for (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (length < admin.minimumPasswordLetters) {
-                    length = admin.minimumPasswordLetters;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i=0; i<N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (length < admin.minimumPasswordLetters) {
+                        length = admin.minimumPasswordLetters;
+                    }
                 }
             }
             return length;
@@ -1735,12 +1843,16 @@
                 return admin != null ? admin.minimumPasswordNumeric : length;
             }
 
-            DevicePolicyData policy = getUserData(userHandle);
-            final int N = policy.mAdminList.size();
-            for (int i = 0; i < N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (length < admin.minimumPasswordNumeric) {
-                    length = admin.minimumPasswordNumeric;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i = 0; i < N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (length < admin.minimumPasswordNumeric) {
+                        length = admin.minimumPasswordNumeric;
+                    }
                 }
             }
             return length;
@@ -1778,12 +1890,16 @@
                 return admin != null ? admin.minimumPasswordSymbols : length;
             }
 
-            DevicePolicyData policy = getUserData(userHandle);
-            final int N = policy.mAdminList.size();
-            for  (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (length < admin.minimumPasswordSymbols) {
-                    length = admin.minimumPasswordSymbols;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i=0; i<N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (length < admin.minimumPasswordSymbols) {
+                        length = admin.minimumPasswordSymbols;
+                    }
                 }
             }
             return length;
@@ -1821,12 +1937,16 @@
                 return admin != null ? admin.minimumPasswordNonLetter : length;
             }
 
-            DevicePolicyData policy = getUserData(userHandle);
-            final int N = policy.mAdminList.size();
-            for (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (length < admin.minimumPasswordNonLetter) {
-                    length = admin.minimumPasswordNonLetter;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i=0; i<N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (length < admin.minimumPasswordNonLetter) {
+                        length = admin.minimumPasswordNonLetter;
+                    }
                 }
             }
             return length;
@@ -1838,8 +1958,16 @@
             return true;
         }
         enforceCrossUserPermission(userHandle);
+
         synchronized (this) {
-            DevicePolicyData policy = getUserData(userHandle);
+
+            // The active password is stored in the user that runs the launcher
+            // If the user this is called from is part of a profile group, that is the parent
+            // of the group.
+            UserInfo parent = getProfileParent(userHandle);
+            int id = parent == null ? userHandle : parent.id;
+            DevicePolicyData policy = getUserData(id);
+
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(null,
@@ -1861,13 +1989,16 @@
     }
 
     public int getCurrentFailedPasswordAttempts(int userHandle) {
-        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(null,
                     DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
-            return getUserData(userHandle).mFailedPasswordAttempts;
+
+            // The active password is stored in the parent.
+            DevicePolicyData policy = getUserData(getProfileParent(userHandle).id);
+
+            return policy.mFailedPasswordAttempts;
         }
     }
 
@@ -1877,6 +2008,9 @@
         }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(who,
@@ -1896,7 +2030,6 @@
         }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
-            DevicePolicyData policy = getUserData(userHandle);
             int count = 0;
 
             if (who != null) {
@@ -1904,14 +2037,19 @@
                 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
             }
 
-            final int N = policy.mAdminList.size();
-            for  (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (count == 0) {
-                    count = admin.maximumFailedPasswordsForWipe;
-                } else if (admin.maximumFailedPasswordsForWipe != 0
-                        && count > admin.maximumFailedPasswordsForWipe) {
-                    count = admin.maximumFailedPasswordsForWipe;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i=0; i<N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (count == 0) {
+                        count = admin.maximumFailedPasswordsForWipe;
+                    } else if (admin.maximumFailedPasswordsForWipe != 0
+                            && count > admin.maximumFailedPasswordsForWipe) {
+                        count = admin.maximumFailedPasswordsForWipe;
+                    }
                 }
             }
             return count;
@@ -1923,9 +2061,11 @@
             return false;
         }
         enforceCrossUserPermission(userHandle);
+        enforceNotManagedProfile(userHandle, "reset the password");
+
         int quality;
         synchronized (this) {
-            // This API can only be called by an active device admin,
+            // This api can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(null,
                     DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
@@ -2103,15 +2243,19 @@
                 return admin != null ? admin.maximumTimeToUnlock : time;
             }
 
-            DevicePolicyData policy = getUserData(userHandle);
-            final int N = policy.mAdminList.size();
-            for  (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (time == 0) {
-                    time = admin.maximumTimeToUnlock;
-                } else if (admin.maximumTimeToUnlock != 0
-                        && time > admin.maximumTimeToUnlock) {
-                    time = admin.maximumTimeToUnlock;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i=0; i<N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (time == 0) {
+                        time = admin.maximumTimeToUnlock;
+                    } else if (admin.maximumTimeToUnlock != 0
+                            && time > admin.maximumTimeToUnlock) {
+                        time = admin.maximumTimeToUnlock;
+                    }
                 }
             }
             return time;
@@ -2269,7 +2413,7 @@
                 public void run() {
                     try {
                         ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER);
-                        ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
+                        (mUserManager)
                                 .removeUser(userHandle);
                     } catch (RemoteException re) {
                         // Shouldn't happen
@@ -2317,6 +2461,8 @@
             return;
         }
         enforceCrossUserPermission(userHandle);
+        enforceNotManagedProfile(userHandle, "set the active password");
+
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
         DevicePolicyData p = getUserData(userHandle);
@@ -2345,7 +2491,8 @@
                     saveSettingsLocked(userHandle);
                     updatePasswordExpirationsLocked(userHandle);
                     setExpirationAlarmCheckLocked(mContext, p);
-                    sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
+                    sendAdminCommandToSelfAndProfilesLocked(
+                            DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
                             DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -2355,26 +2502,31 @@
     }
 
     /**
-     * Called any time the device password is updated.  Resets all password expiration clocks.
+     * Called any time the device password is updated. Resets all password expiration clocks.
      */
     private void updatePasswordExpirationsLocked(int userHandle) {
-        DevicePolicyData policy = getUserData(userHandle);
-        final int N = policy.mAdminList.size();
-        if (N > 0) {
-            for (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
-                    long timeout = admin.passwordExpirationTimeout;
-                    long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
-                    admin.passwordExpirationDate = expiration;
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                int profileId = userInfo.getUserHandle().getIdentifier();
+                DevicePolicyData policy = getUserData(profileId);
+                final int N = policy.mAdminList.size();
+                if (N > 0) {
+                    for (int i=0; i<N; i++) {
+                        ActiveAdmin admin = policy.mAdminList.get(i);
+                        if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
+                            long timeout = admin.passwordExpirationTimeout;
+                            long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
+                            admin.passwordExpirationDate = expiration;
+                        }
+                    }
                 }
+                saveSettingsLocked(profileId);
             }
-            saveSettingsLocked(userHandle);
-        }
     }
 
     public void reportFailedPasswordAttempt(int userHandle) {
         enforceCrossUserPermission(userHandle);
+        enforceNotManagedProfile(userHandle, "report failed password attempt");
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
 
@@ -2389,7 +2541,8 @@
                     if (max > 0 && policy.mFailedPasswordAttempts >= max) {
                         wipeDeviceOrUserLocked(0, userHandle);
                     }
-                    sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
+                    sendAdminCommandToSelfAndProfilesLocked(
+                            DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
                             DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
                 }
             } finally {
@@ -2412,7 +2565,8 @@
                     policy.mPasswordOwner = -1;
                     saveSettingsLocked(userHandle);
                     if (mHasFeature) {
-                        sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
+                        sendAdminCommandToSelfAndProfilesLocked(
+                                DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
                                 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
                     }
                 } finally {
@@ -2441,7 +2595,7 @@
             // Scan through active admins and find if anyone has already
             // set the global proxy.
             Set<ComponentName> compSet = policy.mAdminMap.keySet();
-            for  (ComponentName component : compSet) {
+            for (ComponentName component : compSet) {
                 ActiveAdmin ap = policy.mAdminMap.get(component);
                 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
                     // Another admin already sets the global proxy
@@ -2470,8 +2624,11 @@
             // Reset the global proxy accordingly
             // Do this using system permissions, as apps cannot write to secure settings
             long origId = Binder.clearCallingIdentity();
-            resetGlobalProxyLocked(policy);
-            Binder.restoreCallingIdentity(origId);
+            try {
+                resetGlobalProxyLocked(policy);
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
             return null;
         }
     }
@@ -2531,7 +2688,7 @@
         exclusionList = exclusionList.trim();
         ContentResolver res = mContext.getContentResolver();
 
-        ProxyProperties proxyProperties = new ProxyProperties(data[0], proxyPort, exclusionList);
+        ProxyInfo proxyProperties = new ProxyInfo(data[0], proxyPort, exclusionList);
         if (!proxyProperties.isValid()) {
             Slog.e(LOG_TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
             return;
@@ -2856,8 +3013,7 @@
         }
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
 
-        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        if (um.getUserInfo(userHandle) == null) {
+        if (mUserManager.getUserInfo(userHandle) == null) {
             // User doesn't exist.
             throw new IllegalArgumentException(
                     "Attempted to set profile owner for invalid userId: " + userHandle);
@@ -2903,11 +3059,9 @@
             int userId = UserHandle.getCallingUserId();
             Slog.d(LOG_TAG, "Enabling the profile for: " + userId);
 
-            mDeviceOwner.setProfileEnabled(userId);
-            mDeviceOwner.writeOwnerFile();
-
             long id = Binder.clearCallingIdentity();
             try {
+                mUserManager.setUserEnabled(userId);
                 Intent intent = new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED);
                 intent.putExtra(Intent.EXTRA_USER, new UserHandle(UserHandle.getCallingUserId()));
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY |
@@ -2948,23 +3102,6 @@
         return null;
     }
 
-    @Override
-    public boolean isProfileEnabled(int userHandle) {
-        if (!mHasFeature) {
-            // If device policy management is not enabled, then the userHandle cannot belong to a
-            // managed profile. All other profiles are considered enabled.
-            return true;
-        }
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
-
-        synchronized (this) {
-            if (mDeviceOwner != null) {
-                 return mDeviceOwner.isProfileEnabled(userHandle);
-            }
-        }
-        return true;
-    }
-
     private boolean isDeviceProvisioned() {
         return Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.DEVICE_PROVISIONED, 0) > 0;
@@ -2988,6 +3125,30 @@
         }
     }
 
+    private void enforceNotManagedProfile(int userHandle, String message) {
+        if(isManagedProfile(userHandle)) {
+            throw new SecurityException("You can not " + message + " from a managed profile. ");
+        }
+    }
+
+    private UserInfo getProfileParent(int userHandle) {
+        long ident = Binder.clearCallingIdentity();
+        try {
+            return mUserManager.getProfileParent(userHandle);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private boolean isManagedProfile(int userHandle) {
+        long ident = Binder.clearCallingIdentity();
+        try {
+            return mUserManager.getUserInfo(userHandle).isManagedProfile();
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
     private void enableIfNecessary(String packageName, int userId) {
         try {
             IPackageManager ipm = AppGlobals.getPackageManager();
@@ -3040,6 +3201,7 @@
         }
     }
 
+    @Override
     public void addPersistentPreferredActivity(ComponentName who, IntentFilter filter,
             ComponentName activity) {
         synchronized (this) {
@@ -3060,6 +3222,7 @@
         }
     }
 
+    @Override
     public void clearPackagePersistentPreferredActivities(ComponentName who, String packageName) {
         synchronized (this) {
             if (who == null) {
@@ -3089,10 +3252,56 @@
             }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-            UserManager um = UserManager.get(mContext);
             long id = Binder.clearCallingIdentity();
             try {
-                um.setApplicationRestrictions(packageName, settings, userHandle);
+                mUserManager.setApplicationRestrictions(packageName, settings, userHandle);
+            } finally {
+                restoreCallingIdentity(id);
+            }
+        }
+    }
+
+    public void addForwardingIntentFilter(ComponentName who, IntentFilter filter, int flags) {
+        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();
+            try {
+                if ((flags & DevicePolicyManager.FLAG_TO_PRIMARY_USER) != 0) {
+                    pm.addForwardingIntentFilter(filter, true /*removable*/, callingUserId,
+                            UserHandle.USER_OWNER);
+                }
+                if ((flags & DevicePolicyManager.FLAG_TO_MANAGED_PROFILE) != 0) {
+                    pm.addForwardingIntentFilter(filter, true /*removable*/, UserHandle.USER_OWNER,
+                            callingUserId);
+                }
+            } catch (RemoteException re) {
+                // Shouldn't happen
+            } finally {
+                restoreCallingIdentity(id);
+            }
+        }
+    }
+
+    public void clearForwardingIntentFilters(ComponentName who) {
+        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();
+            try {
+                pm.clearForwardingIntentFilters(callingUserId);
+                pm.clearForwardingIntentFilters(UserHandle.USER_OWNER);
+            } catch (RemoteException re) {
+                // Shouldn't happen
             } finally {
                 restoreCallingIdentity(id);
             }
@@ -3109,10 +3318,9 @@
             }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-            UserManager um = UserManager.get(mContext);
             long id = Binder.clearCallingIdentity();
             try {
-                return um.getApplicationRestrictions(packageName, userHandle);
+                return mUserManager.getApplicationRestrictions(packageName, userHandle);
             } finally {
                 restoreCallingIdentity(id);
             }
@@ -3129,13 +3337,225 @@
             }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-            UserManager um = UserManager.get(mContext);
             long id = Binder.clearCallingIdentity();
             try {
-                um.setUserRestriction(key, enabled, userHandle);
+                mUserManager.setUserRestriction(key, enabled, userHandle);
             } finally {
                 restoreCallingIdentity(id);
             }
         }
     }
+
+    @Override
+    public void enableSystemApp(ComponentName who, String packageName) {
+        synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+            int userId = UserHandle.getCallingUserId();
+            long id = Binder.clearCallingIdentity();
+
+            try {
+                UserManager um = UserManager.get(mContext);
+                if (!um.getUserInfo(userId).isManagedProfile()) {
+                    throw new IllegalStateException(
+                            "Only call this method from a managed profile.");
+                }
+
+                // TODO: Use UserManager::getProfileParent when available.
+                UserInfo primaryUser = um.getUserInfo(UserHandle.USER_OWNER);
+
+                if (DBG) {
+                    Slog.v(LOG_TAG, "installing " + packageName + " for "
+                            + userId);
+                }
+
+                IPackageManager pm = AppGlobals.getPackageManager();
+                if (!isSystemApp(pm, packageName, primaryUser.id)) {
+                    throw new IllegalArgumentException("Only system apps can be enabled this way.");
+                }
+
+                // Install the app.
+                pm.installExistingPackageAsUser(packageName, userId);
+
+            } catch (RemoteException re) {
+                // shouldn't happen
+                Slog.wtf(LOG_TAG, "Failed to install " + packageName, re);
+            } finally {
+                restoreCallingIdentity(id);
+            }
+        }
+    }
+
+    @Override
+    public int enableSystemAppWithIntent(ComponentName who, Intent intent) {
+        synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+            int userId = UserHandle.getCallingUserId();
+            long id = Binder.clearCallingIdentity();
+
+            try {
+                UserManager um = UserManager.get(mContext);
+                if (!um.getUserInfo(userId).isManagedProfile()) {
+                    throw new IllegalStateException(
+                            "Only call this method from a managed profile.");
+                }
+
+                // TODO: Use UserManager::getProfileParent when available.
+                UserInfo primaryUser = um.getUserInfo(UserHandle.USER_OWNER);
+
+                IPackageManager pm = AppGlobals.getPackageManager();
+                List<ResolveInfo> activitiesToEnable = pm.queryIntentActivities(intent,
+                        intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+                        0, // no flags
+                        primaryUser.id);
+
+                if (DBG) Slog.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable);
+                int numberOfAppsInstalled = 0;
+                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.");
+                            }
+
+
+                            numberOfAppsInstalled++;
+                            pm.installExistingPackageAsUser(info.activityInfo.packageName, userId);
+                        }
+                    }
+                }
+                return numberOfAppsInstalled;
+            } catch (RemoteException e) {
+                // shouldn't happen
+                Slog.wtf(LOG_TAG, "Failed to resolve intent for: " + intent);
+                return 0;
+            } finally {
+                restoreCallingIdentity(id);
+            }
+        }
+    }
+
+    private boolean isSystemApp(IPackageManager pm, String packageName, int userId)
+            throws RemoteException {
+        ApplicationInfo appInfo = pm.getApplicationInfo(packageName, 0, userId);
+        return (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) > 0;
+    }
+
+    @Override
+    public void setAccountManagementDisabled(ComponentName who, String accountType,
+            boolean disabled) {
+        if (!mHasFeature) {
+            return;
+        }
+        synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            if (disabled) {
+                ap.accountTypesWithManagementDisabled.add(accountType);
+            } else {
+                ap.accountTypesWithManagementDisabled.remove(accountType);
+            }
+            saveSettingsLocked(UserHandle.getCallingUserId());
+        }
+    }
+
+    @Override
+    public String[] getAccountTypesWithManagementDisabled() {
+        if (!mHasFeature) {
+            return null;
+        }
+        synchronized (this) {
+            DevicePolicyData policy = getUserData(UserHandle.getCallingUserId());
+            final int N = policy.mAdminList.size();
+            HashSet<String> resultSet = new HashSet<String>();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = policy.mAdminList.get(i);
+                resultSet.addAll(admin.accountTypesWithManagementDisabled);
+            }
+            return resultSet.toArray(new String[resultSet.size()]);
+        }
+    }
+
+    /**
+     * Sets which componets may enter lock task mode.
+     *
+     * This function can only be called by the device owner or the profile owner.
+     * @param components The list of components allowed to enter lock task mode.
+     */
+    public void setLockTaskComponents(ComponentName[] components) throws SecurityException {
+        // Get the package names of the caller.
+        int uid = Binder.getCallingUid();
+        String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
+
+        // Check whether any of the package name is the device owner or the profile owner.
+        for (int i=0; i<packageNames.length; i++) {
+            String packageName = packageNames[i];
+            int userHandle = UserHandle.getUserId(uid);
+            String profileOwnerPackage = getProfileOwner(userHandle);
+            if (isDeviceOwner(packageName) ||
+                (profileOwnerPackage != null && profileOwnerPackage.equals(packageName))) {
+
+                // If a package name is the device owner or the profile owner,
+                // we update the component list.
+                DevicePolicyData policy = getUserData(userHandle);
+                policy.mLockTaskComponents.clear();
+                if (components != null) {
+                    for (int j=0; j<components.length; j++) {
+                        ComponentName component = components[j];
+                        policy.mLockTaskComponents.add(component);
+                    }
+                }
+
+                // Store the settings persistently.
+                saveSettingsLocked(userHandle);
+                return;
+            }
+        }
+        throw new SecurityException();
+    }
+
+    /**
+     * This function returns the list of components allowed to start the task lock mode.
+     */
+    public ComponentName[] getLockTaskComponents() {
+        int userHandle = UserHandle.USER_OWNER;
+        DevicePolicyData policy = getUserData(userHandle);
+        ComponentName[] tempArray = policy.mLockTaskComponents.toArray(new ComponentName[0]);
+        return tempArray;
+    }
+
+    /**
+     * This function lets the caller know whether the given component is allowed to start the
+     * lock task mode.
+     * @param component The component to check
+     */
+    public boolean isLockTaskPermitted(ComponentName component) {
+        // Get current user's devicepolicy
+        int uid = Binder.getCallingUid();
+        int userHandle = UserHandle.getUserId(uid);
+        DevicePolicyData policy = getUserData(userHandle);
+        for (int i=0; i<policy.mLockTaskComponents.size(); i++) {
+            ComponentName lockTaskComponent = policy.mLockTaskComponents.get(i);
+
+            // If the given component equals one of the component stored our device-owner-set
+            // list, we allow this component to start the lock task mode.
+            if (lockTaskComponent.getPackageName().equals(component.getPackageName())) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3d82027..22e2a6e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -73,6 +73,7 @@
 import com.android.server.net.NetworkStatsService;
 import com.android.server.notification.NotificationManagerService;
 import com.android.server.os.SchedulingPolicyService;
+import com.android.server.pm.BackgroundDexOptService;
 import com.android.server.pm.Installer;
 import com.android.server.pm.LauncherAppsService;
 import com.android.server.pm.PackageManagerService;
@@ -333,6 +334,7 @@
         InputManagerService inputManager = null;
         TelephonyRegistry telephonyRegistry = null;
         ConsumerIrService consumerIr = null;
+        AudioService audioService = null;
 
         boolean onlyCore = false;
         boolean firstBoot = false;
@@ -604,6 +606,14 @@
 
             if (!disableNetwork) {
                 try {
+                    Slog.i(TAG, "Network Score Service");
+                    networkScore = new NetworkScoreService(context);
+                    ServiceManager.addService(Context.NETWORK_SCORE_SERVICE, networkScore);
+                } catch (Throwable e) {
+                    reportWtf("starting Network Score Service", e);
+                }
+
+                try {
                     Slog.i(TAG, "NetworkStats Service");
                     networkStats = new NetworkStatsService(context, networkManagement, alarm);
                     ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
@@ -641,6 +651,15 @@
                 }
 
                 try {
+                    Slog.i(TAG, "Wi-Fi Scanning Service");
+                    mSystemServiceManager.startService(
+                            "com.android.server.wifi.WifiScanningService");
+
+                } catch (Throwable e) {
+                    reportWtf("starting Wi-Fi Scanning Service", e);
+                }
+
+                try {
                     Slog.i(TAG, "Connectivity Service");
                     connectivity = new ConnectivityService(
                             context, networkManagement, networkStats, networkPolicy);
@@ -652,14 +671,6 @@
                 }
 
                 try {
-                    Slog.i(TAG, "Network Score Service");
-                    networkScore = new NetworkScoreService(context);
-                    ServiceManager.addService(Context.NETWORK_SCORE_SERVICE, networkScore);
-                } catch (Throwable e) {
-                    reportWtf("starting Network Score Service", e);
-                }
-
-                try {
                     Slog.i(TAG, "Network Service Discovery Service");
                     serviceDiscovery = NsdService.create(context);
                     ServiceManager.addService(
@@ -759,7 +770,8 @@
             if (!disableMedia && !"0".equals(SystemProperties.get("system_init.startaudioservice"))) {
                 try {
                     Slog.i(TAG, "Audio Service");
-                    ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context));
+                    audioService = new AudioService(context);
+                    ServiceManager.addService(Context.AUDIO_SERVICE, audioService);
                 } catch (Throwable e) {
                     reportWtf("starting Audio Service", e);
                 }
@@ -923,7 +935,6 @@
             }
 
             try {
-                Slog.i(TAG, "MediaSessionService");
                 mSystemServiceManager.startService(MediaSessionService.class);
             } catch (Throwable e) {
                 reportWtf("starting MediaSessionService", e);
@@ -963,6 +974,13 @@
                 } catch (Throwable e) {
                     Slog.e(TAG, "Failure starting TrustManagerService", e);
                 }
+
+                try {
+                    Slog.i(TAG, "BackgroundDexOptService");
+                    new BackgroundDexOptService(context);
+                } catch (Throwable e) {
+                    reportWtf("starting BackgroundDexOptService", e);
+                }
             }
 
             try {
@@ -1068,6 +1086,7 @@
         final InputManagerService inputManagerF = inputManager;
         final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
         final MediaRouterService mediaRouterF = mediaRouter;
+        final AudioService audioServiceF = audioService;
 
         // We now tell the activity manager it is okay to run third party
         // code.  It will call back into us once it has gotten to the state
@@ -1136,6 +1155,11 @@
                 } catch (Throwable e) {
                     reportWtf("making Recognition Service ready", e);
                 }
+                try {
+                    if (audioServiceF != null) audioServiceF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("Notifying AudioService running", e);
+                }
                 Watchdog.getInstance().start();
 
                 // It is now okay to let the various system services start their
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index f7bec6e..39f228f 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -28,6 +28,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Binder;
@@ -35,6 +36,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.print.IPrintDocumentAdapter;
 import android.print.IPrintJobStateChangeListener;
 import android.print.IPrintManager;
@@ -91,18 +93,23 @@
         private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME =
                 "EXTRA_PRINT_SERVICE_COMPONENT_NAME";
 
+        private static final int BACKGROUND_USER_ID = -10;
+
         private final Object mLock = new Object();
 
         private final Context mContext;
 
+        private final UserManager mUserManager;
+
         private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
 
         private int mCurrentUserId = UserHandle.USER_OWNER;
 
         PrintManagerImpl(Context context) {
             mContext = context;
+            mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
             registerContentObservers();
-            registerBoradcastReceivers();
+            registerBroadcastReceivers();
         }
 
         public void systemRunning() {
@@ -125,11 +132,17 @@
         @Override
         public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
                 PrintAttributes attributes, String packageName, int appId, int userId) {
-            final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-            String resolvedPackageName = resolveCallingPackageNameEnforcingSecurity(packageName);
+            final int resolvedAppId;
             final UserState userState;
+            final String resolvedPackageName;
             synchronized (mLock) {
+                // Only the current group members can start new print jobs.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+                    return null;
+                }
+                resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+                resolvedPackageName = resolveCallingPackageNameEnforcingSecurity(packageName);
                 userState = getOrCreateUserStateLocked(resolvedUserId);
             }
             final long identity = Binder.clearCallingIdentity();
@@ -143,10 +156,15 @@
 
         @Override
         public List<PrintJobInfo> getPrintJobInfos(int appId, int userId) {
-            final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final int resolvedAppId;
             final UserState userState;
             synchronized (mLock) {
+                // Only the current group members can query for state of print jobs.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+                    return null;
+                }
+                resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
                 userState = getOrCreateUserStateLocked(resolvedUserId);
             }
             final long identity = Binder.clearCallingIdentity();
@@ -159,10 +177,15 @@
 
         @Override
         public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) {
-            final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final int resolvedAppId;
             final UserState userState;
             synchronized (mLock) {
+                // Only the current group members can query for state of a print job.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+                    return null;
+                }
+                resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
                 userState = getOrCreateUserStateLocked(resolvedUserId);
             }
             final long identity = Binder.clearCallingIdentity();
@@ -175,10 +198,15 @@
 
         @Override
         public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
-            final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final int resolvedAppId;
             final UserState userState;
             synchronized (mLock) {
+                // Only the current group members can cancel a print job.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+                    return;
+                }
+                resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
                 userState = getOrCreateUserStateLocked(resolvedUserId);
             }
             final long identity = Binder.clearCallingIdentity();
@@ -191,10 +219,15 @@
 
         @Override
         public void restartPrintJob(PrintJobId printJobId, int appId, int userId) {
-            final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final int resolvedAppId;
             final UserState userState;
             synchronized (mLock) {
+                // Only the current group members can restart a print job.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+                    return;
+                }
+                resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
                 userState = getOrCreateUserStateLocked(resolvedUserId);
             }
             final long identity = Binder.clearCallingIdentity();
@@ -210,6 +243,10 @@
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
+                // Only the current group members can get enabled services.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+                    return null;
+                }
                 userState = getOrCreateUserStateLocked(resolvedUserId);
             }
             final long identity = Binder.clearCallingIdentity();
@@ -225,6 +262,10 @@
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
+                // Only the current group members can get installed services.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+                    return null;
+                }
                 userState = getOrCreateUserStateLocked(resolvedUserId);
             }
             final long identity = Binder.clearCallingIdentity();
@@ -241,6 +282,10 @@
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
+                // Only the current group members can create a discovery session.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+                    return;
+                }
                 userState = getOrCreateUserStateLocked(resolvedUserId);
             }
             final long identity = Binder.clearCallingIdentity();
@@ -257,6 +302,10 @@
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
+                // Only the current group members can destroy a discovery session.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+                    return;
+                }
                 userState = getOrCreateUserStateLocked(resolvedUserId);
             }
             final long identity = Binder.clearCallingIdentity();
@@ -273,6 +322,10 @@
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
+                // Only the current group members can start discovery.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+                    return;
+                }
                 userState = getOrCreateUserStateLocked(resolvedUserId);
             }
             final long identity = Binder.clearCallingIdentity();
@@ -288,6 +341,10 @@
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
+                // Only the current group members can stop discovery.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+                    return;
+                }
                 userState = getOrCreateUserStateLocked(resolvedUserId);
             }
             final long identity = Binder.clearCallingIdentity();
@@ -303,6 +360,10 @@
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
+                // Only the current group members can validate printers.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+                    return;
+                }
                 userState = getOrCreateUserStateLocked(resolvedUserId);
             }
             final long identity = Binder.clearCallingIdentity();
@@ -318,6 +379,10 @@
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
+                // Only the current group members can start printer tracking.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+                    return;
+                }
                 userState = getOrCreateUserStateLocked(resolvedUserId);
             }
             final long identity = Binder.clearCallingIdentity();
@@ -333,6 +398,10 @@
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
+                // Only the current group members can stop printer tracking.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+                    return;
+                }
                 userState = getOrCreateUserStateLocked(resolvedUserId);
             }
             final long identity = Binder.clearCallingIdentity();
@@ -347,9 +416,14 @@
         public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
                 int appId, int userId) throws RemoteException {
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-            final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+            final int resolvedAppId;
             final UserState userState;
             synchronized (mLock) {
+                // Only the current group members can add a print job listener.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+                    return;
+                }
+                resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
                 userState = getOrCreateUserStateLocked(resolvedUserId);
             }
             final long identity = Binder.clearCallingIdentity();
@@ -366,6 +440,10 @@
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
+                // Only the current group members can remove a print job listener.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+                    return;
+                }
                 userState = getOrCreateUserStateLocked(resolvedUserId);
             }
             final long identity = Binder.clearCallingIdentity();
@@ -421,11 +499,14 @@
                     false, observer, UserHandle.USER_ALL);
         }
 
-        private void registerBoradcastReceivers() {
+        private void registerBroadcastReceivers() {
             PackageMonitor monitor = new PackageMonitor() {
                 @Override
                 public void onPackageModified(String packageName) {
                     synchronized (mLock) {
+                        // A background user/profile's print jobs are running but there is
+                        // no UI shown. Hence, if the packages of such a user change we need
+                        // to handle it as the change may affect ongoing print jobs.
                         boolean servicesChanged = false;
                         UserState userState = getOrCreateUserStateLocked(getChangingUserId());
                         Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
@@ -444,6 +525,9 @@
                 @Override
                 public void onPackageRemoved(String packageName, int uid) {
                     synchronized (mLock) {
+                        // A background user/profile's print jobs are running but there is
+                        // no UI shown. Hence, if the packages of such a user change we need
+                        // to handle it as the change may affect ongoing print jobs.
                         boolean servicesRemoved = false;
                         UserState userState = getOrCreateUserStateLocked(getChangingUserId());
                         Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
@@ -467,6 +551,9 @@
                 public boolean onHandleForceStop(Intent intent, String[] stoppedPackages,
                         int uid, boolean doit) {
                     synchronized (mLock) {
+                        // A background user/profile's print jobs are running but there is
+                        // no UI shown. Hence, if the packages of such a user change we need
+                        // to handle it as the change may affect ongoing print jobs.
                         UserState userState = getOrCreateUserStateLocked(getChangingUserId());
                         boolean stoppedSomePackages = false;
                         Iterator<ComponentName> iterator = userState.getEnabledServices()
@@ -493,6 +580,9 @@
 
                 @Override
                 public void onPackageAdded(String packageName, int uid) {
+                    // A background user/profile's print jobs are running but there is
+                    // no UI shown. Hence, if the packages of such a user change we need
+                    // to handle it as the change may affect ongoing print jobs.
                     Intent intent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
                     intent.setPackage(packageName);
 
@@ -596,6 +686,23 @@
             }
         }
 
+        private int resolveCallingProfileParentLocked(int userId) {
+            if (userId != mCurrentUserId) {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    UserInfo parent = mUserManager.getProfileParent(userId);
+                    if (parent != null) {
+                        return parent.getUserHandle().getIdentifier();
+                    } else {
+                        return BACKGROUND_USER_ID;
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+            return userId;
+        }
+
         private int resolveCallingAppEnforcingPermissions(int appId) {
             final int callingUid = Binder.getCallingUid();
             if (callingUid == 0 || callingUid == Process.SYSTEM_UID
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index f955f4f..88aaafc 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -163,9 +163,10 @@
         nextConnBroadcast.get();
 
         // verify that both routes were added and DNS was flushed
-        verify(mNetManager).addRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V4));
-        verify(mNetManager).addRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V6));
-        verify(mNetManager).flushInterfaceDnsCache(MOBILE_IFACE);
+        int mobileNetId = mMobile.tracker.getNetwork().netId;
+        verify(mNetManager).addRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V4));
+        verify(mNetManager).addRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V6));
+        verify(mNetManager).flushNetworkDnsCache(mobileNetId);
 
     }
 
@@ -200,11 +201,14 @@
         nextConnBroadcast.get();
 
         // verify that wifi routes added, and teardown requested
-        verify(mNetManager).addRoute(eq(WIFI_IFACE), eq(WIFI_ROUTE_V4));
-        verify(mNetManager).addRoute(eq(WIFI_IFACE), eq(WIFI_ROUTE_V6));
-        verify(mNetManager).flushInterfaceDnsCache(WIFI_IFACE);
+        int wifiNetId = mWifi.tracker.getNetwork().netId;
+        verify(mNetManager).addRoute(eq(wifiNetId), eq(WIFI_ROUTE_V4));
+        verify(mNetManager).addRoute(eq(wifiNetId), eq(WIFI_ROUTE_V6));
+        verify(mNetManager).flushNetworkDnsCache(wifiNetId);
         verify(mMobile.tracker).teardown();
 
+        int mobileNetId = mMobile.tracker.getNetwork().netId;
+
         reset(mNetManager, mMobile.tracker);
 
         // tear down mobile network, as requested
@@ -216,8 +220,8 @@
         mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget();
         nextConnBroadcast.get();
 
-        verify(mNetManager).removeRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V4));
-        verify(mNetManager).removeRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V6));
+        verify(mNetManager).removeRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V4));
+        verify(mNetManager).removeRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V6));
 
     }
 
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index f5ac178..6822ee3 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -373,8 +373,9 @@
                 mUEventObserver.startObserving(USB_STATE_MATCH);
                 mUEventObserver.startObserving(ACCESSORY_START_MATCH);
 
-                mContext.registerReceiver(
-                        mBootCompletedReceiver, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+                IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
+                filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+                mContext.registerReceiver(mBootCompletedReceiver, filter);
                 mContext.registerReceiver(
                         mUserSwitchedReceiver, new IntentFilter(Intent.ACTION_USER_SWITCHED));
             } catch (Exception e) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 045c0f6..16afc8f 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -28,6 +28,8 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.voice.IVoiceInteractionService;
@@ -88,6 +90,21 @@
         private boolean mSafeMode;
         private int mCurUser;
 
+        @Override
+        public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+                throws RemoteException {
+            try {
+                return super.onTransact(code, data, reply, flags);
+            } catch (RuntimeException e) {
+                // The activity manager only throws security exceptions, so let's
+                // log all others.
+                if (!(e instanceof SecurityException)) {
+                    Slog.wtf(TAG, "VoiceInteractionManagerService Crash", e);
+                }
+                throw e;
+            }
+        }
+
         public void systemRunning(boolean safeMode) {
             mSafeMode = safeMode;
 
@@ -97,18 +114,18 @@
 
             synchronized (this) {
                 mCurUser = ActivityManager.getCurrentUser();
-                switchImplementationIfNeededLocked();
+                switchImplementationIfNeededLocked(false);
             }
         }
 
         public void switchUser(int userHandle) {
             synchronized (this) {
                 mCurUser = userHandle;
-                switchImplementationIfNeededLocked();
+                switchImplementationIfNeededLocked(false);
             }
         }
 
-        void switchImplementationIfNeededLocked() {
+        void switchImplementationIfNeededLocked(boolean force) {
             if (!mSafeMode) {
                 String curService = Settings.Secure.getStringForUser(
                         mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser);
@@ -121,7 +138,7 @@
                         serviceComponent = null;
                     }
                 }
-                if (mImpl == null || mImpl.mUser != mCurUser
+                if (force || mImpl == null || mImpl.mUser != mCurUser
                         || !mImpl.mComponent.equals(serviceComponent)) {
                     if (mImpl != null) {
                         mImpl.shutdownLocked();
@@ -138,10 +155,10 @@
         }
 
         @Override
-        public void startVoiceActivity(Intent intent, String resolvedType,
-                IVoiceInteractionService service, Bundle args) {
+        public void startSession(IVoiceInteractionService service, Bundle args) {
             synchronized (this) {
-                if (mImpl == null || service.asBinder() != mImpl.mService.asBinder()) {
+                if (mImpl == null || mImpl.mService == null
+                        || service.asBinder() != mImpl.mService.asBinder()) {
                     throw new SecurityException(
                             "Caller is not the current voice interaction service");
                 }
@@ -149,8 +166,7 @@
                 final int callingUid = Binder.getCallingUid();
                 final long caller = Binder.clearCallingIdentity();
                 try {
-                    mImpl.startVoiceActivityLocked(callingPid, callingUid,
-                            intent, resolvedType, args);
+                    mImpl.startSessionLocked(callingPid, callingUid, args);
                 } finally {
                     Binder.restoreCallingIdentity(caller);
                 }
@@ -158,12 +174,12 @@
         }
 
         @Override
-        public int deliverNewSession(IBinder token, IVoiceInteractionSession session,
+        public boolean deliverNewSession(IBinder token, IVoiceInteractionSession session,
                 IVoiceInteractor interactor) {
             synchronized (this) {
                 if (mImpl == null) {
-                    Slog.w(TAG, "deliverNewSession without running voice interaction service");
-                    return ActivityManager.START_CANCELED;
+                    throw new SecurityException(
+                            "deliverNewSession without running voice interaction service");
                 }
                 final int callingPid = Binder.getCallingPid();
                 final int callingUid = Binder.getCallingUid();
@@ -175,7 +191,43 @@
                     Binder.restoreCallingIdentity(caller);
                 }
             }
+        }
 
+        @Override
+        public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) {
+            synchronized (this) {
+                if (mImpl == null) {
+                    Slog.w(TAG, "startVoiceActivity without running voice interaction service");
+                    return ActivityManager.START_CANCELED;
+                }
+                final int callingPid = Binder.getCallingPid();
+                final int callingUid = Binder.getCallingUid();
+                final long caller = Binder.clearCallingIdentity();
+                try {
+                    return mImpl.startVoiceActivityLocked(callingPid, callingUid, token,
+                            intent, resolvedType);
+                } finally {
+                    Binder.restoreCallingIdentity(caller);
+                }
+            }
+        }
+
+        @Override
+        public void finish(IBinder token) {
+            synchronized (this) {
+                if (mImpl == null) {
+                    Slog.w(TAG, "finish without running voice interaction service");
+                    return;
+                }
+                final int callingPid = Binder.getCallingPid();
+                final int callingUid = Binder.getCallingUid();
+                final long caller = Binder.clearCallingIdentity();
+                try {
+                    mImpl.finishLocked(callingPid, callingUid, token);
+                } finally {
+                    Binder.restoreCallingIdentity(caller);
+                }
+            }
         }
 
         @Override
@@ -207,7 +259,7 @@
 
             @Override public void onChange(boolean selfChange) {
                 synchronized (VoiceInteractionManagerServiceStub.this) {
-                    switchImplementationIfNeededLocked();
+                    switchImplementationIfNeededLocked(false);
                 }
             }
         }
@@ -220,27 +272,25 @@
 
             @Override
             public void onHandleUserStop(Intent intent, int userHandle) {
-                super.onHandleUserStop(intent, userHandle);
             }
 
             @Override
             public void onPackageDisappeared(String packageName, int reason) {
-                super.onPackageDisappeared(packageName, reason);
             }
 
             @Override
             public void onPackageAppeared(String packageName, int reason) {
-                super.onPackageAppeared(packageName, reason);
+                if (mImpl != null && packageName.equals(mImpl.mComponent.getPackageName())) {
+                    switchImplementationIfNeededLocked(true);
+                }
             }
 
             @Override
             public void onPackageModified(String packageName) {
-                super.onPackageModified(packageName);
             }
 
             @Override
             public void onSomePackagesChanged() {
-                super.onSomePackagesChanged();
             }
         };
     }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 6bbd1c1..9b6daad 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -19,9 +19,11 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
@@ -30,6 +32,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.service.voice.IVoiceInteractionService;
 import android.service.voice.IVoiceInteractionSession;
@@ -37,6 +40,8 @@
 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;
@@ -55,11 +60,28 @@
     final IActivityManager mAm;
     final VoiceInteractionServiceInfo mInfo;
     final ComponentName mSessionComponentName;
+    final IWindowManager mIWindowManager;
     boolean mBound = false;
     IVoiceInteractionService mService;
 
     SessionConnection mActiveSession;
 
+    final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+                synchronized (mLock) {
+                    if (mActiveSession != null && mActiveSession.mSession != null) {
+                        try {
+                            mActiveSession.mSession.closeSystemDialogs();
+                        } catch (RemoteException e) {
+                        }
+                    }
+                }
+            }
+        }
+    };
+
     final ServiceConnection mConnection = new ServiceConnection() {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
@@ -76,23 +98,26 @@
 
     final class SessionConnection implements ServiceConnection {
         final IBinder mToken = new Binder();
-        final Intent mIntent;
-        final String mResolvedType;
         final Bundle mArgs;
         boolean mBound;
         IVoiceInteractionSessionService mService;
         IVoiceInteractionSession mSession;
         IVoiceInteractor mInteractor;
 
-        SessionConnection(Intent intent, String resolvedType, Bundle args) {
-            mIntent = intent;
-            mResolvedType = resolvedType;
+        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) {
+            if (mBound) {
+                try {
+                    mIWindowManager.addWindowToken(mToken,
+                            WindowManager.LayoutParams.TYPE_INPUT_METHOD);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed adding window token", e);
+                }
+            } else {
                 Slog.w(TAG, "Failed binding to voice interaction session service " + mComponent);
             }
         }
@@ -105,7 +130,7 @@
                     try {
                         mService.newSession(mToken, mArgs);
                     } catch (RemoteException e) {
-                        Slog.w(TAG, "Failed making new session", e);
+                        Slog.w(TAG, "Failed adding window token", e);
                     }
                 }
             }
@@ -118,7 +143,19 @@
 
         public void cancel() {
             if (mBound) {
+                if (mSession != null) {
+                    try {
+                        mSession.destroy();
+                    } catch (RemoteException e) {
+                        Slog.w(TAG, "Voice interation session already dead");
+                    }
+                }
                 mContext.unbindService(this);
+                try {
+                    mIWindowManager.removeWindowToken(mToken);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed removing window token", e);
+                }
                 mBound = false;
                 mService = null;
                 mSession = null;
@@ -128,8 +165,6 @@
 
         public void dump(String prefix, PrintWriter pw) {
             pw.print(prefix); pw.print("mToken="); pw.println(mToken);
-            pw.print(prefix); pw.print("mIntent="); pw.println(mIntent);
-                    pw.print(" mResolvedType="); pw.println(mResolvedType);
             pw.print(prefix); pw.print("mArgs="); pw.println(mArgs);
             pw.print(prefix); pw.print("mBound="); pw.println(mBound);
             if (mBound) {
@@ -155,6 +190,7 @@
             Slog.w(TAG, "Voice interaction service not found: " + service);
             mInfo = null;
             mSessionComponentName = null;
+            mIWindowManager = null;
             mValid = false;
             return;
         }
@@ -162,43 +198,67 @@
         if (mInfo.getParseError() != null) {
             Slog.w(TAG, "Bad voice interaction service: " + mInfo.getParseError());
             mSessionComponentName = null;
+            mIWindowManager = null;
             mValid = false;
             return;
         }
         mValid = true;
         mSessionComponentName = new ComponentName(service.getPackageName(),
                 mInfo.getSessionService());
+        mIWindowManager = IWindowManager.Stub.asInterface(
+                ServiceManager.getService(Context.WINDOW_SERVICE));
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        mContext.registerReceiver(mBroadcastReceiver, filter, null, handler);
     }
 
-    public void startVoiceActivityLocked(int callingPid, int callingUid, Intent intent,
-            String resolvedType, Bundle args) {
+    public void startSessionLocked(int callingPid, int callingUid, Bundle args) {
         if (mActiveSession != null) {
             mActiveSession.cancel();
             mActiveSession = null;
         }
-        mActiveSession = new SessionConnection(intent, resolvedType, args);
-        intent.addCategory(Intent.CATEGORY_VOICE);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+        mActiveSession = new SessionConnection(args);
     }
 
-    public int deliverNewSessionLocked(int callingPid, int callingUid, IBinder token,
+    public boolean deliverNewSessionLocked(int callingPid, int callingUid, IBinder token,
             IVoiceInteractionSession session, IVoiceInteractor interactor) {
+        if (mActiveSession == null || token != mActiveSession.mToken) {
+            Slog.w(TAG, "deliverNewSession does not match active session");
+            return false;
+        }
+        mActiveSession.mSession = session;
+        mActiveSession.mInteractor = interactor;
+        return true;
+    }
+
+    public int startVoiceActivityLocked(int callingPid, int callingUid, IBinder token,
+            Intent intent, String resolvedType) {
         try {
             if (mActiveSession == null || token != mActiveSession.mToken) {
-                Slog.w(TAG, "deliverNewSession does not match active session");
+                Slog.w(TAG, "startVoiceActivity does not match active session");
                 return ActivityManager.START_CANCELED;
             }
-            mActiveSession.mSession = session;
-            mActiveSession.mInteractor = interactor;
+            intent = new Intent(intent);
+            intent.addCategory(Intent.CATEGORY_VOICE);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
             return mAm.startVoiceActivity(mComponent.getPackageName(), callingPid, callingUid,
-                    mActiveSession.mIntent, mActiveSession.mResolvedType,
-                    mActiveSession.mSession, mActiveSession.mInteractor,
+                    intent, resolvedType, mActiveSession.mSession, mActiveSession.mInteractor,
                     0, null, null, null, mUser);
         } catch (RemoteException e) {
             throw new IllegalStateException("Unexpected remote error", e);
         }
     }
 
+
+    public void finishLocked(int callingPid, int callingUid, IBinder token) {
+        if (mActiveSession == null || token != mActiveSession.mToken) {
+            Slog.w(TAG, "finish does not match active session");
+            return;
+        }
+        mActiveSession.cancel();
+        mActiveSession = null;
+    }
+
     public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!mValid) {
             pw.print("  NOT VALID: ");
@@ -234,5 +294,8 @@
             mContext.unbindService(mConnection);
             mBound = false;
         }
+        if (mValid) {
+            mContext.unregisterReceiver(mBroadcastReceiver);
+        }
     }
 }
diff --git a/telecomm/java/android/telecomm/CallAudioState.aidl b/telecomm/java/android/telecomm/CallAudioState.aidl
new file mode 100644
index 0000000..ae64567
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallAudioState.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.telecomm;
+
+parcelable CallAudioState;
diff --git a/telecomm/java/android/telecomm/CallAudioState.java b/telecomm/java/android/telecomm/CallAudioState.java
new file mode 100644
index 0000000..d9a0090
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallAudioState.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Locale;
+
+/**
+ *  Encapsulates all audio states during a call.
+ */
+public final class CallAudioState implements Parcelable {
+    /** Direct the audio stream through the device's earpiece. */
+    public static int ROUTE_EARPIECE      = 0x00000001;
+
+    /** Direct the audio stream through Bluetooth. */
+    public static int ROUTE_BLUETOOTH     = 0x00000002;
+
+    /** Direct the audio stream through a wired headset. */
+    public static int ROUTE_WIRED_HEADSET = 0x00000004;
+
+    /** Direct the audio stream through the device's spakerphone. */
+    public static int ROUTE_SPEAKER       = 0x00000008;
+
+    /**
+     * Direct the audio stream through the device's earpiece or wired headset if one is
+     * connected.
+     */
+    public static int ROUTE_WIRED_OR_EARPIECE = ROUTE_EARPIECE | ROUTE_WIRED_HEADSET;
+
+    /** Bit mask of all possible audio routes. */
+    public static int ROUTE_ALL = ROUTE_EARPIECE | ROUTE_BLUETOOTH | ROUTE_WIRED_HEADSET |
+            ROUTE_SPEAKER;
+
+    /** True if the call is muted, false otherwise. */
+    public final boolean isMuted;
+
+    /** The route to use for the audio stream. */
+    public final int route;
+
+    /** Bit vector of all routes supported by this call. */
+    public final int supportedRouteMask;
+
+    /** @hide */
+    public CallAudioState(boolean isMuted, int route, int supportedRouteMask) {
+        this.isMuted = isMuted;
+        this.route = route;
+        this.supportedRouteMask = supportedRouteMask;
+    }
+
+    /** @hide */
+    public CallAudioState(CallAudioState state) {
+        isMuted = state.isMuted;
+        route = state.route;
+        supportedRouteMask = state.supportedRouteMask;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof CallAudioState)) {
+            return false;
+        }
+        CallAudioState state = (CallAudioState) obj;
+        return isMuted == state.isMuted && route == state.route &&
+                supportedRouteMask == state.supportedRouteMask;
+    }
+
+    @Override
+    public String toString() {
+        return String.format(Locale.US,
+                "[CallAudioState isMuted: %b, route; %s, supportedRouteMask: %s]",
+                isMuted, audioRouteToString(route), audioRouteToString(supportedRouteMask));
+    }
+
+    /** @hide */
+    public static String audioRouteToString(int route) {
+        if (route == 0 || (route & ~ROUTE_ALL) != 0x0) {
+            return "UNKNOWN";
+        }
+
+        StringBuffer buffer = new StringBuffer();
+        if ((route & ROUTE_EARPIECE) == ROUTE_EARPIECE) {
+            listAppend(buffer, "EARPIECE");
+        }
+        if ((route & ROUTE_BLUETOOTH) == ROUTE_BLUETOOTH) {
+            listAppend(buffer, "BLUETOOTH");
+        }
+        if ((route & ROUTE_WIRED_HEADSET) == ROUTE_WIRED_HEADSET) {
+            listAppend(buffer, "WIRED_HEADSET");
+        }
+        if ((route & ROUTE_SPEAKER) == ROUTE_SPEAKER) {
+            listAppend(buffer, "SPEAKER");
+        }
+
+        return buffer.toString();
+    }
+
+    private static void listAppend(StringBuffer buffer, String str) {
+        if (buffer.length() > 0) {
+            buffer.append(", ");
+        }
+        buffer.append(str);
+    }
+
+    /**
+     * Responsible for creating CallAudioState objects for deserialized Parcels.
+     */
+    public static final Parcelable.Creator<CallAudioState> CREATOR =
+            new Parcelable.Creator<CallAudioState> () {
+
+        @Override
+        public CallAudioState createFromParcel(Parcel source) {
+            boolean isMuted = source.readByte() == 0 ? false : true;
+            int route = source.readInt();
+            int supportedRouteMask = source.readInt();
+            return new CallAudioState(isMuted, route, supportedRouteMask);
+        }
+
+        @Override
+        public CallAudioState[] newArray(int size) {
+            return new CallAudioState[size];
+        }
+    };
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Writes CallAudioState object into a serializeable Parcel.
+     */
+    @Override
+    public void writeToParcel(Parcel destination, int flags) {
+        destination.writeByte((byte) (isMuted ? 1 : 0));
+        destination.writeInt(route);
+        destination.writeInt(supportedRouteMask);
+    }
+}
diff --git a/telecomm/java/android/telecomm/CallCapabilities.java b/telecomm/java/android/telecomm/CallCapabilities.java
new file mode 100644
index 0000000..b2b33a3
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallCapabilities.java
@@ -0,0 +1,50 @@
+/*
+ * 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.telecomm;
+
+/** Defines actions a call currently supports. */
+public class CallCapabilities {
+    /** Call can currently be put on hold or unheld. */
+    public static final int HOLD               = 0x00000001;
+
+    /** Call supports the hold feature. */
+    public static final int SUPPORT_HOLD       = 0x00000002;
+
+    /** Call can currently be merged. */
+    public static final int MERGE_CALLS        = 0x00000004;
+
+     /* Call can currently be swapped with another call. */
+    public static final int SWAP_CALLS         = 0x00000008;
+
+     /* Call currently supports adding another call to this one. */
+    public static final int ADD_CALL           = 0x00000010;
+
+     /* Call supports responding via text option. */
+    public static final int RESPOND_VIA_TEXT   = 0x00000020;
+
+     /* Call can be muted. */
+    public static final int MUTE               = 0x00000040;
+
+     /* Call supports generic conference mode. */
+    public static final int GENERIC_CONFERENCE = 0x00000080;
+
+     /* Call currently supports switch between connections. */
+    public static final int CONNECTION_HANDOFF = 0x00000100;
+
+    public static final int ALL = HOLD | SUPPORT_HOLD | MERGE_CALLS | SWAP_CALLS | ADD_CALL
+            | RESPOND_VIA_TEXT | MUTE | GENERIC_CONFERENCE | CONNECTION_HANDOFF;
+}
diff --git a/telecomm/java/android/telecomm/CallInfo.aidl b/telecomm/java/android/telecomm/CallInfo.aidl
new file mode 100644
index 0000000..bc5ef96
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+package android.telecomm;
+
+parcelable CallInfo;
diff --git a/telecomm/java/android/telecomm/CallInfo.java b/telecomm/java/android/telecomm/CallInfo.java
new file mode 100644
index 0000000..cb7f2dc
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallInfo.java
@@ -0,0 +1,186 @@
+/*
+ * 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.
+ */
+
+package android.telecomm;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Date;
+
+/**
+ * A parcelable holder class of Call information data. This class is intended for transfering call
+ * information from Telecomm to call services and thus is read-only.
+ * TODO(santoscordon): Need final public-facing comments in this file.
+ */
+public final class CallInfo implements Parcelable {
+
+    /**
+     * Unique identifier for the call.
+     */
+    private final String mId;
+
+    /**
+     * The state of the call.
+     */
+    private final CallState mState;
+
+    /**
+     * Endpoint to which the call is connected.
+     * This could be the dialed value for outgoing calls or the caller id of incoming calls.
+     */
+    private final Uri mHandle;
+
+    /**
+     * Gateway information for the call.
+     */
+    private final GatewayInfo mGatewayInfo;
+
+    /**
+     * Additional information that can be persisted. For example, extra handoff information can
+     * attached to a call using {@link CallServiceSelectorAdapter#setHandoffInfo(String,Uri,Bundle).
+     */
+    private final Bundle mExtras;
+
+    /** The descriptor for the call service currently routing this call. */
+    private final CallServiceDescriptor mCurrentCallServiceDescriptor;
+
+    public CallInfo(String id, CallState state, Uri handle) {
+        this(id, state, handle, null, Bundle.EMPTY, null);
+    }
+
+    /**
+     * Persists handle of the other party of this call.
+     *
+     * @param id The unique ID of the call.
+     * @param state The state of the call.
+     * @param handle The handle to the other party in this call.
+     * @param gatewayInfo Gateway information pertaining to this call.
+     * @param extras Additional information that can be persisted.
+     * @param currentCallServiceDescriptor The descriptor for the call service currently routing
+     *         this call.
+     *
+     * @hide
+     */
+    public CallInfo(
+            String id,
+            CallState state,
+            Uri handle,
+            GatewayInfo gatewayInfo,
+            Bundle extras,
+            CallServiceDescriptor currentCallServiceDescriptor) {
+        mId = id;
+        mState = state;
+        mHandle = handle;
+        mGatewayInfo = gatewayInfo;
+        mExtras = extras;
+        mCurrentCallServiceDescriptor = currentCallServiceDescriptor;
+    }
+
+    public String getId() {
+        return mId;
+    }
+
+    public CallState getState() {
+        return mState;
+    }
+
+    public Uri getHandle() {
+        return mHandle;
+    }
+
+    /**
+     * @return The actual handle this call is associated with. This is used by call services to
+     * correctly indicate in their UI what handle the user is actually calling, and by other
+     * telecomm components that require the user-dialed handle to function.
+     */
+    public Uri getOriginalHandle() {
+        if (mGatewayInfo != null) {
+            return mGatewayInfo.getOriginalHandle();
+        }
+        return getHandle();
+    }
+
+    public GatewayInfo getGatewayInfo() {
+        return mGatewayInfo;
+    }
+
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    public CallServiceDescriptor getCurrentCallServiceDescriptor() {
+        return mCurrentCallServiceDescriptor;
+    }
+
+    /**
+     * Responsible for creating CallInfo objects for deserialized Parcels.
+     */
+    public static final Parcelable.Creator<CallInfo> CREATOR = new Parcelable.Creator<CallInfo> () {
+        @Override
+        public CallInfo createFromParcel(Parcel source) {
+            String id = source.readString();
+            CallState state = CallState.valueOf(source.readString());
+            Uri handle = Uri.CREATOR.createFromParcel(source);
+
+            boolean gatewayInfoPresent = source.readByte() != 0;
+            GatewayInfo gatewayInfo = null;
+            if (gatewayInfoPresent) {
+                gatewayInfo = GatewayInfo.CREATOR.createFromParcel(source);
+            }
+
+            ClassLoader classLoader = CallInfo.class.getClassLoader();
+            Bundle extras = source.readParcelable(classLoader);
+            CallServiceDescriptor descriptor = source.readParcelable(classLoader);
+            return new CallInfo(id, state, handle, gatewayInfo, extras, descriptor);
+        }
+
+        @Override
+        public CallInfo[] newArray(int size) {
+            return new CallInfo[size];
+        }
+    };
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Writes CallInfo object into a serializeable Parcel.
+     */
+    @Override
+    public void writeToParcel(Parcel destination, int flags) {
+        destination.writeString(mId);
+        destination.writeString(mState.name());
+        mHandle.writeToParcel(destination, 0);
+
+        if (mGatewayInfo != null) {
+            destination.writeByte((byte) 1);
+            mGatewayInfo.writeToParcel(destination, 0);
+        } else {
+            destination.writeByte((byte) 0);
+        }
+
+        destination.writeParcelable(mExtras, 0);
+        destination.writeParcelable(mCurrentCallServiceDescriptor, 0);
+    }
+}
diff --git a/telecomm/java/android/telecomm/CallNumberPresentation.java b/telecomm/java/android/telecomm/CallNumberPresentation.java
new file mode 100644
index 0000000..6cd22f8
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallNumberPresentation.java
@@ -0,0 +1,32 @@
+/*
+ * 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.telecomm;
+
+/** Defines how numbers are displayed in caller id. */
+public enum CallNumberPresentation {
+    /** Number is displayed normally. */
+    ALLOWED,
+
+    /** Number was blocked. */
+    RESTRICTED,
+
+    /** Presentation was not specified or is unknown. */
+    UNKNOWN,
+
+    /** Number should be displayed as a pay phone. */
+    PAYPHONE
+}
diff --git a/telecomm/java/android/telecomm/CallService.java b/telecomm/java/android/telecomm/CallService.java
new file mode 100644
index 0000000..51f10c1
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallService.java
@@ -0,0 +1,362 @@
+/*
+ * 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.telecomm;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+
+import com.android.internal.os.SomeArgs;
+import com.android.internal.telecomm.ICallService;
+import com.android.internal.telecomm.ICallServiceAdapter;
+
+/**
+ * Base implementation of CallService which can be used to provide calls for the system
+ * in-call UI. CallService is a one-way service from the framework's CallsManager to any app
+ * that would like to provide calls managed by the default system in-call user interface.
+ * When the service is bound by the framework, CallsManager will call setCallServiceAdapter
+ * which will provide CallService with an instance of {@link CallServiceAdapter} to be used
+ * for communicating back to CallsManager. Subsequently, more specific methods of the service
+ * will be called to perform various call actions including making an outgoing call and
+ * disconnected existing calls.
+ * TODO(santoscordon): Needs more about AndroidManifest.xml service registrations before
+ * we can unhide this API.
+ *
+ * Most public methods of this function are backed by a one-way AIDL interface which precludes
+ * synchronous responses. As a result, most responses are handled by (or have TODOs to handle)
+ * response objects instead of return values.
+ * TODO(santoscordon): Improve paragraph above once the final design is in place.
+ */
+public abstract class CallService extends Service {
+
+    private static final int MSG_SET_CALL_SERVICE_ADAPTER = 1;
+    private static final int MSG_IS_COMPATIBLE_WITH = 2;
+    private static final int MSG_CALL = 3;
+    private static final int MSG_ABORT = 4;
+    private static final int MSG_SET_INCOMING_CALL_ID = 5;
+    private static final int MSG_ANSWER = 6;
+    private static final int MSG_REJECT = 7;
+    private static final int MSG_DISCONNECT = 8;
+    private static final int MSG_HOLD = 9;
+    private static final int MSG_UNHOLD = 10;
+    private static final int MSG_ON_AUDIO_STATE_CHANGED = 11;
+    private static final int MSG_PLAY_DTMF_TONE = 12;
+    private static final int MSG_STOP_DTMF_TONE = 13;
+
+    /**
+     * Default Handler used to consolidate binder method calls onto a single thread.
+     */
+    private final class CallServiceMessageHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_SET_CALL_SERVICE_ADAPTER:
+                    mAdapter = new CallServiceAdapter((ICallServiceAdapter) msg.obj);
+                    onAdapterAttached(mAdapter);
+                    break;
+                case MSG_IS_COMPATIBLE_WITH:
+                    isCompatibleWith((CallInfo) msg.obj);
+                    break;
+                case MSG_CALL:
+                    call((CallInfo) msg.obj);
+                    break;
+                case MSG_ABORT:
+                    abort((String) msg.obj);
+                    break;
+                case MSG_SET_INCOMING_CALL_ID: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        String callId = (String) args.arg1;
+                        Bundle extras = (Bundle) args.arg2;
+                        setIncomingCallId(callId, extras);
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
+                case MSG_ANSWER:
+                    answer((String) msg.obj);
+                    break;
+                case MSG_REJECT:
+                    reject((String) msg.obj);
+                    break;
+                case MSG_DISCONNECT:
+                    disconnect((String) msg.obj);
+                    break;
+                case MSG_HOLD:
+                    hold((String) msg.obj);
+                    break;
+                case MSG_UNHOLD:
+                    unhold((String) msg.obj);
+                    break;
+                case MSG_ON_AUDIO_STATE_CHANGED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        String callId = (String) args.arg1;
+                        CallAudioState audioState = (CallAudioState) args.arg2;
+                        onAudioStateChanged(callId, audioState);
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
+                case MSG_PLAY_DTMF_TONE:
+                    playDtmfTone((String) msg.obj, (char) msg.arg1);
+                    break;
+                case MSG_STOP_DTMF_TONE:
+                    stopDtmfTone((String) msg.obj);
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Default ICallService implementation provided to CallsManager via {@link #onBind}.
+     */
+    private final class CallServiceBinder extends ICallService.Stub {
+        @Override
+        public void setCallServiceAdapter(ICallServiceAdapter callServiceAdapter) {
+            mMessageHandler.obtainMessage(MSG_SET_CALL_SERVICE_ADAPTER, callServiceAdapter)
+                    .sendToTarget();
+        }
+
+        @Override
+        public void isCompatibleWith(CallInfo callInfo) {
+            mMessageHandler.obtainMessage(MSG_IS_COMPATIBLE_WITH, callInfo).sendToTarget();
+        }
+
+        @Override
+        public void call(CallInfo callInfo) {
+            mMessageHandler.obtainMessage(MSG_CALL, callInfo).sendToTarget();
+        }
+
+        @Override
+        public void abort(String callId) {
+            mMessageHandler.obtainMessage(MSG_ABORT, callId).sendToTarget();
+        }
+
+        @Override
+        public void setIncomingCallId(String callId, Bundle extras) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callId;
+            args.arg2 = extras;
+            mMessageHandler.obtainMessage(MSG_SET_INCOMING_CALL_ID, args).sendToTarget();
+        }
+
+        @Override
+        public void answer(String callId) {
+            mMessageHandler.obtainMessage(MSG_ANSWER, callId).sendToTarget();
+        }
+
+        @Override
+        public void reject(String callId) {
+            mMessageHandler.obtainMessage(MSG_REJECT, callId).sendToTarget();
+        }
+
+        @Override
+        public void disconnect(String callId) {
+            mMessageHandler.obtainMessage(MSG_DISCONNECT, callId).sendToTarget();
+        }
+
+        @Override
+        public void hold(String callId) {
+            mMessageHandler.obtainMessage(MSG_HOLD, callId).sendToTarget();
+        }
+
+        @Override
+        public void unhold(String callId) {
+            mMessageHandler.obtainMessage(MSG_UNHOLD, callId).sendToTarget();
+        }
+
+        @Override
+        public void playDtmfTone(String callId, char digit) {
+            mMessageHandler.obtainMessage(MSG_PLAY_DTMF_TONE, digit, 0, callId).sendToTarget();
+        }
+
+        @Override
+        public void stopDtmfTone(String callId) {
+            mMessageHandler.obtainMessage(MSG_STOP_DTMF_TONE, callId).sendToTarget();
+        }
+
+        @Override
+        public void onAudioStateChanged(String callId, CallAudioState audioState) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callId;
+            args.arg2 = audioState;
+            mMessageHandler.obtainMessage(MSG_ON_AUDIO_STATE_CHANGED, args).sendToTarget();
+        }
+    }
+
+    /**
+     * Message handler for consolidating binder callbacks onto a single thread.
+     * See {@link CallServiceMessageHandler}.
+     */
+    private final CallServiceMessageHandler mMessageHandler = new CallServiceMessageHandler();
+
+    /**
+     * Default binder implementation of {@link ICallService} interface.
+     */
+    private final CallServiceBinder mBinder = new CallServiceBinder();
+
+    private CallServiceAdapter mAdapter = null;
+
+    /** {@inheritDoc} */
+    @Override
+    public final IBinder onBind(Intent intent) {
+        return getBinder();
+    }
+
+    /**
+     * Returns binder object which can be used across IPC methods.
+     */
+    public final IBinder getBinder() {
+        return mBinder;
+    }
+
+    /**
+     * @return The attached {@link CallServiceAdapter} if the service is bound, null otherwise.
+     */
+    protected final CallServiceAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    /**
+     * Lifecycle callback which is called when this {@link CallService} has been attached to a
+     * {@link CallServiceAdapter}, indicating {@link #getAdapter()} is now safe to use.
+     *
+     * @param adapter The adapter now attached to this call service.
+     */
+    protected void onAdapterAttached(CallServiceAdapter adapter) {
+    }
+
+    /**
+     * Determines if the CallService can place the specified call. Response is sent via
+     * {@link CallServiceAdapter#setIsCompatibleWith}. When responding, the correct call ID must be
+     * specified.  Only used in the context of outgoing calls and call switching (handoff).
+     *
+     * @param callInfo The details of the relevant call.
+     */
+    public abstract void isCompatibleWith(CallInfo callInfo);
+
+    /**
+     * Attempts to call the relevant party using the specified call's handle, be it a phone number,
+     * SIP address, or some other kind of user ID.  Note that the set of handle types is
+     * dynamically extensible since call providers should be able to implement arbitrary
+     * handle-calling systems.  See {@link #isCompatibleWith}. It is expected that the
+     * call service respond via {@link CallServiceAdapter#handleSuccessfulOutgoingCall(String)}
+     * if it can successfully make the call.  Only used in the context of outgoing calls.
+     *
+     * @param callInfo The details of the relevant call.
+     */
+    public abstract void call(CallInfo callInfo);
+
+    /**
+     * Aborts the outgoing call attempt. Invoked in the unlikely event that Telecomm decides to
+     * abort an attempt to place a call.  Only ever be invoked after {@link #call} invocations.
+     * After this is invoked, Telecomm does not expect any more updates about the call and will
+     * actively ignore any such update. This is different from {@link #disconnect} where Telecomm
+     * expects confirmation via CallServiceAdapter.markCallAsDisconnected.
+     *
+     * @param callId The identifier of the call to abort.
+     */
+    public abstract void abort(String callId);
+
+    /**
+     * Receives a new call ID to use with an incoming call. Invoked by Telecomm after it is notified
+     * that this call service has a pending incoming call, see
+     * {@link TelecommConstants#ACTION_INCOMING_CALL}. The call service must first give Telecomm
+     * additional information about the call through {@link CallServiceAdapter#notifyIncomingCall}.
+     * Following that, the call service can update the call at will using the specified call ID.
+     *
+     * If a {@link Bundle} was passed (via {@link TelecommConstants#EXTRA_INCOMING_CALL_EXTRAS}) in
+     * with the {@link TelecommConstants#ACTION_INCOMING_CALL} intent, <code>extras</code> will be
+     * populated with this {@link Bundle}. Otherwise, an empty Bundle will be returned.
+     *
+     * @param callId The ID of the call.
+     * @param extras The optional extras which were passed in with the intent, or an empty Bundle.
+     */
+    public abstract void setIncomingCallId(String callId, Bundle extras);
+
+    /**
+     * Answers a ringing call identified by callId. Telecomm invokes this method as a result of the
+     * user hitting the "answer" button in the incoming call screen.
+     *
+     * @param callId The ID of the call.
+     */
+    public abstract void answer(String callId);
+
+    /**
+     * Rejects a ringing call identified by callId. Telecomm invokes this method as a result of the
+     * user hitting the "reject" button in the incoming call screen.
+     *
+     * @param callId The ID of the call.
+     */
+    public abstract void reject(String callId);
+
+    /**
+     * Disconnects the specified call.
+     *
+     * @param callId The ID of the call to disconnect.
+     */
+    public abstract void disconnect(String callId);
+
+    /**
+     * Puts the specified call on hold.
+     *
+     * @param callId The ID of the call to put on hold.
+     */
+    public abstract void hold(String callId);
+
+    /**
+     * Removes the specified call from hold.
+     *
+     * @param callId The ID of the call to unhold.
+     */
+    public abstract void unhold(String callId);
+
+    /**
+     * Plays a dual-tone multi-frequency signaling (DTMF) tone in a call.
+     *
+     * @param callId The unique ID of the call in which the tone will be played.
+     * @param digit A character representing the DTMF digit for which to play the tone. This
+     *         value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
+     */
+    public abstract void playDtmfTone(String callId, char digit);
+
+    /**
+     * Stops any dual-tone multi-frequency sinaling (DTMF) tone currently playing.
+     *
+     * DTMF tones are played by calling {@link #playDtmfTone(String,char)}. If no DTMF tone is
+     * currently playing, this method will do nothing.
+     *
+     * @param callId The unique ID of the call in which any currently playing tone will be stopped.
+     */
+    public abstract void stopDtmfTone(String callId);
+
+    /**
+     * Called when the audio state changes.
+     *
+     * @param activeCallId The identifier of the call that was active during the state change.
+     * @param audioState The new {@link CallAudioState}.
+     */
+    public abstract void onAudioStateChanged(String activeCallId, CallAudioState audioState);
+}
diff --git a/telecomm/java/android/telecomm/CallServiceAdapter.java b/telecomm/java/android/telecomm/CallServiceAdapter.java
new file mode 100644
index 0000000..d5bb989
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceAdapter.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.os.RemoteException;
+
+import com.android.internal.telecomm.ICallServiceAdapter;
+
+/**
+ * Provides methods for ICallService implementations to interact with the system phone app.
+ * TODO(santoscordon): Need final public-facing comments in this file.
+ */
+public final class CallServiceAdapter {
+    private final ICallServiceAdapter mAdapter;
+
+    /**
+     * {@hide}
+     */
+    public CallServiceAdapter(ICallServiceAdapter adapter) {
+        mAdapter = adapter;
+    }
+
+    /**
+     * Receives confirmation of a call service's ability to place a call. This method is used in
+     * response to {@link CallService#isCompatibleWith}.
+     *
+     * @param callId The identifier of the call for which compatibility is being received. This ID
+     *     should correspond to the ID given as part of the call information in
+     *     {@link CallService#isCompatibleWith}.
+     * @param isCompatible True if the call service can place the call.
+     */
+    public void setIsCompatibleWith(String callId, boolean isCompatible) {
+        try {
+            mAdapter.setIsCompatibleWith(callId, isCompatible);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Provides Telecomm with the details of an incoming call. An invocation of this method must
+     * follow {@link CallService#setIncomingCallId} and use the call ID specified therein. Upon
+     * the invocation of this method, Telecomm will bring up the incoming-call interface where the
+     * user can elect to answer or reject a call.
+     *
+     * @param callInfo The details of the relevant call.
+     */
+    public void notifyIncomingCall(CallInfo callInfo) {
+        try {
+            mAdapter.notifyIncomingCall(callInfo);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Tells Telecomm that an attempt to place the specified outgoing call succeeded.
+     * TODO(santoscordon): Consider adding a CallState parameter in case this outgoing call is
+     * somehow no longer in the DIALING state.
+     *
+     * @param callId The ID of the outgoing call.
+     */
+    public void handleSuccessfulOutgoingCall(String callId) {
+        try {
+            mAdapter.handleSuccessfulOutgoingCall(callId);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Tells Telecomm that an attempt to place the specified outgoing call failed.
+     *
+     * @param callId The ID of the outgoing call.
+     * @param errorMessage The error associated with the failed call attempt.
+     */
+    public void handleFailedOutgoingCall(String callId, String errorMessage) {
+        try {
+            mAdapter.handleFailedOutgoingCall(callId, errorMessage);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Sets a call's state to active (e.g., an ongoing call where two parties can actively
+     * communicate).
+     *
+     * @param callId The unique ID of the call whose state is changing to active.
+     */
+    public void setActive(String callId) {
+        try {
+            mAdapter.setActive(callId);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Sets a call's state to ringing (e.g., an inbound ringing call).
+     *
+     * @param callId The unique ID of the call whose state is changing to ringing.
+     */
+    public void setRinging(String callId) {
+        try {
+            mAdapter.setRinging(callId);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Sets a call's state to dialing (e.g., dialing an outbound call).
+     *
+     * @param callId The unique ID of the call whose state is changing to dialing.
+     */
+    public void setDialing(String callId) {
+        try {
+            mAdapter.setDialing(callId);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Sets a call's state to disconnected.
+     *
+     * @param callId The unique ID of the call whose state is changing to disconnected.
+     * @param disconnectCause The reason for the disconnection, any of
+     *         {@link android.telephony.DisconnectCause}.
+     * @param disconnectMessage Optional call-service-provided message about the disconnect.
+     */
+    public void setDisconnected(String callId, int disconnectCause, String disconnectMessage) {
+        try {
+            mAdapter.setDisconnected(callId, disconnectCause, disconnectMessage);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Sets a call's state to be on hold.
+     *
+     * @param callId - The unique ID of the call whose state is changing to be on hold.
+     */
+    public void setOnHold(String callId) {
+        try {
+            mAdapter.setOnHold(callId);
+        } catch (RemoteException e) {
+        }
+    }
+
+
+}
diff --git a/telecomm/java/android/telecomm/CallServiceDescriptor.aidl b/telecomm/java/android/telecomm/CallServiceDescriptor.aidl
new file mode 100644
index 0000000..f517c73
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceDescriptor.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.telecomm;
+
+parcelable CallServiceDescriptor;
diff --git a/telecomm/java/android/telecomm/CallServiceDescriptor.java b/telecomm/java/android/telecomm/CallServiceDescriptor.java
new file mode 100644
index 0000000..dec3791
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceDescriptor.java
@@ -0,0 +1,232 @@
+/*
+ * 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.telecomm;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.util.Locale;
+import java.util.UUID;
+
+/**
+ * An immutable object containing information about a given {@link CallService}. Instances are
+ * created using the enclosed {@link Builder}.
+ */
+public final class CallServiceDescriptor implements Parcelable {
+    private static final String TAG = CallServiceDescriptor.class.getSimpleName();
+
+    /**
+     * A placeholder value indicating an invalid network type.
+     * @hide
+     */
+    private static final int FLAG_INVALID = 0;
+
+    /**
+     * Indicates that the device must be connected to a Wi-Fi network in order for the backing
+     * {@link CallService} to be used.
+     */
+    public static final int FLAG_WIFI = 0x01;
+
+    /**
+     * Indicates that the device must be connected to a cellular PSTN network in order for the
+     * backing {@link CallService} to be used.
+     */
+    public static final int FLAG_PSTN = 0x02;
+
+    /**
+     * Indicates that the device must be connected to a cellular data network in order for the
+     * backing {@link CallService} to be used.
+     */
+    public static final int FLAG_MOBILE = 0x04;
+
+    /**
+     * Represents all of the defined FLAG_ constants so validity can be easily checked.
+     * @hide
+     */
+    public static final int FLAG_ALL = FLAG_WIFI | FLAG_PSTN | FLAG_MOBILE;
+
+    /**
+     * A unique ID used to identify a given instance.
+     */
+    private final String mCallServiceId;
+
+    /**
+     * The {@link ComponentName} of the {@link CallService} implementation which this is describing.
+     */
+    private final ComponentName mComponentName;
+
+    /**
+     * The type of connection that the {@link CallService} requires; will be one of the FLAG_*
+     * constants defined in this class.
+     */
+    private final int mNetworkType;
+
+    private CallServiceDescriptor(
+            String callServiceId,
+            ComponentName componentName,
+            int networkType) {
+
+        mCallServiceId = callServiceId;
+        mComponentName = componentName;
+        mNetworkType = networkType;
+    }
+
+    /**
+     * @return The ID used to identify this {@link CallService}.
+     */
+    public String getCallServiceId() {
+        return mCallServiceId;
+    }
+
+    /**
+     * @return The {@link ComponentName} of the {@link CallService}.
+     */
+    public ComponentName getServiceComponent() {
+        return mComponentName;
+    }
+
+    /**
+     * @return The network type required by the {@link CallService} to place a call.
+     */
+    public int getNetworkType() {
+        return mNetworkType;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof CallServiceDescriptor)) {
+            return false;
+        }
+        CallServiceDescriptor descriptor = (CallServiceDescriptor) obj;
+        return mCallServiceId.equals(descriptor.mCallServiceId) &&
+                mComponentName.equals(descriptor.mComponentName) &&
+                mNetworkType == descriptor.mNetworkType;
+    }
+
+    @Override
+    public String toString() {
+        return String.format(Locale.US, "[%s, component: %s]",
+                CallServiceDescriptor.class.getSimpleName(),
+                mComponentName == null ? "null" : mComponentName.flattenToShortString());
+    }
+
+    /**
+     * @param context {@link Context} to use for the construction of the {@link Builder}.
+     * @return A new {@link Builder} instance.
+     */
+    public static Builder newBuilder(Context context) {
+        return new Builder(context);
+    }
+
+    /**
+     * Creates {@link CallServiceDescriptor} instances. Builders should be created with the
+     * {@link CallServiceDescriptor#newBuilder(Context)} method.
+     */
+    public static class Builder {
+        /** The {@link Context} to use to verify {@link ComponentName} ownership. */
+        private Context mContext;
+
+        /** The {@link ComponentName} pointing to the backing {@link CallService}. */
+        private ComponentName mComponentName;
+
+        /** The required network type that the {@link CallService} needs. */
+        private int mNetworkType = FLAG_INVALID;
+
+        private Builder(Context context) {
+            mContext = context;
+        }
+
+        /**
+         * Set which {@link CallService} this {@link CallServiceDescriptor} is describing.
+         *
+         * @param callServiceClass The {@link CallService} class
+         * @return This {@link Builder} for method chaining.
+         */
+        public Builder setCallService(Class<? extends CallService> callServiceClass) {
+            mComponentName = new ComponentName(mContext, callServiceClass);
+            return this;
+        }
+
+        /**
+         * Which network type the backing {@link CallService} requires. This must be one of the
+         * {@link CallServiceDescriptor}.TYPE_* fields.
+         *
+         * @param networkType Which network type the backing {@link CallService} requires.
+         * @return This {@link Builder} for method chaining.
+         */
+        public Builder setNetworkType(int networkType) {
+            mNetworkType = networkType;
+            return this;
+        }
+
+        /**
+         * @return A constructed {@link CallServiceDescriptor} object.
+         */
+        public CallServiceDescriptor build() {
+            // STOPSHIP: Verify validity of ComponentName (permissions, intents, etc)
+
+            // Make sure that they passed in a valid network flag combination
+            if (mNetworkType == FLAG_INVALID || ((mNetworkType & FLAG_ALL) == 0)) {
+
+                Log.wtf(TAG, "Invalid network type for " + mComponentName);
+                // Revert them back to TYPE_INVALID so it won't be considered.
+                mNetworkType = FLAG_INVALID;
+            }
+
+            // TODO: Should we use a sha1 of the ComponentName? Would prevent duplicates.
+            return new CallServiceDescriptor(
+                UUID.randomUUID().toString(), mComponentName, mNetworkType);
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mCallServiceId);
+        dest.writeParcelable(mComponentName, 0);
+        dest.writeInt(mNetworkType);
+    }
+
+    public static final Creator<CallServiceDescriptor> CREATOR =
+            new Creator<CallServiceDescriptor>() {
+        @Override
+        public CallServiceDescriptor createFromParcel(Parcel source) {
+            String id = source.readString();
+            ComponentName componentName = source.readParcelable(
+                    CallServiceDescriptor.class.getClassLoader());
+            int networkType = source.readInt();
+
+            return new CallServiceDescriptor(id, componentName, networkType);
+        }
+
+        @Override
+        public CallServiceDescriptor[] newArray(int size) {
+            return new CallServiceDescriptor[size];
+        }
+    };
+}
diff --git a/telecomm/java/android/telecomm/CallServiceLookupResponse.java b/telecomm/java/android/telecomm/CallServiceLookupResponse.java
new file mode 100644
index 0000000..dd35a24
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceLookupResponse.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.os.RemoteException;
+
+import com.android.internal.telecomm.ICallServiceLookupResponse;
+
+import java.util.List;
+
+/**
+ * Used by {@link CallServiceProvider} to return a list of {@link CallServiceDescriptor}s.
+ */
+public final class CallServiceLookupResponse {
+    private final ICallServiceLookupResponse mResponse;
+
+    /**
+     * {@hide}
+     */
+    public CallServiceLookupResponse(ICallServiceLookupResponse response) {
+        mResponse = response;
+    }
+
+    /**
+     * Passes the sorted list of preferred {@link CallServiceDescriptor}s back to Telecomm.  Used
+     * in the context of attempting to place a pending outgoing call.
+     *
+     * @param callServiceDescriptors The set of call-service descriptors from
+     * {@link CallServiceProvider}.
+     */
+    public void setCallServiceDescriptors(List<CallServiceDescriptor> callServiceDescriptors) {
+        try {
+            mResponse.setCallServiceDescriptors(callServiceDescriptors);
+        } catch (RemoteException e) {
+        }
+    }
+}
diff --git a/telecomm/java/android/telecomm/CallServiceProvider.java b/telecomm/java/android/telecomm/CallServiceProvider.java
new file mode 100644
index 0000000..c50334a
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceProvider.java
@@ -0,0 +1,109 @@
+/*
+ * 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.telecomm;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+
+import com.android.internal.telecomm.ICallServiceLookupResponse;
+import com.android.internal.telecomm.ICallServiceProvider;
+
+/**
+ * Base implementation of a call service provider which extends {@link Service}. This class
+ * should be extended by an app that wants to supply phone calls to be handled and managed by
+ * the device's in-call interface. All method-calls from the framework to the call service provider
+ * are passed through to the main thread for before executing the overriden methods of
+ * CallServiceProvider.
+ *
+ * TODO(santoscordon): Improve paragraph above once the final design is in place. Needs more
+ * about how this can be used.
+ */
+public abstract class CallServiceProvider extends Service {
+
+    /**
+     * Default Handler used to consolidate binder method calls onto a single thread.
+     */
+    private final class CallServiceProviderMessageHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_LOOKUP_CALL_SERVICES:
+                    CallServiceLookupResponse response =
+                            new CallServiceLookupResponse((ICallServiceLookupResponse) msg.obj);
+                    lookupCallServices(response);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Default ICallServiceProvider implementation provided to CallsManager via {@link #onBind}.
+     */
+    private final class CallServiceProviderWrapper extends ICallServiceProvider.Stub {
+        /** {@inheritDoc} */
+        @Override
+        public void lookupCallServices(ICallServiceLookupResponse callServiceLookupResponse) {
+            Message message = mMessageHandler.obtainMessage(
+                    MSG_LOOKUP_CALL_SERVICES, callServiceLookupResponse);
+            message.sendToTarget();
+        }
+    }
+
+    // Only used internally by this class.
+    // Binder method calls on this service can occur on multiple threads. These messages are used
+    // in conjunction with {@link #mMessageHandler} to ensure that all callbacks are handled on a
+    // single thread.  Keeping it on a single thread allows CallService implementations to avoid
+    // needing multi-threaded code in their own callback routines.
+    private static final int MSG_LOOKUP_CALL_SERVICES = 1;
+
+    /**
+     * Message handler for consolidating binder callbacks onto a single thread.
+     * See {@link CallServiceProviderMessageHandler}.
+     */
+    private final CallServiceProviderMessageHandler mMessageHandler;
+
+    /**
+     * Default binder implementation of {@link ICallServiceProvider} interface.
+     */
+    private final CallServiceProviderWrapper mBinder;
+
+    /**
+     * Protected constructor called only by subclasses creates the binder interface and
+     * single-threaded message handler.
+     */
+    protected CallServiceProvider() {
+        mMessageHandler = new CallServiceProviderMessageHandler();
+        mBinder = new CallServiceProviderWrapper();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+
+    /**
+     * Initiates the process to retrieve the list of {@link CallServiceDescriptor}s implemented by
+     * this provider.
+     *
+     * @param response The response object through which the list of call services is sent.
+     */
+    public abstract void lookupCallServices(CallServiceLookupResponse response);
+}
diff --git a/telecomm/java/android/telecomm/CallServiceSelector.java b/telecomm/java/android/telecomm/CallServiceSelector.java
new file mode 100644
index 0000000..c9c6ff6
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceSelector.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+
+import com.android.internal.os.SomeArgs;
+import com.android.internal.telecomm.ICallServiceSelector;
+import com.android.internal.telecomm.ICallServiceSelectorAdapter;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Allows for the organization of {@link CallService}s for outbound calls. Given a call and list of
+ * {@link CallService} IDs, order the list in terms of priority and return it using
+ * {@link #select(CallInfo, List)}.
+ */
+public abstract class CallServiceSelector extends Service {
+    private static final int MSG_SET_CALL_SERVICE_SELECTOR_ADAPTER = 0;
+    private static final int MSG_SELECT = 1;
+
+    private final HashMap<String, CallInfo> mCalls = new HashMap<String, CallInfo>();
+
+    /** Handler to move client-bound method calls to the main thread. */
+    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_SET_CALL_SERVICE_SELECTOR_ADAPTER:
+                    mAdapter = new CallServiceSelectorAdapter(
+                            (ICallServiceSelectorAdapter) msg.obj);
+                    onAdapterAttached(mAdapter);
+                    break;
+                case MSG_SELECT:
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        select((CallInfo) args.arg1, (List<CallServiceDescriptor>) args.arg2);
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+            }
+        }
+    };
+
+    /** Manages the binder calls so that the implementor does not need to deal with it. */
+    private final class CallServiceSelectorBinder extends ICallServiceSelector.Stub {
+        @Override
+        public void setCallServiceSelectorAdapter(ICallServiceSelectorAdapter adapter) {
+            mHandler.obtainMessage(MSG_SET_CALL_SERVICE_SELECTOR_ADAPTER, adapter)
+                    .sendToTarget();
+        }
+
+        @Override
+        public void select(CallInfo callInfo, List<CallServiceDescriptor> descriptors) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callInfo;
+            args.arg2 = descriptors;
+            mHandler.obtainMessage(MSG_SELECT, args).sendToTarget();
+        }
+
+        @Override
+        public void onCallUpdated(CallInfo callInfo) {
+            mCalls.put(callInfo.getId(), callInfo);
+        }
+
+        @Override
+        public void onCallRemoved(String callId) {
+            mCalls.remove(callId);
+        }
+    }
+
+    private final CallServiceSelectorBinder mBinder;
+
+    private CallServiceSelectorAdapter mAdapter = null;
+
+    protected CallServiceSelector() {
+        mBinder = new CallServiceSelectorBinder();
+    }
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+
+    /**
+     * Returns a list of all calls managed by this selector.
+     */
+    protected final Collection<CallInfo> getCalls() {
+        return Collections.unmodifiableCollection(mCalls.values());
+    }
+
+    /**
+     * @return The attached {@link CallServiceSelectorAdapter} if attached, or null otherwise.
+     */
+    protected final CallServiceSelectorAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    /**
+     * Cancel the outgoing call. Any subsequent calls to {@link #select(CallInfo, List)} will be
+     * ignored.
+     *
+     * @param callInfo The call to canceled.
+     */
+    protected final void cancelOutgoingCall(CallInfo callInfo) {
+        getAdapter().cancelOutgoingCall(callInfo.getId());
+    }
+
+    /**
+     * Lifecycle callback which is called when this {@link CallServiceSelector} has been attached
+     * to a {@link CallServiceSelectorAdapter}, indicating {@link #getAdapter()} is now safe to use.
+     *
+     * @param adapter The adapter now attached to this call service selector.
+     */
+    protected void onAdapterAttached(CallServiceSelectorAdapter adapter) {
+    }
+
+    /**
+     * Given a list of {@link CallServiceDescriptor}s, order them into a prioritized list and return
+     * them through
+     * {@link CallServiceSelectorAdapter#setSelectedCallServices(String,List)}.
+     *
+     * @param callInfo The call being placed using the {@link CallService}s.
+     * @param descriptors The descriptors of the available {@link CallService}s with which to place
+     *            the call.
+     */
+    protected abstract void select(CallInfo callInfo, List<CallServiceDescriptor> descriptors);
+}
diff --git a/telecomm/java/android/telecomm/CallServiceSelectorAdapter.java b/telecomm/java/android/telecomm/CallServiceSelectorAdapter.java
new file mode 100644
index 0000000..4d2e8aa
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceSelectorAdapter.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.telecomm.CallServiceDescriptor;
+
+import com.android.internal.telecomm.ICallServiceSelectorAdapter;
+
+import java.util.List;
+
+/**
+ * Provides methods for ICallServiceSelector implementations to interact with Telecomm.
+ */
+public final class CallServiceSelectorAdapter {
+    private final ICallServiceSelectorAdapter mAdapter;
+
+    /**
+     * {@hide}
+     */
+    public CallServiceSelectorAdapter(ICallServiceSelectorAdapter adapter) {
+        mAdapter = adapter;
+    }
+
+    /**
+     * Records the sorted set of call services that are preferred by the corresponding
+     * call-service selector.
+     *
+     * @param callId The ID of the call to complete.
+     * @param selectedCallServiceDescriptors The prioritized list of preferred call-service
+     *        descriptors to use for completing the call.
+     */
+    public void setSelectedCallServices(
+            String callId,
+            List<CallServiceDescriptor> selectedCallServiceDescriptors) {
+        try {
+            mAdapter.setSelectedCallServices(callId, selectedCallServiceDescriptors);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Cancels the specified outgoing call.
+     *
+     * @param callId The ID of the call to cancel.
+     */
+    public void cancelOutgoingCall(String callId) {
+        try {
+            mAdapter.cancelOutgoingCall(callId);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Associates handoff information with an ongoing call. Calls can switch from one call service
+     * to another. Setting handle to a non-null value marks the call as switchable.
+     *
+     * @param callId The ID of the call to set handoff information for.
+     * @param handle The handle used to place the call when switching.
+     * @param extras Optional extra that's attached to the call.
+     */
+    public void setHandoffInfo(String callId, Uri handle, Bundle extras) {
+        try {
+            mAdapter.setHandoffInfo(callId, handle, extras);
+        } catch (RemoteException e) {
+        }
+    }
+}
diff --git a/telecomm/java/android/telecomm/CallState.java b/telecomm/java/android/telecomm/CallState.java
new file mode 100644
index 0000000..152c2023
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallState.java
@@ -0,0 +1,96 @@
+/*
+ * 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.telecomm;
+
+/**
+ * Defines call-state constants of the different states in which a call can exist. Although states
+ * have the notion of normal transitions, due to the volatile nature of telephony systems, code
+ * that uses these states should be resilient to unexpected state changes outside of what is
+ * considered traditional.
+ */
+public enum CallState {
+    /**
+     * Indicates that a call is new and not connected. This is used as the default state internally
+     * within Telecomm and should not be used between Telecomm and call services. Call services are
+     * not expected to ever interact with NEW calls, but {@link InCallService}s will see calls in
+     * this state.
+     */
+    NEW,
+
+    /**
+     * Indicates that a call is outgoing and in the dialing state. A call transitions to this state
+     * once an outgoing call has begun (e.g., user presses the dial button in Dialer). Calls in this
+     * state usually transition to {@link #ACTIVE} if the call was answered or {@link #DISCONNECTED}
+     * if the call was disconnected somehow (e.g., failure or cancellation of the call by the user).
+     */
+    DIALING,
+
+    /**
+     * Indicates that a call is incoming and the user still has the option of answering, rejecting,
+     * or doing nothing with the call. This state is usually associated with some type of audible
+     * ringtone. Normal transitions are to {@link #ACTIVE} if answered or {@link #DISCONNECTED}
+     * otherwise.
+     */
+    RINGING,
+
+    /**
+     * Indicates that the call is active but in a "post-dial" state where Telecomm is now sending
+     * some dual-tone multi-frequency signaling (DTMF) tones appended to the dialed number. Normal
+     * transitions are to {@link #POST_DIAL_WAIT} when the post-dial string requires user
+     * confirmation to proceed, {@link #ACTIVE} when the post-dial tones are completed, or
+     * {@link #DISCONNECTED}.
+     */
+    POST_DIAL,
+
+    /**
+     * Indicates that the call was in the {@link #POST_DIAL} state but is now waiting for user
+     * confirmation before the remaining digits can be sent. Normal transitions are to
+     * {@link #POST_DIAL} when the user asks Telecomm to proceed with the post-dial sequence.
+     */
+    POST_DIAL_WAIT,
+
+    /**
+     * Indicates that a call is currently connected to another party and a communication channel is
+     * open between them. The normal transition to this state is by the user answering a
+     * {@link #DIALING} call or a {@link #RINGING} call being answered by the other party.
+     */
+    ACTIVE,
+
+    /**
+     * Indicates that the call is currently on hold. In this state, the call is not terminated
+     * but no communication is allowed until the call is no longer on hold. The typical transition
+     * to this state is by the user putting an {@link #ACTIVE} call on hold by explicitly performing
+     * an action, such as clicking the hold button.
+     */
+    ON_HOLD,
+
+    /**
+     * Indicates that a call is currently disconnected. All states can transition to this state
+     * by the call service giving notice that the connection has been severed. When the user
+     * explicitly ends a call, it will not transition to this state until the call service confirms
+     * the disconnection or communication was lost to the call service currently responsible for
+     * this call (e.g., call service crashes).
+     */
+    DISCONNECTED,
+
+    /**
+     * Indicates that the call was attempted (mostly in the context of outgoing, at least at the
+     * time of writing) but cancelled before it was successfully connected.
+     * @hide
+     */
+    ABORTED;
+}
diff --git a/telecomm/java/android/telecomm/GatewayInfo.aidl b/telecomm/java/android/telecomm/GatewayInfo.aidl
new file mode 100644
index 0000000..d59e9b4
--- /dev/null
+++ b/telecomm/java/android/telecomm/GatewayInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.telecomm;
+
+parcelable GatewayInfo;
diff --git a/telecomm/java/android/telecomm/GatewayInfo.java b/telecomm/java/android/telecomm/GatewayInfo.java
new file mode 100644
index 0000000..b95e6b6
--- /dev/null
+++ b/telecomm/java/android/telecomm/GatewayInfo.java
@@ -0,0 +1,106 @@
+/*
+ * 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.telecomm;
+
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+/**
+ * When calls are made, they may contain gateway information for services which route phone calls
+ * through their own service/numbers. The data consists of a number to call and the package name of
+ * the service. This data is used in two ways:
+ * <ol>
+ * <li> Call the appropriate routing number
+ * <li> Display information about how the call is being routed to the user
+ * </ol>
+ */
+public class GatewayInfo implements Parcelable {
+
+    private final String mGatewayProviderPackageName;
+    private final Uri mGatewayHandle;
+    private final Uri mOriginalHandle;
+
+    /** @hide */
+    public GatewayInfo(String packageName, Uri gatewayUri, Uri originalHandle) {
+        mGatewayProviderPackageName = packageName;
+        mGatewayHandle = gatewayUri;
+        mOriginalHandle = originalHandle;
+    }
+
+    /**
+     * Package name of the gateway provider service. used to place the call with.
+     */
+    public String getGatewayProviderPackageName() {
+        return mGatewayProviderPackageName;
+    }
+
+    /**
+     * Gateway provider handle to use when actually placing the call.
+     */
+    public Uri getGatewayHandle() {
+        return mGatewayHandle;
+    }
+
+    /**
+     * The actual call handle that the user is trying to connect to via the gateway.
+     */
+    public Uri getOriginalHandle() {
+        return mOriginalHandle;
+    }
+
+    public boolean isEmpty() {
+        return TextUtils.isEmpty(mGatewayProviderPackageName) || mGatewayHandle == null;
+    }
+
+    /** Implement the Parcelable interface */
+    public static final Parcelable.Creator<GatewayInfo> CREATOR =
+            new Parcelable.Creator<GatewayInfo> () {
+
+        @Override
+        public GatewayInfo createFromParcel(Parcel source) {
+            String gatewayPackageName = source.readString();
+            Uri gatewayUri = Uri.CREATOR.createFromParcel(source);
+            Uri originalHandle = Uri.CREATOR.createFromParcel(source);
+            return new GatewayInfo(gatewayPackageName, gatewayUri, originalHandle);
+        }
+
+        @Override
+        public GatewayInfo[] newArray(int size) {
+            return new GatewayInfo[size];
+        }
+    };
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void writeToParcel(Parcel destination, int flags) {
+        destination.writeString(mGatewayProviderPackageName);
+        mGatewayHandle.writeToParcel(destination, 0);
+        mOriginalHandle.writeToParcel(destination, 0);
+    }
+}
diff --git a/telecomm/java/android/telecomm/InCallAdapter.java b/telecomm/java/android/telecomm/InCallAdapter.java
new file mode 100644
index 0000000..e41d3f6
--- /dev/null
+++ b/telecomm/java/android/telecomm/InCallAdapter.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.os.RemoteException;
+
+import com.android.internal.telecomm.IInCallAdapter;
+
+/**
+ * Receives commands from {@link InCallService} implementations which should be executed by
+ * Telecomm. When Telecomm binds to a {@link InCallService}, an instance of this class is given to
+ * the in-call service through which it can manipulate live (active, dialing, ringing) calls. When
+ * the in-call service is notified of new calls ({@link InCallService#addCall}), it can use the
+ * given call IDs to execute commands such as {@link #answerCall} for incoming calls or
+ * {@link #disconnectCall} for active calls the user would like to end. Some commands are only
+ * appropriate for calls in certain states; please consult each method for such limitations.
+ * TODO(santoscordon): Needs more/better comments once the API is finalized.
+ * TODO(santoscordon): Specify the adapter will stop functioning when there are no more calls.
+ */
+public final class InCallAdapter {
+    private final IInCallAdapter mAdapter;
+
+    /**
+     * {@hide}
+     */
+    public InCallAdapter(IInCallAdapter adapter) {
+        mAdapter = adapter;
+    }
+
+    /**
+     * Instructs Telecomm to answer the specified call.
+     *
+     * @param callId The identifier of the call to answer.
+     */
+    public void answerCall(String callId) {
+        try {
+            mAdapter.answerCall(callId);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Instructs Telecomm to reject the specified call.
+     * TODO(santoscordon): Add reject-with-text-message parameter when that feature
+     * is ported over.
+     *
+     * @param callId The identifier of the call to reject.
+     */
+    public void rejectCall(String callId) {
+        try {
+            mAdapter.rejectCall(callId);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Instructs Telecomm to disconnect the specified call.
+     *
+     * @param callId The identifier of the call to disconnect.
+     */
+    public void disconnectCall(String callId) {
+        try {
+            mAdapter.disconnectCall(callId);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Instructs Telecomm to put the specified call on hold.
+     *
+     * @param callId The identifier of the call to put on hold.
+     */
+    public void holdCall(String callId) {
+        try {
+            mAdapter.holdCall(callId);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Instructs Telecomm to release the specified call from hold.
+     *
+     * @param callId The identifier of the call to release from hold.
+     */
+    public void unholdCall(String callId) {
+        try {
+            mAdapter.unholdCall(callId);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Mute the microphone.
+     *
+     * @param shouldMute True if the microphone should be muted.
+     */
+    public void mute(boolean shouldMute) {
+        try {
+            mAdapter.mute(shouldMute);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Sets the audio route (speaker, bluetooth, etc...). See {@link CallAudioState}.
+     *
+     * @param route The audio route to use.
+     */
+    public void setAudioRoute(int route) {
+        try {
+            mAdapter.setAudioRoute(route);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Instructs Telecomm to play a dual-tone multi-frequency signaling (DTMF) tone in a call.
+     *
+     * Any other currently playing DTMF tone in the specified call is immediately stopped.
+     *
+     * @param callId The unique ID of the call in which the tone will be played.
+     * @param digit A character representing the DTMF digit for which to play the tone. This
+     *         value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
+     */
+    public void playDtmfTone(String callId, char digit) {
+        try {
+            mAdapter.playDtmfTone(callId, digit);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Instructs Telecomm to stop any dual-tone multi-frequency signaling (DTMF) tone currently
+     * playing.
+     *
+     * DTMF tones are played by calling {@link #playDtmfTone(String,char)}. If no DTMF tone is
+     * currently playing, this method will do nothing.
+     *
+     * @param callId The unique ID of the call in which any currently playing tone will be stopped.
+     */
+    public void stopDtmfTone(String callId) {
+        try {
+            mAdapter.stopDtmfTone(callId);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Instructs Telecomm to continue playing a post-dial DTMF string.
+     *
+     * A post-dial DTMF string is a string of digits entered after a phone number, when dialed,
+     * that are immediately sent as DTMF tones to the recipient as soon as the connection is made.
+     * While these tones are playing, Telecomm will notify the {@link InCallService} that the call
+     * is in the {@link InCallService#setPostDial(String,String)} state.
+     *
+     * If the DTMF string contains a {@link TelecommConstants#DTMF_CHARACTER_PAUSE} symbol, Telecomm
+     * will temporarily pause playing the tones for a pre-defined period of time.
+     *
+     * If the DTMF string contains a {@link TelecommConstants#DTMF_CHARACTER_WAIT} symbol, Telecomm
+     * will pause playing the tones and notify the {@link InCallService} that the call is in the
+     * {@link InCallService#setPostDialWait(String,String)} state. When the user decides to continue
+     * the postdial sequence, the {@link InCallService} should invoke the
+     * {@link #postDialContinue(String)} method.
+     *
+     * @param callId The unique ID of the call for which postdial string playing should continue.
+     */
+    public void postDialContinue(String callId) {
+        try {
+            mAdapter.postDialContinue(callId);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Instructs Telecomm to handoff the call to another call service.
+     *
+     * @param callId The identifier of the call to handoff.
+     */
+    public void handoffCall(String callId) {
+        try {
+            mAdapter.handoffCall(callId);
+        } catch (RemoteException e) {
+        }
+    }
+}
diff --git a/telecomm/java/android/telecomm/InCallCall.aidl b/telecomm/java/android/telecomm/InCallCall.aidl
new file mode 100644
index 0000000..be2cdf8
--- /dev/null
+++ b/telecomm/java/android/telecomm/InCallCall.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.telecomm;
+
+parcelable InCallCall;
diff --git a/telecomm/java/android/telecomm/InCallCall.java b/telecomm/java/android/telecomm/InCallCall.java
new file mode 100644
index 0000000..c3b2ae7
--- /dev/null
+++ b/telecomm/java/android/telecomm/InCallCall.java
@@ -0,0 +1,159 @@
+/*
+ * 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.telecomm;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.DisconnectCause;
+
+import java.util.Date;
+import java.util.UUID;
+
+/**
+ * Information about a call that is used between InCallService and Telecomm.
+ */
+public final class InCallCall implements Parcelable {
+    private final String mId;
+    private final CallState mState;
+    private final int mDisconnectCause;
+    private final int mCapabilities;
+    private final long mConnectTimeMillis;
+    private final Uri mHandle;
+    private final GatewayInfo mGatewayInfo;
+    private final CallServiceDescriptor mCurrentCallServiceDescriptor;
+    private final CallServiceDescriptor mHandoffCallServiceDescriptor;
+
+    /** @hide */
+    public InCallCall(
+            String id,
+            CallState state,
+            int disconnectCause,
+            int capabilities,
+            long connectTimeMillis,
+            Uri handle,
+            GatewayInfo gatewayInfo,
+            CallServiceDescriptor descriptor,
+            CallServiceDescriptor handoffDescriptor) {
+        mId = id;
+        mState = state;
+        mDisconnectCause = disconnectCause;
+        mCapabilities = capabilities;
+        mConnectTimeMillis = connectTimeMillis;
+        mHandle = handle;
+        mGatewayInfo = gatewayInfo;
+        mCurrentCallServiceDescriptor = descriptor;
+        mHandoffCallServiceDescriptor = handoffDescriptor;
+    }
+
+    /** The unique ID of the call. */
+    public String getId() {
+        return mId;
+    }
+
+    /** The current state of the call. */
+    public CallState getState() {
+        return mState;
+    }
+
+    /**
+     * Reason for disconnection, values are defined in {@link DisconnectCause}. Valid when call
+     * state is {@link CallState#DISCONNECTED}.
+     */
+    public int getDisconnectCause() {
+        return mDisconnectCause;
+    }
+
+    // Bit mask of actions a call supports, values are defined in {@link CallCapabilities}.
+    public int getCapabilities() {
+        return mCapabilities;
+    }
+
+    /** The time that the call switched to the active state. */
+    public long getConnectTimeMillis() {
+        return mConnectTimeMillis;
+    }
+
+    /** The endpoint to which the call is connected. */
+    public Uri getHandle() {
+        return mHandle;
+    }
+
+    /** Gateway information for the call. */
+    public GatewayInfo getGatewayInfo() {
+        return mGatewayInfo;
+    }
+
+    /** The descriptor for the call service currently routing this call. */
+    public CallServiceDescriptor getCurrentCallServiceDescriptor() {
+        return mCurrentCallServiceDescriptor;
+    }
+
+    /**
+     * The descriptor for the call service that this call is being switched to, null if handoff is
+     * not in progress.
+     */
+    public CallServiceDescriptor getHandoffCallServiceDescriptor() {
+        return mHandoffCallServiceDescriptor;
+    }
+
+    /** Responsible for creating InCallCall objects for deserialized Parcels. */
+    public static final Parcelable.Creator<InCallCall> CREATOR =
+            new Parcelable.Creator<InCallCall> () {
+        @Override
+        public InCallCall createFromParcel(Parcel source) {
+            String id = source.readString();
+            CallState state = CallState.valueOf(source.readString());
+            int disconnectCause = source.readInt();
+            int capabilities = source.readInt();
+            long connectTimeMillis = source.readLong();
+            ClassLoader classLoader = InCallCall.class.getClassLoader();
+            Uri handle = source.readParcelable(classLoader);
+            GatewayInfo gatewayInfo = source.readParcelable(classLoader);
+            CallServiceDescriptor descriptor = source.readParcelable(classLoader);
+            CallServiceDescriptor handoffDescriptor = source.readParcelable(classLoader);
+            return new InCallCall(id, state, disconnectCause, capabilities, connectTimeMillis,
+                    handle, gatewayInfo, descriptor, handoffDescriptor);
+        }
+
+        @Override
+        public InCallCall[] newArray(int size) {
+            return new InCallCall[size];
+        }
+    };
+
+    /** {@inheritDoc} */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Writes InCallCall object into a Parcel. */
+    @Override
+    public void writeToParcel(Parcel destination, int flags) {
+        destination.writeString(mId);
+        destination.writeString(mState.name());
+        destination.writeInt(mDisconnectCause);
+        destination.writeInt(mCapabilities);
+        destination.writeLong(mConnectTimeMillis);
+        destination.writeParcelable(mHandle, 0);
+        destination.writeParcelable(mGatewayInfo, 0);
+        destination.writeParcelable(mCurrentCallServiceDescriptor, 0);
+        destination.writeParcelable(mHandoffCallServiceDescriptor, 0);
+    }
+}
diff --git a/telecomm/java/android/telecomm/InCallService.java b/telecomm/java/android/telecomm/InCallService.java
new file mode 100644
index 0000000..63b2020
--- /dev/null
+++ b/telecomm/java/android/telecomm/InCallService.java
@@ -0,0 +1,209 @@
+/*
+ * 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.telecomm;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+
+import com.android.internal.os.SomeArgs;
+import com.android.internal.telecomm.IInCallAdapter;
+import com.android.internal.telecomm.IInCallService;
+
+/**
+ * This service is implemented by any app that wishes to provide the user-interface for managing
+ * phone calls. Telecomm binds to this service while there exists a live (active or incoming)
+ * call, and uses it to notify the in-call app of any live and and recently disconnected calls.
+ * TODO(santoscordon): Needs more/better description of lifecycle once the interface is better
+ * defined.
+ * TODO(santoscordon): What happens if two or more apps on a given device implement this interface?
+ */
+public abstract class InCallService extends Service {
+    private static final int MSG_SET_IN_CALL_ADAPTER = 1;
+    private static final int MSG_ADD_CALL = 2;
+    private static final int MSG_UPDATE_CALL = 3;
+    private static final int MSG_SET_POST_DIAL = 4;
+    private static final int MSG_SET_POST_DIAL_WAIT = 5;
+    private static final int MSG_ON_AUDIO_STATE_CHANGED = 6;
+
+    /** Default Handler used to consolidate binder method calls onto a single thread. */
+    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_SET_IN_CALL_ADAPTER:
+                    mAdapter = new InCallAdapter((IInCallAdapter) msg.obj);
+                    onAdapterAttached(mAdapter);
+                    break;
+                case MSG_ADD_CALL:
+                    addCall((InCallCall) msg.obj);
+                    break;
+                case MSG_UPDATE_CALL:
+                    updateCall((InCallCall) msg.obj);
+                    break;
+                case MSG_SET_POST_DIAL: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        String callId = (String) args.arg1;
+                        String remaining = (String) args.arg2;
+                        setPostDial(callId, remaining);
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
+                case MSG_SET_POST_DIAL_WAIT: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        String callId = (String) args.arg1;
+                        String remaining = (String) args.arg2;
+                        setPostDialWait(callId, remaining);
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
+                case MSG_ON_AUDIO_STATE_CHANGED:
+                    onAudioStateChanged((CallAudioState) msg.obj);
+                    break;
+                default:
+                    break;
+            }
+        }
+    };
+
+    /** Manages the binder calls so that the implementor does not need to deal with it. */
+    private final class InCallServiceBinder extends IInCallService.Stub {
+        /** {@inheritDoc} */
+        @Override
+        public void setInCallAdapter(IInCallAdapter inCallAdapter) {
+            mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER, inCallAdapter).sendToTarget();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void addCall(InCallCall call) {
+            mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void updateCall(InCallCall call) {
+            mHandler.obtainMessage(MSG_UPDATE_CALL, call).sendToTarget();
+        }
+
+        @Override
+        public void setPostDial(String callId, String remaining) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callId;
+            args.arg2 = remaining;
+            mHandler.obtainMessage(MSG_SET_POST_DIAL, args).sendToTarget();
+        }
+
+        @Override
+        public void setPostDialWait(String callId, String remaining) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callId;
+            args.arg2 = remaining;
+            mHandler.obtainMessage(MSG_SET_POST_DIAL_WAIT, args).sendToTarget();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void onAudioStateChanged(CallAudioState audioState) {
+            mHandler.obtainMessage(MSG_ON_AUDIO_STATE_CHANGED, audioState).sendToTarget();
+        }
+    }
+
+    private final InCallServiceBinder mBinder;
+
+    private InCallAdapter mAdapter;
+
+    protected InCallService() {
+        mBinder = new InCallServiceBinder();
+    }
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+
+    /**
+     * @return The attached {@link CallServiceSelectorAdapter} if attached, or null otherwise.
+     */
+    protected final InCallAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    /**
+     * Lifecycle callback which is called when this {@link InCallService} has been attached
+     * to a {@link InCallAdapter}, indicating {@link #getAdapter()} is now safe to use.
+     *
+     * @param adapter The adapter now attached to this in-call service.
+     */
+    protected void onAdapterAttached(InCallAdapter adapter) {
+    }
+
+    /**
+     * Indicates to the in-call app that a new call has been created and an appropriate
+     * user-interface should be built and shown to notify the user.
+     *
+     * @param call Information about the new call.
+     */
+     protected abstract void addCall(InCallCall call);
+
+    /**
+     * Call when information about a call has changed.
+     *
+     * @param call Information about the new call.
+     */
+     protected abstract void updateCall(InCallCall call);
+
+    /**
+     * Indicates to the in-call app that the specified call is active but in a "post-dial" state
+     * where Telecomm is now sending some dual-tone multi-frequency signaling (DTMF) tones appended
+     * to the dialed number. Normal transitions are to {@link #setPostDialWait(String,String)} when
+     * the post-dial string requires user confirmation to proceed, and {@link CallState#ACTIVE} when
+     * the post-dial tones are completed.
+     *
+     * @param callId The identifier of the call changing state.
+     * @param remaining The remaining postdial string to be dialed.
+     */
+    protected abstract void setPostDial(String callId, String remaining);
+
+    /**
+     * Indicates to the in-call app that the specified call was in the
+     * {@link #setPostDial(String,String)} state but is now waiting for user confirmation before the
+     * remaining digits can be sent. Normal transitions are to {@link #setPostDial(String,String)}
+     * when the user asks Telecomm to proceed with the post-dial sequence and the in-call app
+     * informs Telecomm of this by invoking {@link InCallAdapter#postDialContinue(String)}.
+     *
+     * @param callId The identifier of the call changing state.
+     * @param remaining The remaining postdial string to be dialed.
+     */
+    protected abstract void setPostDialWait(String callId, String remaining);
+
+    /**
+     * Called when the audio state changes.
+     *
+     * @param audioState The new {@link CallAudioState}.
+     */
+    protected abstract void onAudioStateChanged(CallAudioState audioState);
+}
diff --git a/telecomm/java/android/telecomm/TelecommConstants.java b/telecomm/java/android/telecomm/TelecommConstants.java
new file mode 100644
index 0000000..8300c92
--- /dev/null
+++ b/telecomm/java/android/telecomm/TelecommConstants.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.os.Bundle;
+import android.telephony.TelephonyManager;
+
+/**
+ * Defines constants for use with the Telecomm system.
+ */
+public final class TelecommConstants {
+    /**
+     * <p>Activity action: Starts the UI for handing an incoming call. This intent starts the
+     * in-call UI by notifying the Telecomm system that an incoming call exists for a specific call
+     * service (see {@link android.telecomm.CallService}). Telecomm reads the Intent extras to find
+     * and bind to the appropriate {@link android.telecomm.CallService} which Telecomm will
+     * ultimately use to control and get information about the call.</p>
+     *
+     * <p>Input: get*Extra field {@link #EXTRA_CALL_SERVICE_DESCRIPTOR} contains the component name
+     * of the {@link android.telecomm.CallService} that Telecomm should bind to. Telecomm will then
+     * ask the call service for more information about the call prior to showing any UI.
+     *
+     * TODO(santoscordon): Needs permissions.
+     * TODO(santoscordon): Consider moving this into a simple method call on a system service.
+     */
+    public static final String ACTION_INCOMING_CALL = "android.intent.action.INCOMING_CALL";
+
+    /**
+     * The service action used to bind to {@link CallServiceProvider} implementations.
+     */
+    public static final String ACTION_CALL_SERVICE_PROVIDER = CallServiceProvider.class.getName();
+
+    /**
+     * The service action used to bind to {@link CallService} implementations.
+     */
+    public static final String ACTION_CALL_SERVICE = CallService.class.getName();
+
+    /**
+     * The service action used to bind to {@link CallServiceSelector} implementations.
+     */
+    public static final String ACTION_CALL_SERVICE_SELECTOR = CallServiceSelector.class.getName();
+
+    /**
+     * Extra for {@link #ACTION_INCOMING_CALL} containing the {@link CallServiceDescriptor} that
+     * describes the call service to use for the incoming call.
+     */
+    public static final String EXTRA_CALL_SERVICE_DESCRIPTOR =
+            "android.intent.extra.CALL_SERVICE_DESCRIPTOR";
+
+    /**
+     * Optional extra for {@link #ACTION_INCOMING_CALL} containing a {@link Bundle} which contains
+     * metadata about the call. This {@link Bundle} will be returned to the {@link CallService} as
+     * part of {@link CallService#setIncomingCallId(String,Bundle)}.
+     */
+    public static final String EXTRA_INCOMING_CALL_EXTRAS =
+            "android.intent.extra.INCOMING_CALL_EXTRAS";
+
+    /**
+     * Optional extra for {@link TelephonyManager#ACTION_PHONE_STATE_CHANGED} containing the
+     * disconnect code.
+     */
+    public static final String EXTRA_CALL_DISCONNECT_CAUSE =
+            "android.telecomm.extra.CALL_DISCONNECT_CAUSE";
+
+    /**
+     * Optional extra for {@link TelephonyManager#ACTION_PHONE_STATE_CHANGED} containing the
+     * disconnect message.
+     */
+    public static final String EXTRA_CALL_DISCONNECT_MESSAGE =
+            "android.telecomm.extra.CALL_DISCONNECT_MESSAGE";
+
+    /**
+     * The dual tone multi-frequency signaling character sent to indicate the dialing system should
+     * pause for a predefined period.
+     */
+    public static final char DTMF_CHARACTER_PAUSE = ',';
+
+    /**
+     * The dual-tone multi-frequency signaling character sent to indicate the dialing system should
+     * wait for user confirmation before proceeding.
+     */
+    public static final char DTMF_CHARACTER_WAIT = ';';
+}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallService.aidl b/telecomm/java/com/android/internal/telecomm/ICallService.aidl
new file mode 100644
index 0000000..cc0641c
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecomm/ICallService.aidl
@@ -0,0 +1,58 @@
+/*
+ * 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.telecomm;
+
+import android.os.Bundle;
+import android.telecomm.CallAudioState;
+import android.telecomm.CallInfo;
+
+import com.android.internal.telecomm.ICallServiceAdapter;
+
+/**
+ * Internal remote interface for call services.
+ *
+ * @see android.telecomm.CallService
+ *
+ * @hide
+ */
+oneway interface ICallService {
+    void setCallServiceAdapter(in ICallServiceAdapter callServiceAdapter);
+
+    void isCompatibleWith(in CallInfo callInfo);
+
+    void call(in CallInfo callInfo);
+
+    void abort(String callId);
+
+    void setIncomingCallId(String callId, in Bundle extras);
+
+    void answer(String callId);
+
+    void reject(String callId);
+
+    void disconnect(String callId);
+
+    void hold(String callId);
+
+    void unhold(String callId);
+
+    void onAudioStateChanged(String activeCallId, in CallAudioState audioState);
+
+    void playDtmfTone(String callId, char digit);
+
+    void stopDtmfTone(String callId);
+}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl b/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl
new file mode 100644
index 0000000..dfdaa75
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl
@@ -0,0 +1,46 @@
+/*
+ * 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.telecomm;
+
+import android.telecomm.CallInfo;
+
+/**
+ * Internal remote callback interface for call services.
+ *
+ * @see android.telecomm.CallServiceAdapter
+ *
+ * {@hide}
+ */
+oneway interface ICallServiceAdapter {
+    void setIsCompatibleWith(String callId, boolean isCompatible);
+
+    void notifyIncomingCall(in CallInfo callInfo);
+
+    void handleSuccessfulOutgoingCall(String callId);
+
+    void handleFailedOutgoingCall(String callId, String errorMessage);
+
+    void setActive(String callId);
+
+    void setRinging(String callId);
+
+    void setDialing(String callId);
+
+    void setDisconnected(String callId, int disconnectCause, String disconnectMessage);
+
+    void setOnHold(String callId);
+}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallServiceLookupResponse.aidl b/telecomm/java/com/android/internal/telecomm/ICallServiceLookupResponse.aidl
new file mode 100644
index 0000000..10d73be
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecomm/ICallServiceLookupResponse.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telecomm;
+
+import android.os.IBinder;
+import android.telecomm.CallServiceDescriptor;
+import java.util.List;
+
+/**
+ * Internal remote interface for call service lookup response.
+ *
+ * @see android.telecomm.CallServiceLookupResponse
+ *
+ * @hide
+ */
+oneway interface ICallServiceLookupResponse {
+    void setCallServiceDescriptors(in List<CallServiceDescriptor> callServiceDescriptors);
+}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallServiceProvider.aidl b/telecomm/java/com/android/internal/telecomm/ICallServiceProvider.aidl
new file mode 100644
index 0000000..96daeed
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecomm/ICallServiceProvider.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.telecomm;
+
+import android.telecomm.CallServiceDescriptor;
+
+import com.android.internal.telecomm.ICallServiceLookupResponse;
+
+/**
+ * Internal remote interface for call service providers.
+ *
+ * @see android.telecomm.CallServiceProvider
+ *
+ * @hide
+ */
+oneway interface ICallServiceProvider {
+    void lookupCallServices(in ICallServiceLookupResponse response);
+}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallServiceSelector.aidl b/telecomm/java/com/android/internal/telecomm/ICallServiceSelector.aidl
new file mode 100644
index 0000000..9597dc1
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecomm/ICallServiceSelector.aidl
@@ -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.internal.telecomm;
+
+import android.telecomm.CallInfo;
+import android.telecomm.CallServiceDescriptor;
+
+import com.android.internal.telecomm.ICallService;
+import com.android.internal.telecomm.ICallServiceSelectorAdapter;
+
+import java.util.List;
+
+/**
+ * Internal remote interface for call service selectors.
+ *
+ * @see android.telecomm.CallServiceSelector
+ *
+ * @hide
+ */
+oneway interface ICallServiceSelector {
+    void setCallServiceSelectorAdapter(in ICallServiceSelectorAdapter adapter);
+
+    void select(in CallInfo callInfo, in List<CallServiceDescriptor> callServiceDescriptors);
+
+    void onCallUpdated(in CallInfo callInfo);
+
+    void onCallRemoved(String callId);
+}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallServiceSelectorAdapter.aidl b/telecomm/java/com/android/internal/telecomm/ICallServiceSelectorAdapter.aidl
new file mode 100644
index 0000000..ad71e3c
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecomm/ICallServiceSelectorAdapter.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 com.android.internal.telecomm;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.telecomm.CallInfo;
+import android.telecomm.CallServiceDescriptor;
+
+import java.util.List;
+
+/**
+ * Internal remote interface for call service selector adapter.
+ *
+ * @see android.telecomm.CallServiceSelectorAdapter
+ *
+ * @hide
+ */
+oneway interface ICallServiceSelectorAdapter {
+    void setSelectedCallServices(
+            String callId,
+            in List<CallServiceDescriptor> selectedCallServiceDescriptors);
+
+    void cancelOutgoingCall(String callId);
+
+    void setHandoffInfo(String callId, in Uri handle, in Bundle extras);
+}
diff --git a/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
new file mode 100644
index 0000000..512e898
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.telecomm;
+
+import android.telecomm.CallAudioState;
+
+/**
+ * Internal remote callback interface for in-call services.
+ *
+ * @see android.telecomm.InCallAdapter
+ *
+ * {@hide}
+ */
+oneway interface IInCallAdapter {
+    void answerCall(String callId);
+
+    void rejectCall(String callId);
+
+    void disconnectCall(String callId);
+
+    void holdCall(String callId);
+
+    void unholdCall(String callId);
+
+    void mute(boolean shouldMute);
+
+    void setAudioRoute(int route);
+
+    void playDtmfTone(String callId, char digit);
+
+    void stopDtmfTone(String callId);
+
+    void postDialContinue(String callId);
+
+    void handoffCall(String callId);
+}
diff --git a/telecomm/java/com/android/internal/telecomm/IInCallService.aidl b/telecomm/java/com/android/internal/telecomm/IInCallService.aidl
new file mode 100644
index 0000000..ccf7e3f
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecomm/IInCallService.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.telecomm;
+
+import android.telecomm.CallAudioState;
+import android.telecomm.InCallCall;
+
+import com.android.internal.telecomm.IInCallAdapter;
+
+/**
+ * Internal remote interface for in-call services.
+ *
+ * @see android.telecomm.InCallService
+ *
+ * {@hide}
+ */
+oneway interface IInCallService {
+    void setInCallAdapter(in IInCallAdapter inCallAdapter);
+
+    void addCall(in InCallCall call);
+
+    void updateCall(in InCallCall call);
+
+    void setPostDial(String callId, String remaining);
+
+    void setPostDialWait(String callId, String remaining);
+
+    void onAudioStateChanged(in CallAudioState audioState);
+}
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index 1c75658..8681344 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -17,10 +17,7 @@
 package android.telephony;
 
 /**
- * Contains disconnect call causes generated by the
- * framework and the RIL.
- *
- * @hide
+ * Contains disconnect call causes generated by the framework and the RIL.
  */
 public class DisconnectCause {
 
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index c79e9bf..9da032a 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1492,6 +1492,10 @@
      * @return the normalized number.
      */
     public static String normalizeNumber(String phoneNumber) {
+        if (TextUtils.isEmpty(phoneNumber)) {
+            return "";
+        }
+
         StringBuilder sb = new StringBuilder();
         int len = phoneNumber.length();
         for (int i = 0; i < len; i++) {
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 606fcb4..1ee390f 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -797,6 +797,8 @@
             return TelephonyManager.NETWORK_TYPE_LTE;
         case ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP:
             return TelephonyManager.NETWORK_TYPE_HSPAP;
+        case ServiceState.RIL_RADIO_TECHNOLOGY_GSM:
+            return TelephonyManager.NETWORK_TYPE_GSM;
         default:
             return TelephonyManager.NETWORK_TYPE_UNKNOWN;
         }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 407a8d1..7002744 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -19,6 +19,7 @@
 import android.annotation.PrivateApi;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.content.ComponentName;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.Handler;
@@ -67,6 +68,20 @@
 
     private static ITelephonyRegistry sRegistry;
 
+    /**
+     * The allowed states of Wi-Fi calling.
+     *
+     * @hide
+     */
+    public interface WifiCallingChoices {
+        /** Always use Wi-Fi calling */
+        static final int ALWAYS_USE = 0;
+        /** Ask the user whether to use Wi-Fi on every call */
+        static final int ASK_EVERY_TIME = 1;
+        /** Never use Wi-Fi calling */
+        static final int NEVER_USE = 2;
+    }
+
     private final HashMap<CallStateListener,Listener> mListeners
             = new HashMap<CallStateListener,Listener>();
     private final Context mContext;
@@ -911,6 +926,8 @@
     public static final int NETWORK_TYPE_EHRPD = 14;
     /** Current network is HSPA+ */
     public static final int NETWORK_TYPE_HSPAP = 15;
+    /** Current network is GSM {@hide} */
+    public static final int NETWORK_TYPE_GSM = 16;
 
     /**
      * @return the NETWORK_TYPE_xxxx for current data connection.
@@ -1002,6 +1019,7 @@
     public static int getNetworkClass(int networkType) {
         switch (networkType) {
             case NETWORK_TYPE_GPRS:
+            case NETWORK_TYPE_GSM:
             case NETWORK_TYPE_EDGE:
             case NETWORK_TYPE_CDMA:
             case NETWORK_TYPE_1xRTT:
@@ -1068,6 +1086,8 @@
                 return "iDEN";
             case NETWORK_TYPE_HSPAP:
                 return "HSPA+";
+            case NETWORK_TYPE_GSM:
+                return "GSM";
             default:
                 return "UNKNOWN";
         }
diff --git a/telephony/java/com/android/internal/telephony/CallInfo.aidl b/telephony/java/com/android/internal/telephony/CallInfo.aidl
new file mode 100644
index 0000000..9140388
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/CallInfo.aidl
@@ -0,0 +1,19 @@
+/*
+** 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.
+*/
+
+package com.android.internal.telephony;
+
+parcelable CallInfo;
diff --git a/telephony/java/com/android/internal/telephony/CallInfo.java b/telephony/java/com/android/internal/telephony/CallInfo.java
new file mode 100644
index 0000000..6bfc9d7
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/CallInfo.java
@@ -0,0 +1,77 @@
+/*
+** 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.
+*/
+
+package com.android.internal.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ *  A parcelable holder class of Call information data.
+ */
+public class CallInfo implements Parcelable {
+
+    /**
+     * Endpoint to which the call is connected.
+     * This could be the dialed value for outgoing calls or the caller id of incoming calls.
+     */
+    private String handle;
+
+    public CallInfo(String handle) {
+        this.handle = handle;
+    }
+
+    public String getHandle() {
+        return handle;
+    }
+
+    //
+    // Parcelling related code below here.
+    //
+
+    /**
+     * Responsible for creating CallInfo objects for deserialized Parcels.
+     */
+    public static final Parcelable.Creator<CallInfo> CREATOR
+            = new Parcelable.Creator<CallInfo> () {
+
+        @Override
+        public CallInfo createFromParcel(Parcel source) {
+            return new CallInfo(source.readString());
+        }
+
+        @Override
+        public CallInfo[] newArray(int size) {
+            return new CallInfo[size];
+        }
+    };
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Writes CallInfo object into a serializeable Parcel.
+     */
+    @Override
+    public void writeToParcel(Parcel destination, int flags) {
+        destination.writeString(handle);
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/ICallService.aidl b/telephony/java/com/android/internal/telephony/ICallService.aidl
new file mode 100644
index 0000000..cb9b2e8
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ICallService.aidl
@@ -0,0 +1,61 @@
+/*
+ * 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.telephony;
+
+import com.android.internal.telephony.ICallServiceAdapter;
+
+/**
+ * Service interface for services which would like to provide calls to be
+ * managed by the system in-call UI.
+ *
+ * This interface provides methods that the android framework can use to deliver commands
+ * for calls provided by this call service including making new calls and disconnecting
+ * existing ones. A binding to ICallService implementations exists for two conditions:
+ * 1) There exists one or more live calls for that call service,
+ * 2) Prior to an outbound call to test if this call service is compatible with the outgoing call.
+ */
+oneway interface ICallService {
+
+    /**
+     * Determines if the CallService can make calls to the handle.
+     * TODO(santoscordon): Move this method into its own service interface long term.
+     * TODO(santoscordon): Add response callback parameter.
+     */
+    void isCompatibleWith(String handle);
+
+    /**
+     * Attempts to call the relevant party using the specified handle, be it a phone number,
+     * SIP address, or some other kind of user ID.  Note that the set of handle types is
+     * dynamically extensible since call providers should be able to implement arbitrary
+     * handle-calling systems.  See {@link #isCompatibleWith}.
+     * TODO(santoscordon): Should this have a response attached to it to ensure that the call
+     * service actually plans to make the call?
+     */
+    void call(String handle);
+
+    /**
+     * Disconnects the call identified by callId.
+     */
+    void disconnect(String callId);
+
+    /**
+     * Sets an implementation of ICallServiceAdapter which the call service can use to add new calls
+     * and communicate state changes of existing calls. This is the first method that is called
+     * after a the framework binds to the call service.
+     */
+    void setCallServiceAdapter(ICallServiceAdapter callServiceAdapter);
+}
diff --git a/telephony/java/com/android/internal/telephony/ICallServiceAdapter.aidl b/telephony/java/com/android/internal/telephony/ICallServiceAdapter.aidl
new file mode 100644
index 0000000..bc900f0
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ICallServiceAdapter.aidl
@@ -0,0 +1,61 @@
+/*
+ * 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.telephony;
+
+import com.android.internal.telephony.CallInfo;
+
+/**
+ * Provides methods for ICallService implementations to interact with the system phone app.
+ */
+oneway interface ICallServiceAdapter {
+
+    /**
+     * Retrieves a new unique call id for use with newOutgoingCall and newIncomingCall.
+     */
+    void getNextCallId(/* TODO(santoscordon): Needs response object */);
+
+    /**
+     * Tells CallsManager of a new incoming call.
+     */
+    void newIncomingCall(String callId, in CallInfo info);
+
+    /**
+     * Tells CallsManager of a new outgoing call.
+     */
+    void newOutgoingCall(String callId, in CallInfo info);
+
+    /**
+     * Sets a call's state to active (e.g., an ongoing call where two parties can actively
+     * communicate).
+     */
+    void setActive(String callId);
+
+    /**
+     * Sets a call's state to ringing (e.g., an inbound ringing call).
+     */
+    void setRinging(String callId);
+
+    /**
+     * Sets a call's state to dialing (e.g., dialing an outbound call).
+     */
+    void setDialing(String callId);
+
+    /**
+     * Sets a call's state to disconnected.
+     */
+    void setDisconnected(String callId);
+}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index fa74494..72398ad 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -16,6 +16,7 @@
 
 package com.android.internal.telephony;
 
+import android.content.ComponentName;
 import android.os.Bundle;
 import android.telephony.CellInfo;
 import android.telephony.NeighboringCellInfo;
@@ -24,6 +25,8 @@
 
 import java.util.List;
 
+import java.util.List;
+
 /**
  * Interface used to interact with the phone.  Mostly this is used by the
  * TelephonyManager class.  A few places are still using this directly.
@@ -407,7 +410,7 @@
      */
     boolean nvResetConfig(int resetType);
 
-    /**
+    /*
      * Get the preferred network type.
      * Used for device configuration by some CDMA operators.
      *
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 8ea9b0d..b104c11 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -18,7 +18,7 @@
 
 import android.content.Intent;
 import android.net.LinkProperties;
-import android.net.LinkCapabilities;
+import android.net.NetworkCapabilities;
 import android.os.Bundle;
 import android.telephony.CellInfo;
 import android.telephony.DataConnectionRealTimeInfo;
@@ -37,7 +37,7 @@
     void notifyDataActivity(int state);
     void notifyDataConnection(int state, boolean isDataConnectivityPossible,
             String reason, String apn, String apnType, in LinkProperties linkProperties,
-            in LinkCapabilities linkCapabilities, int networkType, boolean roaming);
+            in NetworkCapabilities networkCapabilities, int networkType, boolean roaming);
     void notifyDataConnectionFailed(String reason, String apnType);
     void notifyCellLocation(in Bundle cellLocation);
     void notifyOtaspChanged(in int otaspMode);
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl
new file mode 100644
index 0000000..bcf2d81
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl
@@ -0,0 +1,46 @@
+/*
+ * 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.telephony;
+
+import com.android.internal.telephony.IThirdPartyCallProvider;
+
+/**
+ * Interface provided to ThirdPartyCallService. The service can use this to notify the listener of
+ * changes to the call state.
+ */
+oneway interface IThirdPartyCallListener {
+    /**
+     * Called by the service when a call provider is available to perform the outgoing or incoming
+     * call.
+     */
+    void onCallProviderAttached(IThirdPartyCallProvider callProvider);
+
+    /**
+     * Notifies the listener that ringing has started for this call.
+     */
+    void onRingingStarted();
+
+    /**
+     * Notifies the listener that the call has been successfully established.
+     */
+    void onCallEstablished();
+
+    /**
+     * Notifies the listener that the call has ended.
+     */
+    void onCallEnded(int reason);
+}
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl
new file mode 100644
index 0000000..9d595b0
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl
@@ -0,0 +1,47 @@
+/*
+ * 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.telephony;
+
+import com.android.internal.telephony.IThirdPartyCallListener;
+import com.android.internal.telephony.IThirdPartyCallSendDtmfCallback;
+
+/**
+ * Interface sent to ThirdPartyCallListener.onCallProviderAttached. This is used to control an
+ * outgoing or incoming call.
+ */
+oneway interface IThirdPartyCallProvider {
+    /**
+     * Mutes or unmutes the call.
+     */
+    void mute(boolean shouldMute);
+
+    /**
+     * Ends the current call. If this is an unanswered incoming call then the call is rejected (for
+     * example, a notification is sent to a server that the user declined the call).
+     */
+    void hangup();
+
+    /**
+     * Accepts the incoming call.
+     */
+    void incomingCallAccept();
+
+    /**
+     * Sends the given DTMF code. The code can be '0'-'9', 'A'-'D', '#', or '*'.
+     */
+    void sendDtmf(char c, IThirdPartyCallSendDtmfCallback callback);
+}
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallSendDtmfCallback.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallSendDtmfCallback.aidl
new file mode 100644
index 0000000..3a02b06
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IThirdPartyCallSendDtmfCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.telephony;
+
+/**
+ * Callback interface for when DTMF has been sent.
+ */
+oneway interface IThirdPartyCallSendDtmfCallback {
+    /**
+     * Called when the DTMF code has been sent.
+     */
+    void onSendDtmfCompleted();
+}
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl
new file mode 100644
index 0000000..597567a
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.telephony;
+
+import com.android.internal.telephony.IThirdPartyCallListener;
+
+/**
+ * Interface provided by a service to start outgoing calls and attach to incoming calls.
+ */
+oneway interface IThirdPartyCallService {
+    /**
+     * Call to start a new outgoing call.
+     */
+    void outgoingCallInitiate(IThirdPartyCallListener listener, String number);
+
+    /**
+     * Call to attach to an incoming call. This is in response to a call to
+     * TelephonyManager.newIncomingThirdPartyCall.
+     */
+    void incomingCallAttach(IThirdPartyCallListener listener, String callId);
+}
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 8c42d25..08f4379 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -57,6 +57,7 @@
     public static final int PHONE_TYPE_GSM = RILConstants.GSM_PHONE;
     public static final int PHONE_TYPE_CDMA = RILConstants.CDMA_PHONE;
     public static final int PHONE_TYPE_SIP = RILConstants.SIP_PHONE;
+    public static final int PHONE_TYPE_THIRD_PARTY = RILConstants.THIRD_PARTY_PHONE;
 
     // Modes for LTE_ON_CDMA
     public static final int LTE_ON_CDMA_UNKNOWN = RILConstants.LTE_ON_CDMA_UNKNOWN;
@@ -78,7 +79,7 @@
     public static final String DATA_APN_TYPE_KEY = "apnType";
     public static final String DATA_APN_KEY = "apn";
     public static final String DATA_LINK_PROPERTIES_KEY = "linkProperties";
-    public static final String DATA_LINK_CAPABILITIES_KEY = "linkCapabilities";
+    public static final String DATA_NETWORK_CAPABILITIES_KEY = "networkCapabilities";
 
     public static final String DATA_IFACE_NAME_KEY = "iface";
     public static final String NETWORK_UNAVAILABLE_KEY = "networkUnvailable";
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index d338857..815211c 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -84,6 +84,7 @@
     int GSM_PHONE = 1;
     int CDMA_PHONE = 2;
     int SIP_PHONE  = 3;
+    int THIRD_PARTY_PHONE = 4;
 
     int LTE_ON_CDMA_UNKNOWN = -1;
     int LTE_ON_CDMA_FALSE = 0;
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 992ef4b..3190fb0 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -33,6 +33,7 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.ManifestDigest;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
@@ -701,4 +702,26 @@
             VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
         throw new UnsupportedOperationException();
     }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void addForwardingIntentFilter(IntentFilter filter, boolean removable, int userIdOrig,
+            int userIdDest) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void clearForwardingIntentFilters(int userIdOrig) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@hide} */
+    public PackageInstaller getPackageInstaller() {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 5c2583b..3e9cf43 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -232,6 +232,15 @@
                 <category android:name="com.android.test.hwui.TEST" />
             </intent-filter>
         </activity>
+
+        <activity
+                android:name="LooperAcceleration"
+                android:label="Misc/LooperAcceleration">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.hwui.TEST" />
+            </intent-filter>
+        </activity>
         
         <activity
                 android:name="TextFadeActivity"
@@ -288,6 +297,15 @@
         </activity>
 
         <activity
+                android:name="CirclePropActivity"
+                android:label="Draw/Circle Props">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.hwui.TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity
                 android:name="ClearActivity"
                 android:label="Window/Clear">
             <intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
new file mode 100644
index 0000000..1d0a806
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.animation.TimeInterpolator;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.CanvasProperty;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.os.Bundle;
+import android.os.Trace;
+import android.view.HardwareCanvas;
+import android.view.RenderNodeAnimator;
+import android.view.View;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.OvershootInterpolator;
+import android.webkit.WebChromeClient;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+import android.widget.ProgressBar;
+
+import java.util.ArrayList;
+
+public class CirclePropActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final LinearLayout layout = new LinearLayout(this);
+        layout.setOrientation(LinearLayout.VERTICAL);
+
+        ProgressBar spinner = new ProgressBar(this, null, android.R.attr.progressBarStyleLarge);
+        layout.addView(spinner, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+        // For testing with a functor in the tree
+//        WebView wv = new WebView(this);
+//        wv.setWebViewClient(new WebViewClient());
+//        wv.setWebChromeClient(new WebChromeClient());
+//        wv.loadUrl("http://theverge.com");
+//        layout.addView(wv, new LayoutParams(LayoutParams.MATCH_PARENT, 100));
+
+        layout.addView(new CircleView(this),
+                new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+
+        setContentView(layout);
+    }
+
+    static class CircleView extends View {
+        static final int DURATION = 500;
+
+        private boolean mToggle = false;
+        ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<RenderNodeAnimator>();
+
+        CanvasProperty<Float> mX;
+        CanvasProperty<Float> mY;
+        CanvasProperty<Float> mRadius;
+        CanvasProperty<Paint> mPaint;
+
+        CircleView(Context c) {
+            super(c);
+            setClickable(true);
+
+            mX = CanvasProperty.createFloat(200.0f);
+            mY = CanvasProperty.createFloat(200.0f);
+            mRadius = CanvasProperty.createFloat(150.0f);
+
+            Paint p = new Paint();
+            p.setAntiAlias(true);
+            p.setColor(0xFFFF0000);
+            p.setStyle(Style.STROKE);
+            p.setStrokeWidth(60.0f);
+            mPaint = CanvasProperty.createPaint(p);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+
+            if (canvas.isHardwareAccelerated()) {
+                HardwareCanvas hwcanvas = (HardwareCanvas) canvas;
+                hwcanvas.drawCircle(mX, mY, mRadius, mPaint);
+            }
+        }
+
+        @Override
+        public boolean performClick() {
+            for (int i = 0; i < mRunningAnimations.size(); i++) {
+                mRunningAnimations.get(i).cancel();
+            }
+            mRunningAnimations.clear();
+
+            mToggle = !mToggle;
+
+            mRunningAnimations.add(new RenderNodeAnimator(
+                    mX, RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 400.0f : 200.0f));
+
+            mRunningAnimations.add(new RenderNodeAnimator(
+                    mY, RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 600.0f : 200.0f));
+
+            mRunningAnimations.add(new RenderNodeAnimator(
+                    mRadius, RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 250.0f : 150.0f));
+
+            mRunningAnimations.add(new RenderNodeAnimator(
+                    mPaint, RenderNodeAnimator.PAINT_ALPHA,
+                    RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 64.0f : 255.0f));
+
+            mRunningAnimations.add(new RenderNodeAnimator(
+                    mPaint, RenderNodeAnimator.PAINT_STROKE_WIDTH,
+                    RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 5.0f : 60.0f));
+
+            TimeInterpolator interp = new OvershootInterpolator(3.0f);
+            for (int i = 0; i < mRunningAnimations.size(); i++) {
+                RenderNodeAnimator anim = mRunningAnimations.get(i);
+                anim.setInterpolator(interp);
+                anim.start(this);
+            }
+
+            if (mToggle) {
+                post(new Runnable() {
+                    @Override
+                    public void run() {
+                        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "pretendBusy");
+                        try {
+                            Thread.sleep(DURATION);
+                        } catch (InterruptedException e) {
+                        }
+                        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+                    }
+                });
+            }
+
+            return true;
+        }
+    }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/LooperAcceleration.java b/tests/HwAccelerationTest/src/com/android/test/hwui/LooperAcceleration.java
new file mode 100644
index 0000000..20d8e11
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/LooperAcceleration.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.graphics.Canvas;
+import android.os.Bundle;
+import android.os.Looper;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.webkit.WebChromeClient;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.LinearLayout;
+
+public class LooperAcceleration extends Activity {
+
+    static final boolean INCLUDE_WEBVIEW = false;
+
+    static class IsAcceleratedView extends View {
+
+        public IsAcceleratedView(Context context) {
+            super(context);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+            if (canvas.isHardwareAccelerated()) {
+                canvas.drawARGB(0xFF, 0x00, 0xFF, 0x00);
+            } else {
+                canvas.drawARGB(0xFF, 0xFF, 0x00, 0x00);
+            }
+        }
+
+    }
+
+    private View makeView() {
+        LinearLayout layout = new LinearLayout(this);
+        layout.addView(new IsAcceleratedView(this), LayoutParams.MATCH_PARENT, 60);
+
+        if (INCLUDE_WEBVIEW) {
+            WebView wv = new WebView(this);
+            wv.setWebViewClient(new WebViewClient());
+            wv.setWebChromeClient(new WebChromeClient());
+            wv.loadUrl("http://www.webkit.org/blog-files/3d-transforms/poster-circle.html");
+            layout.addView(wv, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+        }
+        return layout;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(makeView());
+
+        new Thread() {
+            @Override
+            public void run() {
+                Looper.prepare();
+                final Context context = LooperAcceleration.this;
+                Dialog dlg = new Dialog(context);
+                dlg.addContentView(makeView(), new LayoutParams(300, 400));
+                dlg.setCancelable(true);
+                dlg.setCanceledOnTouchOutside(true);
+                dlg.setOnDismissListener(new DialogInterface.OnDismissListener() {
+                    @Override
+                    public void onDismiss(DialogInterface dialog) {
+                        Looper.myLooper().quit();
+                    }
+                });
+                dlg.setTitle("Not Looper.getMainLooper() check");
+                dlg.show();
+                Looper.loop();
+            }
+        }.start();
+    }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java
index 8c02539..a3f4ddc 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java
@@ -57,7 +57,7 @@
             
             mPaint = new Paint();
             mPaint.setAntiAlias(true);
-            mPaint.setColor(0xffffffff);
+            mPaint.setColor(0xff00ffff);
         }
 
         @Override
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
index 5dc3904..b7dcef7 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
@@ -84,11 +84,12 @@
         Log.d(TAG, "Creating session for package " + mContext.getBasePackageName());
         mSession = man.createSession("OneMedia");
         mSession.addCallback(mCallback);
-        mPerformer = mSession.setTransportPerformerEnabled();
+        mPerformer = mSession.getTransportPerformer();
         mPerformer.addListener(new TransportListener());
         mPerformer.setPlaybackState(mPlaybackState);
+        mSession.setFlags(Session.FLAG_HANDLES_TRANSPORT_CONTROLS);
         mSession.setRouteOptions(mRouteOptions);
-        mSession.publish();
+        mSession.setActive(true);
     }
 
     public void onDestroy() {
@@ -119,7 +120,9 @@
     }
 
     private void updateState(int newState) {
-        mPlaybackState.setState(newState);
+        float rate = newState == PlaybackState.PLAYSTATE_PLAYING ? 1 : 0;
+        long position = mRenderer == null ? -1 : mRenderer.getSeekPosition();
+        mPlaybackState.setState(newState, position, rate);
         mPerformer.setPlaybackState(mPlaybackState);
     }
 
@@ -132,7 +135,7 @@
         @Override
         public void onError(int type, int extra, Bundle extras, Throwable error) {
             Log.d(TAG, "Sending onError with type " + type + " and extra " + extra);
-            mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR);
+            mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR, -1, 0);
             if (error != null) {
                 mPlaybackState.setErrorMessage(error.getLocalizedMessage());
             }
@@ -147,34 +150,33 @@
             if (newState != Renderer.STATE_ERROR) {
                 mPlaybackState.setErrorMessage(null);
             }
+            long position = -1;
+            if (mRenderer != null) {
+                position = mRenderer.getSeekPosition();
+            }
             switch (newState) {
                 case Renderer.STATE_ENDED:
                 case Renderer.STATE_STOPPED:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_STOPPED);
+                    mPlaybackState.setState(PlaybackState.PLAYSTATE_STOPPED, position, 0);
                     break;
                 case Renderer.STATE_INIT:
                 case Renderer.STATE_PREPARING:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_BUFFERING);
+                    mPlaybackState.setState(PlaybackState.PLAYSTATE_BUFFERING, position, 0);
                     break;
                 case Renderer.STATE_ERROR:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR);
+                    mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR, position, 0);
                     break;
                 case Renderer.STATE_PAUSED:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED);
+                    mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED, position, 0);
                     break;
                 case Renderer.STATE_PLAYING:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_PLAYING);
+                    mPlaybackState.setState(PlaybackState.PLAYSTATE_PLAYING, position, 1);
                     break;
                 default:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR);
+                    mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR, position, 0);
                     mPlaybackState.setErrorMessage("unkown state");
                     break;
             }
-            if (mRenderer != null) {
-                mPlaybackState.setPosition(mRenderer.getSeekPosition());
-            } else {
-                mPlaybackState.setPosition(-1);
-            }
             mPerformer.setPlaybackState(mPlaybackState);
             if (mListener != null) {
                 mListener.onPlayStateChanged(mPlaybackState);
@@ -188,8 +190,8 @@
         @Override
         public void onFocusLost() {
             Log.d(TAG, "Focus lost, changing state to " + Renderer.STATE_PAUSED);
-            mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED);
-            mPlaybackState.setPosition(mRenderer.getSeekPosition());
+            long position = mRenderer == null ? -1 : mRenderer.getSeekPosition();
+            mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED, position, 0);
             mPerformer.setPlaybackState(mPlaybackState);
             if (mListener != null) {
                 mListener.onPlayStateChanged(mPlaybackState);
diff --git a/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java b/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
index 6edcd7d..6537d49 100644
--- a/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
+++ b/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
@@ -158,30 +158,33 @@
             if (newState != Renderer.STATE_ERROR) {
                 mPlaybackState.setErrorMessage(null);
             }
+            long position = -1;
+            if (mRenderer != null) {
+                position = mRenderer.getSeekPosition();
+            }
             switch (newState) {
                 case Renderer.STATE_ENDED:
                 case Renderer.STATE_STOPPED:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_STOPPED);
+                    mPlaybackState.setState(PlaybackState.PLAYSTATE_STOPPED, position, 0);
                     break;
                 case Renderer.STATE_INIT:
                 case Renderer.STATE_PREPARING:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_BUFFERING);
+                    mPlaybackState.setState(PlaybackState.PLAYSTATE_BUFFERING, position, 0);
                     break;
                 case Renderer.STATE_ERROR:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR);
+                    mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR, position, 0);
                     break;
                 case Renderer.STATE_PAUSED:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED);
+                    mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED, position, 0);
                     break;
                 case Renderer.STATE_PLAYING:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_PLAYING);
+                    mPlaybackState.setState(PlaybackState.PLAYSTATE_PLAYING, position, 1);
                     break;
                 default:
-                    mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR);
+                    mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR, position, 0);
                     mPlaybackState.setErrorMessage("unkown state");
                     break;
             }
-            mPlaybackState.setPosition(mRenderer.getSeekPosition());
 
             mControls.sendPlaybackChangeEvent(mPlaybackState.getState());
         }
@@ -193,8 +196,8 @@
         @Override
         public void onFocusLost() {
             Log.d(TAG, "Focus lost, changing state to " + Renderer.STATE_PAUSED);
-            mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED);
-            mPlaybackState.setPosition(mRenderer.getSeekPosition());
+            mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED, mRenderer.getSeekPosition(), 0);
+            mRenderer.onPause();
         }
 
         @Override
diff --git a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
index 1d209dd..8f9cf58 100644
--- a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
+++ b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
@@ -19,8 +19,6 @@
 
 public class MainActivity extends Activity implements OnItemClickListener {
 
-    static final int TRANSLATION_Y = 1;
-    static final int DELTA_TYPE_DELTA = 1;
     static final int DURATION = 400;
 
     static final String KEY_NAME = "name";
@@ -75,7 +73,7 @@
             float delta = (pos - clickedPosition) * 1.1f;
             if (delta == 0) delta = -1;
             RenderNodeAnimator animator = new RenderNodeAnimator(
-                    TRANSLATION_Y, DELTA_TYPE_DELTA, dy * delta);
+                    RenderNodeAnimator.TRANSLATION_Y, RenderNodeAnimator.DELTA_TYPE_DELTA, dy * delta);
             animator.setDuration(DURATION);
             animator.start(child);
         }
diff --git a/tests/Split/Android.mk b/tests/Split/Android.mk
new file mode 100644
index 0000000..7884d4d
--- /dev/null
+++ b/tests/Split/Android.mk
@@ -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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_PACKAGE_NAME := Split
+
+LOCAL_AAPT_FLAGS := --split fr,de
+LOCAL_AAPT_FLAGS += -v
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/Split/AndroidManifest.xml b/tests/Split/AndroidManifest.xml
new file mode 100644
index 0000000..a4956a7
--- /dev/null
+++ b/tests/Split/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.example.split">
+    <application android:label="@string/app_title">
+        <activity android:name="ActivityMain">
+            <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/Split/assets/blah.txt b/tests/Split/assets/blah.txt
new file mode 100644
index 0000000..1b37e40
--- /dev/null
+++ b/tests/Split/assets/blah.txt
@@ -0,0 +1 @@
+This is some useful info.
diff --git a/tests/Split/assets/statement.xml b/tests/Split/assets/statement.xml
new file mode 100644
index 0000000..91750d1
--- /dev/null
+++ b/tests/Split/assets/statement.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.
+-->
+
+<statement>
+    <value>Hello</value>
+</statement>
diff --git a/tests/Split/res/layout-fr-sw600dp/main.xml b/tests/Split/res/layout-fr-sw600dp/main.xml
new file mode 100644
index 0000000..2461c8c
--- /dev/null
+++ b/tests/Split/res/layout-fr-sw600dp/main.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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <FrameLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+</FrameLayout>
diff --git a/tests/Split/res/layout/main.xml b/tests/Split/res/layout/main.xml
new file mode 100644
index 0000000..36992a2
--- /dev/null
+++ b/tests/Split/res/layout/main.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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"/>
diff --git a/tests/Split/res/values-de/values.xml b/tests/Split/res/values-de/values.xml
new file mode 100644
index 0000000..26d0507
--- /dev/null
+++ b/tests/Split/res/values-de/values.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.
+-->
+
+<resources>
+    <string name="test">Achtung!</string>
+</resources>
diff --git a/tests/Split/res/values-fr/values.xml b/tests/Split/res/values-fr/values.xml
new file mode 100644
index 0000000..16532da
--- /dev/null
+++ b/tests/Split/res/values-fr/values.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.
+-->
+
+<resources>
+    <string name="app_title">APK Divisé</string>
+    <string name="test">Bonjour, Monde!</string>
+    <string name="blah">Bleh..</string>
+    <string-array name="lotsofstrings">
+        <item>Hé là</item>
+        <item>Au revoir</item>
+    </string-array>
+</resources>
diff --git a/tests/Split/res/values-sw600dp/values.xml b/tests/Split/res/values-sw600dp/values.xml
new file mode 100644
index 0000000..a8329bb
--- /dev/null
+++ b/tests/Split/res/values-sw600dp/values.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.
+-->
+
+<resources>
+    <dimen name="width">230dp</dimen>
+</resources>
diff --git a/tests/Split/res/values/values.xml b/tests/Split/res/values/values.xml
new file mode 100644
index 0000000..68edc77
--- /dev/null
+++ b/tests/Split/res/values/values.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="app_title">Split APK</string>
+    <string name="test">Hello, World!</string>
+    <string name="boom">Boom!</string>
+    <string name="blah">Blah...</string>
+    <string-array name="lotsofstrings">
+        <item>Hello there</item>
+        <item>Good bye</item>
+    </string-array>
+
+    <plurals name="plur">
+        <item quantity="zero">I no haz :(</item>
+        <item quantity="one">I haz 1!1! :)</item>
+        <item quantity="many">I haz ALL!</item>
+    </plurals>
+
+    <bool name="que">true</bool>
+    <color name="green">#00FF00</color>
+    <dimen name="width">23dp</dimen>
+    <item type="id" name="identifier" />
+    <integer name="number">123</integer>
+    <integer-array name="numList">
+        <item>1234</item>
+    </integer-array>
+
+    <array name="ary">
+        <item>@string/test</item>
+        <item>@string/boom</item>
+        <item>25dp</item>
+    </array>
+</resources>
diff --git a/tests/Split/src/java/com/android/example/split/ActivityMain.java b/tests/Split/src/java/com/android/example/split/ActivityMain.java
new file mode 100644
index 0000000..a15fb3c
--- /dev/null
+++ b/tests/Split/src/java/com/android/example/split/ActivityMain.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.example.split;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class ActivityMain extends Activity {
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        TextView text = new TextView(this);
+        text.setText(R.string.test);
+        setContentView(text);
+    }
+}
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
index bb2bebf..118f258 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:trigger="state_checked" android:versionCode="1" >
+    android:versionCode="1" >
 
     <size
         android:height="48dp"
@@ -24,55 +24,12 @@
         android:viewportHeight="480"
         android:viewportWidth="480" />
 
-    <group>
-        <path
-            android:name="check"
-            android:pathData="m20,200l100,90l180,-180l-35,-35l-145,145l-60,-60l-40,40z"
-            android:fill="?android:attr/colorControlActivated" />
-    </group>
-    <group>
-        <path
-            android:name="box1"
-            android:pathData="m127,171l37,38l33,-31l-37,-40l-1,3l-2,0l-30,30z"
-            android:fill="?android:attr/colorControlActivated"
-            android:stroke="?android:attr/colorControlActivated"
-            android:strokeLineCap="round"
-            android:strokeLineJoin="round" />
-    </group>
-    <group>
-        <path
-            android:name="box2"
-            android:pathData="m127,171l37,38l33,-31l-37,-40l-1,3l-2,0l-30,30z"
-            android:rotation="46.757"
-            android:pivotX="162"
-            android:pivotY="173.5"
-            android:fill="?android:attr/colorControlNormal"
-            android:stroke="?android:attr/colorControlNormal"
-            android:strokeWidth="3"
-            android:strokeLineCap="round"
-            android:strokeLineJoin="round" />
-    </group>
-    <group>
-        <path
-            android:name="box3"
-            android:pathData="m187,147l-1,55l-49,-1l2,-53l48,0z"
-            android:stroke="?android:attr/colorControlNormal"
-            android:strokeWidth="10"
-            android:strokeLineCap="round"
-            android:strokeLineJoin="round" />
-    </group>
-    <group>
-        <path
-            android:name="box4"
-            android:pathData="m248,74l0,164l-177,0l1,-165l173,-1l3,2z"
-            android:stroke="?android:attr/colorControlNormal"
-            android:strokeWidth="30"
-            android:strokeLineCap="round"
-            android:strokeLineJoin="round" />
-    </group>
+    <path
+        android:name="box1"
+        android:fill="?android:attr/colorControlActivated"
+        android:pathData="m20,200l100,90l180,-180l-35,-35l-145,145l-60,-60l-40,40z"
+        android:stroke="?android:attr/colorControlActivated"
+        android:strokeLineCap="round"
+        android:strokeLineJoin="round" />
 
-    <animation
-        android:durations="300,100,0,300"
-        android:sequence="check,box1,box2,box3,box4" />
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
index 49906d17..034f7a0 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+ Copyright (C) 2014 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -15,32 +16,23 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android" >
 
     <size
-            android:width="64dp"
-            android:height="64dp"/>
+        android:height="64dp"
+        android:width="64dp" />
 
-    <viewport android:viewportWidth="320"
-          android:viewportHeight="320"/>
+    <viewport
+        android:viewportHeight="320"
+        android:viewportWidth="320" />
 
-    <group>
-        <path
-                android:name="arrow"
-                android:pathData="M 100,225 L 100,115 L 130,115 L 70,15 L 10,115 L 40,115 L 40,225 z"
-                android:fill="#ffffffff"
-                android:stroke="#FF00FF00"
-                android:strokeWidth="1"/>
-    </group>
-    <group>
-        <path
-                android:name="house"
-                android:pathData="M 130,225 L 130,115 L 130,115 L 70,15 L 10,115 L 10,115 L 10,225 z"
-                android:fill="#ff440000"
-                android:stroke="#FF00FF00"
-                android:strokeWidth="10"
-                android:rotation="180"
-                android:pivotX="70"
-                android:pivotY="120"
-                android:trimPathStart=".1"
-                android:trimPathEnd=".9"/>
-    </group>
-    <animation android:sequence="arrow,house"/>
-</vector>
+    <path
+        android:name="house"
+        android:fill="#ff440000"
+        android:pathData="M 130,225 L 130,115 L 130,115 L 70,15 L 10,115 L 10,115 L 10,225 z"
+        android:pivotX="70"
+        android:pivotY="120"
+        android:rotation="180"
+        android:stroke="#FF00FF00"
+        android:strokeWidth="10"
+        android:trimPathEnd=".9"
+        android:trimPathStart=".1" />
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
index 137049d..451b28e 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+ Copyright (C) 2014 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -15,51 +16,47 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android" >
 
     <size
-            android:width="64dp"
-            android:height="64dp"/>
+        android:height="64dp"
+        android:width="64dp" />
 
     <viewport
-            android:viewportWidth="7.30625"
-            android:viewportHeight="12.25"/>
+        android:viewportHeight="12.25"
+        android:viewportWidth="7.30625" />
 
-    <group>
-
-        <path
-                android:name="clip1"
-                android:pathData="
+    <path
+        android:name="clip1"
+        android:clipToPath="true"
+        android:pathData="
                 M 0, 0
                 l 7.3, 0
                 l 0, 0
                 l -7.3, 0
                 z"
-                android:clipToPath="true"
-                android:rotation="-30"
-                android:pivotX="3.65"
-                android:pivotY="6.125"
-                />
-        <path
-                android:name="one"
-                android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
+        android:pivotX="3.65"
+        android:pivotY="6.125"
+        android:rotation="-30" />
+    <path
+        android:name="one"
+        android:fill="#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"
-                android:fill="#ff88ff"
-                />
-        <path
-                android:name="clip2"
-                android:pathData="
+                l -5.046875,0.0 0.0,-1.0Z" />
+    <path
+        android:name="clip2"
+        android:clipToPath="true"
+        android:pathData="
                 M 0, 0
                 l 7.3, 0
                 l 0, 12.25
                 l -7.3, 0
                 z"
-                android:clipToPath="true"
-                android:rotation="-30"
-                android:pivotX="3.65"
-                android:pivotY="6.125"
-                />
-        <path
-                android:name="two"
-                android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
+        android:pivotX="3.65"
+        android:pivotY="6.125"
+        android:rotation="-30" />
+    <path
+        android:name="two"
+        android:fill="#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
@@ -67,71 +64,6 @@
                         q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
                         q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
                         q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
-                        q -0.78125024,0.8125 -2.2187502,2.265625Z"
-                android:fill="#ff88ff"
-                />
-    </group>
-    <group>
-        <path
-                android:name="clip1"
-                android:pathData="
-                M 0, 0
-                l 7.3, 0
-                l 0, 12.25
-                l -7.3, 0
-                z"
-                android:clipToPath="true"
-                android:rotation="-30"
-                android:pivotX="3.65"
-                android:pivotY="6.125"
-                />
-        <path
-                android:name="one"
-                android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
-                l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
-                l -5.046875,0.0 0.0,-1.0Z"
-                android:fill="#ff88ff"
-                />
-        <path
-                android:name="clip2"
-                android:pathData="
-                M 0, 12.25
-                l 7.3, 0
-                l 0, 12.25
-                l -7.3, 0
-                z"
-                android:clipToPath="true"
-                android:rotation="-30"
-                android:pivotX="3.65"
-                android:pivotY="6.125"
-                />
-        <path
-                android:name="two"
-                android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
-                        q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
-                        q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
-                        q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
-                        q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875
-                        q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
-                        q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
-                        q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
-                        q -0.78125024,0.8125 -2.2187502,2.265625Z"
-                android:fill="#ff88ff"
-                />
-    </group>
+                        q -0.78125024,0.8125 -2.2187502,2.265625Z" />
 
-
-    <animation
-            android:sequence="one,one"
-            android:durations="4000"/>
-    <animation
-            android:sequence="two,two"
-            android:durations="4000"/>
-    <animation
-            android:sequence="clip1,clip1"
-            android:durations="4000"/>
-    <animation
-            android:sequence="clip2,clip2"
-            android:durations="4000"/>
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml
index cffb73f..6f9caa8 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+ Copyright (C) 2014 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -12,48 +13,44 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android">
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
 
     <size
-            android:width="64dp"
-            android:height="64dp"/>
+        android:height="64dp"
+        android:width="64dp" />
 
     <viewport
-            android:viewportWidth="7.30625"
-            android:viewportHeight="12.25"/>
+        android:viewportHeight="12.25"
+        android:viewportWidth="7.30625" />
 
-    <group>
-        <path
-                android:name="clip1"
-                android:pathData="
+    <path
+        android:name="clip1"
+        android:clipToPath="true"
+        android:fill="#112233"
+        android:pathData="
                 M 3.65, 6.125
                 m -.001, 0
                 a .001,.001 0 1,0 .002,0
-                a .001,.001 0 1,0 -.002,0z"
-                android:clipToPath="true"
-                android:fill="#112233"
-                />
-
-        <path
-                android:name="one"
-                android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
+                a .001,.001 0 1,0 -.002,0z" />
+    <path
+        android:name="one"
+        android:fill="#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"
-                android:fill="#ff88ff"
-                />
-        <path
-                android:name="clip2"
-                android:pathData="
+                l -5.046875,0.0 0.0,-1.0Z" />
+    <path
+        android:name="clip2"
+        android:clipToPath="true"
+        android:fill="#112233"
+        android:pathData="
                 M 3.65, 6.125
                 m -6, 0
                 a 6,6 0 1,0 12,0
-                a 6,6 0 1,0 -12,0z"
-                android:clipToPath="true"
-                android:fill="#112233"
-                />
-        <path
-                android:name="two"
-                android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
+                a 6,6 0 1,0 -12,0z" />
+    <path
+        android:name="two"
+        android:fill="#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
@@ -61,66 +58,6 @@
                         q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
                         q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
                         q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
-                        q -0.78125024,0.8125 -2.2187502,2.265625Z"
-                android:fill="#ff88ff"
-                />
-    </group>
-    <group>
-        <path
-                android:name="clip1"
-                android:pathData="
-                M 3.65, 6.125
-                m -6, 0
-                a 6,6 0 1,0 12,0
-                a 6,6 0 1,0 -12,0z"
-                android:clipToPath="true"
-                android:fill="#332233"
-                />
-        <path
-                android:name="one"
-                android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
-                l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
-                l -5.046875,0.0 0.0,-1.0Z"
-                android:fill="#ff88ff"
-                />
-        <path
-                android:name="clip2"
-                android:pathData="
-                 M 3.65, 6.125
-                m -.001, 0
-                a .001,.001 0 1,0 .002,0
-                a .001,.001 0 1,0 -.002,0z"
-                android:clipToPath="true"
-                android:fill="#662233"
-                />
-        <path
-                android:name="two"
-                android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
-                        q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
-                        q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
-                        q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
-                        q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875
-                        q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
-                        q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
-                        q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
-                        q -0.78125024,0.8125 -2.2187502,2.265625Z"
-                android:fill="#ff88ff"
-                />
-    </group>
+                        q -0.78125024,0.8125 -2.2187502,2.265625Z" />
 
-
-
-    <animation
-            android:sequence="one,one"
-            android:durations="4000"/>
-    <animation
-            android:sequence="two,two"
-            android:durations="4000"/>
-    <animation
-            android:sequence="clip1,clip1"
-            android:durations="4000"/>
-    <animation
-            android:sequence="clip2,clip2"
-            android:durations="4000"/>
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
index 0be6755..e6c2557 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
@@ -23,18 +23,17 @@
         android:viewportHeight="12.25"
         android:viewportWidth="7.30625" />
 
-    <group>
-        <path
-            android:name="one"
-            android:fill="#ffff00"
-            android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
+    <path
+        android:name="one"
+        android:fill="#ffff00"
+        android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
                 l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
                 l -5.046875,0.0 0.0,-1.0Z" />
-        <path
-            android:name="two"
-            android:fill="#ffff00"
-            android:fillOpacity="0"
-            android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
+    <path
+        android:name="two"
+        android:fill="#ffff00"
+        android:fillOpacity="0"
+        android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
                         q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
                         q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
                         q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
@@ -43,96 +42,5 @@
                         q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
                         q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
                         q -0.78125024,0.8125 -2.2187502,2.265625Z" />
-    </group>
-    <group>
-        <path
-            android:name="one"
-            android:fill="#ffff00"
-            android:fillOpacity="0"
-            android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
-l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
-l -5.046875,0.0 0.0,-1.0Z" />
-        <path
-            android:name="two"
-            android:fill="#ffff00"
-            android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
-                        q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
-                        q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
-                        q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
-                        q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875
-                        q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
-                        q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
-                        q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
-                        q -0.78125024,0.8125 -2.2187502,2.265625Z" />
-    </group>
-    <group>
-        <path
-            android:name="two"
-            android:fill="#ffff00"
-            android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
-                        q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
-                        q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
-                        q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
-                        q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875
-                        q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
-                        q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
-                        q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
-                        q -0.78125024,0.8125 -2.2187502,2.265625Z" />
-        <path
-            android:name="three"
-            android:fill="#ffff00"
-            android:fillOpacity="0"
-            android:pathData="M 5.103125,6.003125q 0.84375,0.1875 1.3125,0.765625 0.484375,0.5625 0.484375,1.40625
-                        q 0.0,1.296875 -0.890625,2.015625 -0.890625,0.703125 -2.53125,0.703125
-                        q -0.546875,0.0 -1.140625,-0.109375 -0.5781251,-0.109375 -1.1875001,-0.328125
-                        l 0.0,-1.140625q 0.484375,0.28125 1.0625001,0.4375 0.59375,0.140625 1.234375,0.140625
-                        q 1.109375,0.0 1.6875,-0.4375 0.59375,-0.4375 0.59375,-1.28125
-                        q 0.0,-0.765625 -0.546875,-1.203125 -0.546875,-0.4375 -1.5,-0.4375
-                        l -1.03125,0.0 0.0,-0.96875 1.078125,0.0q 0.859375,0.0 1.328125,-0.34375
-                        q 0.46875,-0.359375 0.46875,-1.015625 0.0,-0.671875 -0.484375,-1.03125
-                        q -0.46875,-0.359375 -1.359375,-0.359375 -0.5,0.0 -1.0625,0.109375
-                        q -0.546875,0.09375 -1.2187501,0.3125l 0.0,-1.046875q 0.6875001,-0.1875 1.2656251,-0.28125
-                        q 0.59375,-0.09375 1.109375,-0.09375 1.359375,0.0 2.140625,0.609375
-                        q 0.78125,0.609375 0.78125,1.65625 0.0,0.734375 -0.421875,1.234375
-                        q -0.40625,0.5 -1.171875,0.6875Z" />
-    </group>
-    <group>
-        <path
-            android:name="two"
-            android:fill="#ffff00"
-            android:fillOpacity="0"
-            android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
-                        q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
-                        q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
-                        q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
-                        q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875
-                        q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
-                        q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
-                        q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
-                        q -0.78125024,0.8125 -2.2187502,2.265625Z" />
-        <path
-            android:name="three"
-            android:fill="#ffff00"
-            android:pathData="M 5.103125,6.003125q 0.84375,0.1875 1.3125,0.765625 0.484375,0.5625 0.484375,1.40625
-                        q 0.0,1.296875 -0.890625,2.015625 -0.890625,0.703125 -2.53125,0.703125
-                        q -0.546875,0.0 -1.140625,-0.109375 -0.5781251,-0.109375 -1.1875001,-0.328125
-                        l 0.0,-1.140625q 0.484375,0.28125 1.0625001,0.4375 0.59375,0.140625 1.234375,0.140625
-                        q 1.109375,0.0 1.6875,-0.4375 0.59375,-0.4375 0.59375,-1.28125
-                        q 0.0,-0.765625 -0.546875,-1.203125 -0.546875,-0.4375 -1.5,-0.4375
-                        l -1.03125,0.0 0.0,-0.96875 1.078125,0.0q 0.859375,0.0 1.328125,-0.34375
-                        q 0.46875,-0.359375 0.46875,-1.015625 0.0,-0.671875 -0.484375,-1.03125
-                        q -0.46875,-0.359375 -1.359375,-0.359375 -0.5,0.0 -1.0625,0.109375
-                        q -0.546875,0.09375 -1.2187501,0.3125l 0.0,-1.046875q 0.6875001,-0.1875 1.2656251,-0.28125
-                        q 0.59375,-0.09375 1.109375,-0.09375 1.359375,0.0 2.140625,0.609375
-                        q 0.78125,0.609375 0.78125,1.65625 0.0,0.734375 -0.421875,1.234375
-                        q -0.40625,0.5 -1.171875,0.6875Z" />
-    </group>
-
-    <animation
-        android:durations="2000,0,2000"
-        android:sequence="one,one,three,three" />
-    <animation
-        android:durations="2000,0,2000"
-        android:sequence="two,two,two,two" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml
index 73ff5e2..3f8cc09 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+ Copyright (C) 2014 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -15,62 +16,38 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android" >
 
     <size
-            android:width="64dp"
-            android:height="64dp"/>
+        android:height="64dp"
+        android:width="64dp" />
 
     <viewport
-            android:viewportWidth="700"
-            android:viewportHeight="700"/>
+        android:viewportHeight="700"
+        android:viewportWidth="700" />
 
-    <group>
-    </group>
-    <path android:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z"
-          android:name="path2451"
-          android:stroke="#FF000000"
-          android:strokeWidth="30.65500000000000"/>
-    <path android:pathData="M 365.015 311.066"
-          android:name="path2453"
-          android:stroke="#FF000000"
-          android:strokeWidth="30.655000000000001"/>
-    <path android:pathData="M 164.46 164.49L 340.78 343.158C 353.849 356.328 377.63 356.172 390.423 343.278L 566.622 165.928"
-          android:name="path2455"
-          android:stroke="#FF000000"
-          android:fill="#FF0000FF"
-          android:strokeWidth="30.655000000000001"/>
-    <path android:pathData="M 170.515 451.566L 305.61 313.46"
-          android:name="path2457"
-          android:stroke="#000000"
-          android:strokeWidth="30.655000000000001"/>
-    <path android:pathData="M 557.968 449.974L 426.515 315.375"
-          android:name="path2459"
-          android:stroke="#000000"
-          android:strokeWidth="30.655000000000001"/>
-    <group>
-        <path android:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z"
-              android:name="path2451"
-              android:stroke="#FF000000"
-              android:strokeWidth="30.65500000000000"/>
-        <path android:pathData="M 365.015 311.066"
-              android:name="path2453"
-              android:stroke="#FF000000"
-              android:strokeWidth="30.655000000000001"/>
-        <path android:pathData="M 164.46 164.49L 340.78 343.158C 353.849 356.328 377.63 356.172 390.423 343.278L 566.622 165.928"
-              android:name="path2455"
-              android:stroke="#FF000000"
-              android:fill="#FFFFFFFF"
-              android:strokeWidth="30.655000000000001"/>
-        <path android:pathData="M 170.515 451.566L 305.61 313.46"
-              android:name="path2457"
-              android:stroke="#000000"
-              android:strokeWidth="30.655000000000001"/>
-        <path android:pathData="M 557.968 449.974L 426.515 315.375"
-              android:name="path2459"
-              android:stroke="#000000"
-              android:strokeWidth="30.655000000000001"/>
-    </group>
+    <path
+        android:name="path2451"
+        android:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z"
+        android:stroke="#FF000000"
+        android:strokeWidth="30.65500000000000" />
+    <path
+        android:name="path2453"
+        android:pathData="M 365.015 311.066"
+        android:stroke="#FF000000"
+        android:strokeWidth="30.655000000000001" />
+    <path
+        android:name="path2455"
+        android:fill="#FFFFFFFF"
+        android:pathData="M 164.46 164.49L 340.78 343.158C 353.849 356.328 377.63 356.172 390.423 343.278L 566.622 165.928"
+        android:stroke="#FF000000"
+        android:strokeWidth="30.655000000000001" />
+    <path
+        android:name="path2457"
+        android:pathData="M 170.515 451.566L 305.61 313.46"
+        android:stroke="#000000"
+        android:strokeWidth="30.655000000000001" />
+    <path
+        android:name="path2459"
+        android:pathData="M 557.968 449.974L 426.515 315.375"
+        android:stroke="#000000"
+        android:strokeWidth="30.655000000000001" />
 
-    <animation android:sequence="path2451,path2451"
-        android:durations="1000"/>
-
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml
index 99d37ef..4db5090 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+ Copyright (C) 2014 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -12,34 +13,21 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"   >
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+
     <size
-            android:width="64dp"
-            android:height="64dp"/>
+        android:height="64dp"
+        android:width="64dp" />
 
-    <viewport android:viewportWidth="140"
-          android:viewportHeight="110"/>
-    <group>
-        <path
-                android:name="menu"
-                android:pathData="M 20,20 l 100,0 0,10 -100,0 z
-              M 20,50 l 100,0 0,10 -100,0 z
-              M 20,80 l 0,-10 100,0 0,10 z"
-                android:fill="#ffffffff"/>
-    </group>
-    <group>
-        <path
-                android:name="back"
-                android:pathData="M 20,55 l 35.3,-35.3 7.07,7.07 -35.3,35.3 z
+    <viewport
+        android:viewportHeight="110"
+        android:viewportWidth="140" />
+
+    <path
+        android:name="back"
+        android:fill="#ffffffff"
+        android:pathData="M 20,55 l 35.3,-35.3 7.07,7.07 -35.3,35.3 z
               M 27,50 l 97,0 0,10 -97,0 z
-              M 20,55 l 7.07,-7.07 35.3,35.3 -7.07,7.07 z"
-                android:fill="#ffffffff"
-                android:rotation="180"
-                android:pivotX="70"
-                android:pivotY="55"
-                />
-    </group>
-    <animation android:sequence="menu,back"/>
+              M 20,55 l 7.07,-7.07 35.3,35.3 -7.07,7.07 z" />
 
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
index f8a03d7..44ef979 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+ Copyright (C) 2014 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -15,34 +16,18 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android" >
 
     <size
-            android:width="64dp"
-            android:height="64dp"/>
+        android:height="64dp"
+        android:width="64dp" />
 
+    <viewport
+        android:viewportHeight="600"
+        android:viewportWidth="600" />
 
-    <viewport android:viewportWidth="600"
-          android:viewportHeight="600"/>
+    <path
+        android:name="pie1"
+        android:fill="#ffffcc00"
+        android:pathData="M535.441,412.339A280.868,280.868 0 1,1 536.186,161.733L284.493,286.29Z"
+        android:stroke="#FF00FF00"
+        android:strokeWidth="1" />
 
-    <group>
-        <path
-                android:name="pie1"
-                android:pathData="M535.441,412.339A280.868,280.868 0 1,1 536.186,161.733L284.493,286.29Z"
-                android:fill="#ffffcc00"
-                android:stroke="#FF00FF00"
-                android:strokeWidth="1"/>
-    </group>
-
-    <group>
-        <path
-                android:name="pie2"
-                android:pathData="M564.441,287A280.868,280.868 0 1,1 564.441,285L284.493,286.29Z"
-                android:fill="#FFccaa00"
-                android:stroke="#FF000000"
-                android:strokeWidth="10"
-                android:pivotX="90"
-                android:pivotY="100"/>
-    </group>
-
-    <animation android:sequence="pie1,pie2"/>
-
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
index b3c91a88..248a143 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
@@ -23,22 +23,12 @@
         android:viewportHeight="200"
         android:viewportWidth="200" />
 
-    <group>
-        <path
-            android:name="arrow"
-            android:fill="#ffffffff"
-            android:pathData="M 20,20 l 60,0 0,140 -60,0 z M 120,20 l 60,0 0,140 -60,0 z" />
-    </group>
-    <group>
-        <path
-            android:name="house"
-            android:fill="#ffffffff"
-            android:pathData="M 100,20 l 0,0 0,140 -80,0 z M 100,20 l 0,0 80,140 -80,0 z"
-            android:pivotX="100"
-            android:pivotY="100"
-            android:rotation="90" />
-    </group>
-
-    <animation android:sequence="arrow,house" />
+    <path
+        android:name="house"
+        android:fill="#ffffffff"
+        android:pathData="M 100,20 l 0,0 0,140 -80,0 z M 100,20 l 0,0 80,140 -80,0 z"
+        android:pivotX="100"
+        android:pivotY="100"
+        android:rotation="90" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
index 7aca169..56c2972 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
@@ -24,90 +24,21 @@
         android:viewportHeight="200"
         android:viewportWidth="200" />
 
-    <group>
-        <path
-            android:name="bar3"
-            android:fill="#FFFFFFFF"
-            android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" />
-        <path
-            android:name="bar2"
-            android:fill="#FF555555"
-            android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
-        <path
-            android:name="bar1"
-            android:fill="#FF555555"
-            android:pathData="M14.001,34.645   L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
-        <path
-            android:name="bar0"
-            android:fill="#FF555555"
-            android:pathData="M0,20.502l6.999,7.071   c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" />
-    </group>
-    <group>
-        <path
-            android:name="bar3"
-            android:fill="#FFFFFFFF"
-            android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" />
-        <path
-            android:name="bar2"
-            android:fill="#FFFFFFFF"
-            android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
-        <path
-            android:name="bar1"
-            android:fill="#FF555555"
-            android:pathData="M14.001,34.645   L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
-        <path
-            android:name="bar0"
-            android:fill="#FF555555"
-            android:pathData="M0,20.502l6.999,7.071   c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" />
-    </group>
-    <group>
-        <path
-            android:name="bar3"
-            android:fill="#FFFFFFFF"
-            android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" />
-        <path
-            android:name="bar2"
-            android:fill="#FFFFFFFF"
-            android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
-        <path
-            android:name="bar1"
-            android:fill="#FFFFFFFF"
-            android:pathData="M14.001,34.645   L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
-        <path
-            android:name="bar0"
-            android:fill="#FF555555"
-            android:pathData="M0,20.502l6.999,7.071   c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" />
-    </group>
-    <group>
-        <path
-            android:name="bar3"
-            android:fill="#FFFFFFFF"
-            android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" />
-        <path
-            android:name="bar2"
-            android:fill="#FFFFFFFF"
-            android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
-        <path
-            android:name="bar1"
-            android:fill="#FFFFFFFF"
-            android:pathData="M14.001,34.645   L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
-        <path
-            android:name="bar0"
-            android:fill="#FFFFFFFF"
-            android:pathData="M0,20.502l6.999,7.071   c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" />
-    </group>
-
-    <animation
-        android:durations="500,500,500"
-        android:sequence="bar0,bar0,bar0,bar0" />
-    <animation
-        android:durations="500,500,500"
-        android:sequence="bar1,bar1,bar1,bar1" />
-    <animation
-        android:durations="500,500,500"
-        android:sequence="bar2,bar2,bar2,bar2" />
-    <animation
-        android:durations="500,500,500"
-        android:sequence="bar3,bar3,bar3,bar3" />
+    <path
+        android:name="bar3"
+        android:fill="#FFFFFFFF"
+        android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" />
+    <path
+        android:name="bar2"
+        android:fill="#FFFFFFFF"
+        android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
+    <path
+        android:name="bar1"
+        android:fill="#FF555555"
+        android:pathData="M14.001,34.645   L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
+    <path
+        android:name="bar0"
+        android:fill="#FF555555"
+        android:pathData="M0,20.502l6.999,7.071   c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
index a4403c5..16d8b48 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
@@ -23,38 +23,16 @@
         android:viewportHeight="80"
         android:viewportWidth="40" />
 
-    <group>
-        <path
-            android:name="battery"
-            android:fill="#3388ff"
-            android:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z"
-            android:rotation="0"
-            android:stroke="#ff8833"
-            android:strokeWidth="1" />
-        <path
-            android:name="spark"
-            android:fill="#FFFF0000"
-            android:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" />
-    </group>
-    <group>
-        <path
-            android:name="battery"
-            android:fill="#ff8833"
-            android:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z"
-            android:rotation="0"
-            android:stroke="#3388ff"
-            android:strokeWidth="1" />
-        <path
-            android:name="spark"
-            android:fill="#FFFF0000"
-            android:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" />
-    </group>
-
-    <animation
-        android:durations="2000"
-        android:sequence="spark,spark" />
-    <animation
-        android:durations="2000"
-        android:sequence="battery,battery" />
+    <path
+        android:name="battery"
+        android:fill="#3388ff"
+        android:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z"
+        android:rotation="0"
+        android:stroke="#ff8833"
+        android:strokeWidth="1" />
+    <path
+        android:name="spark"
+        android:fill="#FFFF0000"
+        android:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
index 207879d..0a0407d 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
@@ -23,65 +23,20 @@
         android:viewportHeight="600"
         android:viewportWidth="600" />
 
-    <group>
-        <path
-            android:name="pie1"
-            android:pathData="M300,70 a230,230 0 1,0 1,0 z"
-            android:stroke="#FF00FF00"
-            android:strokeWidth="70"
-            android:trimPathEnd=".75"
-            android:trimPathOffset="0"
-            android:trimPathStart="0" />
-        <path
-            android:name="v"
-            android:fill="#FF00FF00"
-            android:pathData="M300,70 l 0,-70 70,70 -70,70z"
-            android:pivotX="300"
-            android:pivotY="300"
-            android:rotation="0" />
-    </group>
-    <group>
-        <path
-            android:name="v"
-            android:pathData="M300,70 l 0,-70 70,70 -70,70z"
-            android:pivotX="300"
-            android:pivotY="300"
-            android:rotation="360" />
-        <path
-            android:name="pie2"
-            android:pathData="M300,70 a230,230 0 1,0 1,0 z"
-            android:pivotX="300"
-            android:pivotY="300"
-            android:rotation="360"
-            android:stroke="#FF00FF00"
-            android:strokeLineCap="round"
-            android:strokeWidth="70"
-            android:trimPathEnd=".5"
-            android:trimPathOffset="0"
-            android:trimPathStart="0" />
-    </group>
-
-    <animation
-        android:animate="easeInOut"
-        android:durations="2000"
-        android:repeatCount="-1"
-        android:repeatStyle="forward"
-        android:sequence="pie1,pie2"
-        android:startOffset="500" />
-    <animation
-        android:animate="easeInOut"
-        android:durations="2000"
-        android:repeatCount="-1"
-        android:repeatStyle="forward"
-        android:sequence="v,v"
-        android:startOffset="500" />
-    <animation
-        android:animate="easeInOut"
-        android:durations="2800"
-        android:limitTo="trimPathEnd"
-        android:repeatCount="-1"
-        android:repeatStyle="reverse"
-        android:sequence="pie1,pie2"
-        android:startOffset="500" />
+    <path
+        android:name="pie1"
+        android:pathData="M300,70 a230,230 0 1,0 1,0 z"
+        android:stroke="#FF00FF00"
+        android:strokeWidth="70"
+        android:trimPathEnd=".75"
+        android:trimPathOffset="0"
+        android:trimPathStart="0" />
+    <path
+        android:name="v"
+        android:fill="#FF00FF00"
+        android:pathData="M300,70 l 0,-70 70,70 -70,70z"
+        android:pivotX="300"
+        android:pivotY="300"
+        android:rotation="0" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
index 4a2ed90..385b1e9 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
@@ -23,57 +23,20 @@
         android:viewportHeight="400"
         android:viewportWidth="600" />
 
-    <group>
-        <path
-            android:name="pie1"
-            android:fill="#ffffffff"
-            android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
-            android:stroke="#FF00FF00"
-            android:strokeWidth="1" />
-        <path
-            android:name="half"
-            android:fill="#FFFF0000"
-            android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
-            android:pivotX="300"
-            android:pivotY="200"
-            android:rotation="0"
-            android:stroke="#FF0000FF"
-            android:strokeWidth="5" />
-    </group>
-    <group>
-        <path
-            android:name="pie2"
-            android:fill="#ffff0000"
-            android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
-            android:pivotX="300"
-            android:pivotY="200"
-            android:rotation="360"
-            android:stroke="#FF00FF00"
-            android:strokeWidth="10" />
-        <path
-            android:name="half"
-            android:fill="#FFFFFF00"
-            android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
-            android:pivotX="300"
-            android:pivotY="200"
-            android:rotation="-360"
-            android:stroke="#FF0000FF"
-            android:strokeWidth="5" />
-    </group>
-
-    <animation
-        android:animate="easeInOut"
-        android:durations="1000"
-        android:repeatCount="2"
-        android:repeatStyle="forward"
-        android:sequence="pie1,pie2"
-        android:startOffset="500" />
-    <animation
-        android:animate="easeInOut"
-        android:durations="1000"
-        android:repeatCount="5"
-        android:repeatStyle="forward"
-        android:sequence="half,half"
-        android:startOffset="500" />
+    <path
+        android:name="pie1"
+        android:fill="#ffffffff"
+        android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
+        android:stroke="#FF00FF00"
+        android:strokeWidth="1" />
+    <path
+        android:name="half"
+        android:fill="#FFFF0000"
+        android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
+        android:pivotX="300"
+        android:pivotY="200"
+        android:rotation="0"
+        android:stroke="#FF0000FF"
+        android:strokeWidth="5" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
index 6ebd56b..b701b35 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
@@ -23,32 +23,17 @@
         android:viewportHeight="500"
         android:viewportWidth="800" />
 
-    <group>
-        <path
-            android:name="pie1"
-            android:pathData="M200,450 l 50,-25
-           a25,25 -30 0,1 100,-50 l 50,-25
-           a25,50 -30 0,1 100,-50 l 50,-25
-           a25,75 -30 0,1 100,-50 l 50,-25
-           a25,100 -30 0,1 100,-50 l 50,-25"
-            android:stroke="#FF00FF00"
-            android:strokeWidth="10" />
-    </group>
-    <group>
-        <path
-            android:name="pie2"
-            android:pathData="M200,350 l 50,-25
+    <path
+        android:name="pie2"
+        android:pathData="M200,350 l 50,-25
            a25,12 -30 0,1 100,-50 l 50,-25
            a25,25 -30 0,1 100,-50 l 50,-25
            a25,37 -30 0,1 100,-50 l 50,-25
            a25,50 -30 0,1 100,-50 l 50,-25"
-            android:pivotX="90"
-            android:pivotY="100"
-            android:rotation="20"
-            android:stroke="#FF00FF00"
-            android:strokeWidth="10" />
-    </group>
-
-    <animation android:sequence="pie1,pie2" />
+        android:pivotX="90"
+        android:pivotY="100"
+        android:rotation="20"
+        android:stroke="#FF00FF00"
+        android:strokeWidth="10" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
index 3c92d25..8d773e1 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
@@ -23,26 +23,14 @@
         android:viewportHeight="400"
         android:viewportWidth="500" />
 
-    <group>
-        <path
-            android:name="arrow"
-            android:fill="#ffffffff"
-            android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
-            android:stroke="#FFFF0000"
-            android:strokeWidth="1" />
-    </group>
-    <group>
-        <path
-            android:name="house"
-            android:fill="#ff440000"
-            android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
-            android:pivotX="250"
-            android:pivotY="200"
-            android:rotation="180"
-            android:stroke="#FFFF0000"
-            android:strokeWidth="10" />
-    </group>
-
-    <animation android:sequence="arrow,house" />
+    <path
+        android:name="house"
+        android:fill="#ff440000"
+        android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+        android:pivotX="250"
+        android:pivotY="200"
+        android:rotation="180"
+        android:stroke="#FFFF0000"
+        android:strokeWidth="10" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
index 7e757a5..3b7926c 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
@@ -23,24 +23,13 @@
         android:viewportHeight="200"
         android:viewportWidth="200" />
 
-    <group>
-        <path
-            android:name="arrow"
-            android:pathData="M 100,10 v 180 M 10,100 h 180"
-            android:stroke="#FF00FF00"
-            android:strokeWidth="1" />
-    </group>
-    <group>
-        <path
-            android:name="house"
-            android:pathData="M 100,10 v 90 M 10,100 h 90"
-            android:pivotX="100"
-            android:pivotY="100"
-            android:rotation="360"
-            android:stroke="#FF00FF00"
-            android:strokeWidth="10" />
-    </group>
-
-    <animation android:sequence="arrow,house" />
+    <path
+        android:name="house"
+        android:pathData="M 100,10 v 90 M 10,100 h 90"
+        android:pivotX="100"
+        android:pivotY="100"
+        android:rotation="360"
+        android:stroke="#FF00FF00"
+        android:strokeWidth="10" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
index 9427652..1ec72be 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+ Copyright (C) 2014 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -15,32 +16,20 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android" >
 
     <size
-            android:width="64dp"
-            android:height="64dp"/>
+        android:height="64dp"
+        android:width="64dp" />
 
-    <viewport android:viewportWidth="1200"
-          android:viewportHeight="600"/>
+    <viewport
+        android:viewportHeight="600"
+        android:viewportWidth="1200" />
 
-    <group>
-        <path
-                android:name="arrow"
-                android:pathData="M200,300 Q400,50 600,300 T1000,300"
-                android:stroke="#FF00FF00"
-                android:strokeWidth="1"/>
-    </group>
+    <path
+        android:name="house"
+        android:pathData="M200,300 Q400,50 600,300 T1000,300"
+        android:pivotX="600"
+        android:pivotY="300"
+        android:rotation="360"
+        android:stroke="#FFFF0000"
+        android:strokeWidth="10" />
 
-    <group>
-        <path
-                android:name="house"
-                android:pathData="M200,300 Q400,50 600,300 T1000,300"
-                android:stroke="#FFFF0000"
-                android:strokeWidth="10"
-                android:rotation="360"
-                android:pivotX="600"
-                android:pivotY="300"/>
-    </group>
-
-    <animation android:sequence="arrow,house"/>
-
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
index 69212f5..12d0e93 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
@@ -23,23 +23,13 @@
         android:viewportHeight="400"
         android:viewportWidth="500" />
 
-    <group>
-        <path
-            android:name="arrow"
-            android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
-            android:stroke="#FFFFFF00"
-            android:strokeWidth="10" />
-    </group>
-    <group>
-        <path
-            android:name="house"
-            android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
-            android:pivotX="250"
-            android:pivotY="200"
-            android:rotation="360"
-            android:strokeWidth="10" />
-    </group>
-
-    <animation android:sequence="arrow,house" />
+    <path
+        android:name="house"
+        android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+        android:pivotX="250"
+        android:pivotY="200"
+        android:rotation="360"
+        android:stroke="#FFFFFF00"
+        android:strokeWidth="10" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
index 2dca48d..017e04c 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
@@ -23,23 +23,12 @@
         android:viewportHeight="800"
         android:viewportWidth="1000" />
 
-    <group>
-        <path
-            android:name="arrow"
-            android:pathData="M10,300 Q400,50 600,300 T1000,300"
-            android:stroke="#FF00FFFF"
-            android:strokeWidth="40" />
-    </group>
-    <group>
-        <path
-            android:name="house"
-            android:pathData="M10,300 Q400,550 600,300 T1000,300"
-            android:pivotX="90"
-            android:pivotY="100"
-            android:stroke="#FFFF0000"
-            android:strokeWidth="60" />
-    </group>
-
-    <animation android:sequence="arrow,house" />
+    <path
+        android:name="house"
+        android:pathData="M10,300 Q400,550 600,300 T1000,300"
+        android:pivotX="90"
+        android:pivotY="100"
+        android:stroke="#FFFF0000"
+        android:strokeWidth="60" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
index b8af7e2..b7002a3 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
@@ -23,16 +23,14 @@
         android:viewportHeight="480"
         android:viewportWidth="480" />
 
-    <group>
-        <path
-            android:name="edit"
-            android:fill="#FF00FFFF"
-            android:pathData="M406.667,180c0,0 -100 -100 -113.334 -113.333
+    <path
+        android:name="edit"
+        android:fill="#FF00FFFF"
+        android:pathData="M406.667,180c0,0 -100 -100 -113.334 -113.333
     c-13.333 -13.334 -33.333,0 -33.333,0l-160,160c0,0 -40,153.333 -40,173.333c0,13.333,13.333,13.333,13.333,13.333l173.334 -40
     c0,0,146.666 -146.666,160 -160C420,200,406.667,180,406.667,180z M226.399,356.823L131.95,378.62l-38.516 -38.522
     c7.848 -34.675,20.152 -82.52,23.538 -95.593l3.027,2.162l106.667,106.666L226.399,356.823z"
-            android:stroke="#FF000000"
-            android:strokeWidth="10" />
-    </group>
+        android:stroke="#FF000000"
+        android:strokeWidth="10" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
index 22ce795..cda213d 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
@@ -23,10 +23,8 @@
         android:viewportHeight="24"
         android:viewportWidth="24" />
 
-    <group>
-        <path
-            android:fill="#FF000000"
-            android:pathData="M3.0,17.25L3.0,21.0l3.75,0.0L17.813995,9.936001l-3.75,-3.75L3.0,17.25zM20.707,7.0429993c0.391,-0.391 0.391,-1.023 0.0,-1.414l-2.336,-2.336c-0.391,-0.391 -1.023,-0.391 -1.414,0.0l-1.832,1.832l3.75,3.75L20.707,7.0429993z" />
-    </group>
+    <path
+        android:fill="#FF000000"
+        android:pathData="M3.0,17.25L3.0,21.0l3.75,0.0L17.813995,9.936001l-3.75,-3.75L3.0,17.25zM20.707,7.0429993c0.391,-0.391 0.391,-1.023 0.0,-1.414l-2.336,-2.336c-0.391,-0.391 -1.023,-0.391 -1.414,0.0l-1.832,1.832l3.75,3.75L20.707,7.0429993z" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
index 042173c..2cb6381 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
@@ -23,10 +23,8 @@
         android:viewportHeight="24"
         android:viewportWidth="24" />
 
-    <group>
-        <path
-            android:fill="#FF000000"
-            android:pathData="M6.0,19.0c0.0,1.104 0.896,2.0 2.0,2.0l8.0,0.0c1.104,0.0 2.0,-0.896 2.0,-2.0l0.0,-12.0L6.0,7.0L6.0,19.0zM18.0,4.0l-2.5,0.0l-1.0,-1.0l-5.0,0.0l-1.0,1.0L6.0,4.0C5.4469986,4.0 5.0,4.4469986 5.0,5.0l0.0,1.0l14.0,0.0l0.0,-1.0C19.0,4.4469986 18.552002,4.0 18.0,4.0z" />
-    </group>
+    <path
+        android:fill="#FF000000"
+        android:pathData="M6.0,19.0c0.0,1.104 0.896,2.0 2.0,2.0l8.0,0.0c1.104,0.0 2.0,-0.896 2.0,-2.0l0.0,-12.0L6.0,7.0L6.0,19.0zM18.0,4.0l-2.5,0.0l-1.0,-1.0l-5.0,0.0l-1.0,1.0L6.0,4.0C5.4469986,4.0 5.0,4.4469986 5.0,5.0l0.0,1.0l14.0,0.0l0.0,-1.0C19.0,4.4469986 18.552002,4.0 18.0,4.0z" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
index 6b6f43d..d58942e 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
@@ -23,10 +23,8 @@
         android:viewportHeight="24"
         android:viewportWidth="24" />
 
-    <group>
-        <path
-            android:fill="#FF000000"
-            android:pathData="M16.0,5.0c-1.955,0.0 -3.83,1.268 -4.5,3.0c-0.67,-1.732 -2.547,-3.0 -4.5,-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207,-5.242 9.0,-7.971 9.0,-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z" />
-    </group>
+    <path
+        android:fill="#FF000000"
+        android:pathData="M16.0,5.0c-1.955,0.0 -3.83,1.268 -4.5,3.0c-0.67,-1.732 -2.547,-3.0 -4.5,-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207,-5.242 9.0,-7.971 9.0,-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
index ba8ebca..4717be4 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
@@ -23,13 +23,11 @@
         android:viewportHeight="24"
         android:viewportWidth="24" />
 
-    <group>
-        <path
-            android:fillOpacity="0.9"
-            android:pathData="M11.994999,2.0C6.4679985,2.0 2.0,6.4780006 2.0,12.0s4.468,10.0 9.995,10.0S22.0,17.522 22.0,12.0S17.521,2.0 11.994999,2.0zM12.0,20.0c-4.42,0.0 -8.0,-3.582 -8.0,-8.0s3.58,-8.0 8.0,-8.0s8.0,3.582 8.0,8.0S16.419998,20.0 12.0,20.0z" />
-        <path
-            android:fillOpacity="0.9"
-            android:pathData="M12.5,6.0l-1.5,0.0 0.0,7.0 5.3029995,3.1819992 0.75,-1.249999 -4.5529995,-2.7320004z" />
-    </group>
+    <path
+        android:fillOpacity="0.9"
+        android:pathData="M11.994999,2.0C6.4679985,2.0 2.0,6.4780006 2.0,12.0s4.468,10.0 9.995,10.0S22.0,17.522 22.0,12.0S17.521,2.0 11.994999,2.0zM12.0,20.0c-4.42,0.0 -8.0,-3.582 -8.0,-8.0s3.58,-8.0 8.0,-8.0s8.0,3.582 8.0,8.0S16.419998,20.0 12.0,20.0z" />
+    <path
+        android:fillOpacity="0.9"
+        android:pathData="M12.5,6.0l-1.5,0.0 0.0,7.0 5.3029995,3.1819992 0.75,-1.249999 -4.5529995,-2.7320004z" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
index 896a938..c626325 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
@@ -23,10 +23,8 @@
         android:viewportHeight="24"
         android:viewportWidth="24" />
 
-    <group>
-        <path
-            android:fill="#FF000000"
-            android:pathData="M19.429,12.975998c0.042,-0.32 0.07,-0.645 0.07,-0.976s-0.029,-0.655 -0.07,-0.976l2.113,-1.654c0.188,-0.151 0.243,-0.422 0.118,-0.639l-2.0,-3.463c-0.125,-0.217 -0.386,-0.304 -0.612,-0.218l-2.49,1.004c-0.516,-0.396 -1.081,-0.731 -1.69,-0.984l-0.375,-2.648C14.456,2.1829987 14.25,2.0 14.0,2.0l-4.0,0.0C9.75,2.0 9.544,2.1829987 9.506,2.422001L9.131,5.0699997C8.521,5.322998 7.957,5.6570015 7.44,6.054001L4.952,5.0509987C4.726,4.965 4.464,5.052002 4.34,5.269001l-2.0,3.463C2.2150002,8.947998 2.27,9.219002 2.4580002,9.369999l2.112,1.653C4.528,11.344002 4.5,11.668999 4.5,12.0s0.029,0.656 0.071,0.977L2.4580002,14.630001c-0.188,0.151 -0.243,0.422 -0.118,0.639l2.0,3.463c0.125,0.217 0.386,0.304 0.612,0.218l2.489,-1.004c0.516,0.396 1.081,0.731 1.69,0.984l0.375,2.648C9.544,21.817001 9.75,22.0 10.0,22.0l4.0,0.0c0.25,0.0 0.456,-0.183 0.494,-0.422l0.375,-2.648c0.609,-0.253 1.174,-0.588 1.689,-0.984l2.49,1.004c0.226,0.086 0.487,-0.001 0.612,-0.218l2.0,-3.463c0.125,-0.217 0.07,-0.487 -0.118,-0.639L19.429,12.975998zM12.0,16.0c-2.21,0.0 -4.0,-1.791 -4.0,-4.0c0.0,-2.21 1.79,-4.0 4.0,-4.0c2.208,0.0 4.0,1.79 4.0,4.0C16.0,14.209 14.208,16.0 12.0,16.0z" />
-    </group>
+    <path
+        android:fill="#FF000000"
+        android:pathData="M19.429,12.975998c0.042,-0.32 0.07,-0.645 0.07,-0.976s-0.029,-0.655 -0.07,-0.976l2.113,-1.654c0.188,-0.151 0.243,-0.422 0.118,-0.639l-2.0,-3.463c-0.125,-0.217 -0.386,-0.304 -0.612,-0.218l-2.49,1.004c-0.516,-0.396 -1.081,-0.731 -1.69,-0.984l-0.375,-2.648C14.456,2.1829987 14.25,2.0 14.0,2.0l-4.0,0.0C9.75,2.0 9.544,2.1829987 9.506,2.422001L9.131,5.0699997C8.521,5.322998 7.957,5.6570015 7.44,6.054001L4.952,5.0509987C4.726,4.965 4.464,5.052002 4.34,5.269001l-2.0,3.463C2.2150002,8.947998 2.27,9.219002 2.4580002,9.369999l2.112,1.653C4.528,11.344002 4.5,11.668999 4.5,12.0s0.029,0.656 0.071,0.977L2.4580002,14.630001c-0.188,0.151 -0.243,0.422 -0.118,0.639l2.0,3.463c0.125,0.217 0.386,0.304 0.612,0.218l2.489,-1.004c0.516,0.396 1.081,0.731 1.69,0.984l0.375,2.648C9.544,21.817001 9.75,22.0 10.0,22.0l4.0,0.0c0.25,0.0 0.456,-0.183 0.494,-0.422l0.375,-2.648c0.609,-0.253 1.174,-0.588 1.689,-0.984l2.49,1.004c0.226,0.086 0.487,-0.001 0.612,-0.218l2.0,-3.463c0.125,-0.217 0.07,-0.487 -0.118,-0.639L19.429,12.975998zM12.0,16.0c-2.21,0.0 -4.0,-1.791 -4.0,-4.0c0.0,-2.21 1.79,-4.0 4.0,-4.0c2.208,0.0 4.0,1.79 4.0,4.0C16.0,14.209 14.208,16.0 12.0,16.0z" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_test01.xml b/tests/VectorDrawableTest/res/drawable/vector_test01.xml
index a9091ab..bad5a46 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_test01.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_test01.xml
@@ -23,12 +23,10 @@
         android:viewportHeight="512"
         android:viewportWidth="512" />
 
-    <group>
-        <path
-            android:name="002b"
-            android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0t-200,299"
-            android:stroke="#FF0000FF"
-            android:strokeWidth="4" />
-    </group>
+    <path
+        android:name="002b"
+        android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0t-200,299"
+        android:stroke="#FF0000FF"
+        android:strokeWidth="4" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_test02.xml b/tests/VectorDrawableTest/res/drawable/vector_test02.xml
index ab58c06..c92b6f4 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_test02.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_test02.xml
@@ -23,12 +23,10 @@
         android:viewportHeight="512"
         android:viewportWidth="512" />
 
-    <group>
-        <path
-            android:name="002b"
-            android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0T-200,299"
-            android:stroke="#FF0000FF"
-            android:strokeWidth="4" />
-    </group>
+    <path
+        android:name="002b"
+        android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0T-200,299"
+        android:stroke="#FF0000FF"
+        android:strokeWidth="4" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java
index 88ae398..7ba01b1 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java
@@ -22,7 +22,7 @@
 import android.widget.GridLayout;
 
 @SuppressWarnings({"UnusedDeclaration"})
-public class VectorDrawable01 extends Activity implements View.OnClickListener {
+public class VectorDrawable01 extends Activity {
     private static final String LOGCAT = "VectorDrawable1";
     int[] icon = {
             R.drawable.vector_drawable01,
@@ -61,28 +61,10 @@
             button.setWidth(200);
             button.setBackgroundResource(icon[i]);
             container.addView(button);
-            button.setOnClickListener(this);
         }
-        Button b = new Button(this);
-        b.setText("Run All");
-        b.setOnClickListener(new View.OnClickListener(){
 
-            @Override
-            public void onClick(View v) {
-                for (int i = 0; i < bArray.length; i++) {
-                    VectorDrawable d = (VectorDrawable)  bArray[i].getBackground();
-                    d.start();
-                }
-            }});
-        container.addView(b);
         setContentView(container);
 
     }
 
-    @Override
-    public void onClick(View v) {
-        VectorDrawable d = (VectorDrawable) v.getBackground();
-        d.start();
-    }
-
 }
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
index 3929298..b918cdd 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
@@ -25,7 +25,7 @@
 import java.text.DecimalFormat;
 
 @SuppressWarnings({"UnusedDeclaration"})
-public class VectorDrawablePerformance extends Activity implements View.OnClickListener {
+public class VectorDrawablePerformance extends Activity {
     private static final String LOGCAT = "VectorDrawable1";
     protected int[] icon = {
             R.drawable.vector_drawable01,
@@ -76,7 +76,6 @@
             button.setWidth(200);
             button.setBackgroundResource(icon[i]);
             container.addView(button);
-            button.setOnClickListener(this);
         }
         setContentView(scrollView);
         time =  android.os.SystemClock.elapsedRealtimeNanos()-time;
@@ -85,10 +84,4 @@
         t.setBackgroundColor(0xFF000000);
         container.addView(t);
     }
-
-    @Override
-    public void onClick(View v) {
-        VectorDrawable d = (VectorDrawable) v.getBackground();
-        d.start();
-    }
 }
diff --git a/tests/VoiceInteraction/res/layout/voice_interaction_session.xml b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
new file mode 100644
index 0000000..9fcbf3e
--- /dev/null
+++ b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
@@ -0,0 +1,38 @@
+<?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="fill_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:background="#ffffffff"
+    >
+
+    <TextView android:id="@+id/text"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="32dp"
+        />
+
+    <Button android:id="@+id/start"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/start"
+        />
+
+</LinearLayout>
+
+
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
index 008d97b..d40b05f 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
@@ -17,6 +17,7 @@
 package com.android.test.voiceinteraction;
 
 import android.content.Intent;
+import android.os.Bundle;
 import android.service.voice.VoiceInteractionService;
 import android.util.Log;
 
@@ -31,7 +32,9 @@
 
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
-        startVoiceActivity(new Intent(this, TestInteractionActivity.class), null);
+        Bundle args = new Bundle();
+        args.putParcelable("intent", new Intent(this, TestInteractionActivity.class));
+        startSession(args);
         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 0fc563b..a3af284 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -17,18 +17,59 @@
 package com.android.test.voiceinteraction;
 
 import android.content.Context;
+import android.content.Intent;
 import android.os.Bundle;
 import android.service.voice.VoiceInteractionSession;
 import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
 
-public class MainInteractionSession extends VoiceInteractionSession {
+public class MainInteractionSession extends VoiceInteractionSession
+        implements View.OnClickListener {
     static final String TAG = "MainInteractionSession";
 
-    final Bundle mArgs;
+    Intent mStartIntent;
+    View mContentView;
+    TextView mText;
+    Button mStartButton;
 
-    MainInteractionSession(Context context, Bundle args) {
+    Request mPendingRequest;
+    boolean mPendingConfirm;
+
+    MainInteractionSession(Context context) {
         super(context);
-        mArgs = args;
+    }
+
+    @Override
+    public void onCreate(Bundle args) {
+        super.onCreate(args);
+        showWindow();
+        mStartIntent = args.getParcelable("intent");
+    }
+
+    @Override
+    public View onCreateContentView() {
+        mContentView = getLayoutInflater().inflate(R.layout.voice_interaction_session, null);
+        mText = (TextView)mContentView.findViewById(R.id.text);
+        mStartButton = (Button)mContentView.findViewById(R.id.start);
+        mStartButton.setOnClickListener(this);
+        return mContentView;
+    }
+
+    public void onClick(View v) {
+        if (mPendingRequest == null) {
+            mStartButton.setEnabled(false);
+            startVoiceActivity(mStartIntent);
+        } else {
+            if (mPendingConfirm) {
+                mPendingRequest.sendConfirmResult(true, null);
+            } else {
+                mPendingRequest.sendCommandResult(true, null);
+            }
+            mPendingRequest = null;
+            mStartButton.setText("Start");
+        }
     }
 
     @Override
@@ -38,14 +79,22 @@
 
     @Override
     public void onConfirm(Caller caller, Request request, String prompt, Bundle extras) {
-        Log.i(TAG, "onConform: prompt=" + prompt + " extras=" + extras);
-        request.sendConfirmResult(true, null);
+        Log.i(TAG, "onConfirm: prompt=" + prompt + " extras=" + extras);
+        mText.setText(prompt);
+        mStartButton.setEnabled(true);
+        mStartButton.setText("Confirm");
+        mPendingRequest = request;
+        mPendingConfirm = true;
     }
 
     @Override
     public void onCommand(Caller caller, Request request, String command, Bundle extras) {
         Log.i(TAG, "onCommand: command=" + command + " extras=" + extras);
-        request.sendCommandResult(true, null);
+        mText.setText("Command: " + command);
+        mStartButton.setEnabled(true);
+        mStartButton.setText("Finish Command");
+        mPendingRequest = request;
+        mPendingConfirm = false;
     }
 
     @Override
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.java
index 8864d71..7cf8178 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.java
@@ -23,6 +23,6 @@
 public class MainInteractionSessionService extends VoiceInteractionSessionService {
     @Override
     public VoiceInteractionSession onNewSession(Bundle args) {
-        return new MainInteractionSession(this, args);
+        return new MainInteractionSession(this);
     }
 }
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index e0dab78..12d5389 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -3,8 +3,10 @@
 //
 
 #include "AaptAssets.h"
-#include "ResourceFilter.h"
+#include "AaptConfig.h"
+#include "AaptUtil.h"
 #include "Main.h"
+#include "ResourceFilter.h"
 
 #include <utils/misc.h>
 #include <utils/SortedVector.h>
@@ -14,7 +16,6 @@
 #include <errno.h>
 
 static const char* kDefaultLocale = "default";
-static const char* kWildcardName = "any";
 static const char* kAssetDir = "assets";
 static const char* kResourceDir = "res";
 static const char* kValuesDir = "values";
@@ -149,24 +150,6 @@
 // =========================================================================
 // =========================================================================
 
-/* static */ void AaptLocaleValue::splitAndLowerCase(const char* const chars,
-        Vector<String8>* parts, const char separator) {
-    const char *p = chars;
-    const char *q;
-    while (NULL != (q = strchr(p, separator))) {
-         String8 val(p, q - p);
-         val.toLower();
-         parts->add(val);
-         p = q+1;
-    }
-
-    if (p < chars + strlen(chars)) {
-        String8 val(p);
-        val.toLower();
-        parts->add(val);
-    }
-}
-
 /* static */
 inline bool isAlpha(const String8& string) {
      const size_t length = string.length();
@@ -230,8 +213,7 @@
 bool AaptLocaleValue::initFromFilterString(const String8& str) {
      // A locale (as specified in the filter) is an underscore separated name such
      // as "en_US", "en_Latn_US", or "en_US_POSIX".
-     Vector<String8> parts;
-     splitAndLowerCase(str.string(), &parts, '_');
+     Vector<String8> parts = AaptUtil::splitAndLowerCase(str, '_');
 
      const int numTags = parts.size();
      bool valid = false;
@@ -301,8 +283,7 @@
     if (part[0] == 'b' && part[1] == '+') {
         // This is a "modified" BCP-47 language tag. Same semantics as BCP-47 tags,
         // except that the separator is "+" and not "-".
-        Vector<String8> subtags;
-        AaptLocaleValue::splitAndLowerCase(part.string(), &subtags, '+');
+        Vector<String8> subtags = AaptUtil::splitAndLowerCase(part, '+');
         subtags.removeItemsAt(0);
         if (subtags.size() == 1) {
             setLanguage(subtags[0]);
@@ -438,1349 +419,46 @@
     }
 }
 
-
-/* static */ bool
-AaptGroupEntry::parseFilterNamePart(const String8& part, int* axis, AxisValue* value)
-{
-    ResTable_config config;
-    memset(&config, 0, sizeof(ResTable_config));
-
-    // IMSI - MCC
-    if (getMccName(part.string(), &config)) {
-        *axis = AXIS_MCC;
-        value->intValue = config.mcc;
-        return true;
-    }
-
-    // IMSI - MNC
-    if (getMncName(part.string(), &config)) {
-        *axis = AXIS_MNC;
-        value->intValue = config.mnc;
-        return true;
-    }
-
-    // locale - language
-    if (value->localeValue.initFromFilterString(part)) {
-        *axis = AXIS_LOCALE;
-        return true;
-    }
-
-    // layout direction
-    if (getLayoutDirectionName(part.string(), &config)) {
-        *axis = AXIS_LAYOUTDIR;
-        value->intValue = (config.screenLayout&ResTable_config::MASK_LAYOUTDIR);
-        return true;
-    }
-
-    // smallest screen dp width
-    if (getSmallestScreenWidthDpName(part.string(), &config)) {
-        *axis = AXIS_SMALLESTSCREENWIDTHDP;
-        value->intValue = config.smallestScreenWidthDp;
-        return true;
-    }
-
-    // screen dp width
-    if (getScreenWidthDpName(part.string(), &config)) {
-        *axis = AXIS_SCREENWIDTHDP;
-        value->intValue = config.screenWidthDp;
-        return true;
-    }
-
-    // screen dp height
-    if (getScreenHeightDpName(part.string(), &config)) {
-        *axis = AXIS_SCREENHEIGHTDP;
-        value->intValue = config.screenHeightDp;
-        return true;
-    }
-
-    // screen layout size
-    if (getScreenLayoutSizeName(part.string(), &config)) {
-        *axis = AXIS_SCREENLAYOUTSIZE;
-        value->intValue = (config.screenLayout&ResTable_config::MASK_SCREENSIZE);
-        return true;
-    }
-
-    // screen layout long
-    if (getScreenLayoutLongName(part.string(), &config)) {
-        *axis = AXIS_SCREENLAYOUTLONG;
-        value->intValue = (config.screenLayout&ResTable_config::MASK_SCREENLONG);
-        return true;
-    }
-
-    // orientation
-    if (getOrientationName(part.string(), &config)) {
-        *axis = AXIS_ORIENTATION;
-        value->intValue = config.orientation;
-        return true;
-    }
-
-    // ui mode type
-    if (getUiModeTypeName(part.string(), &config)) {
-        *axis = AXIS_UIMODETYPE;
-        value->intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
-        return true;
-    }
-
-    // ui mode night
-    if (getUiModeNightName(part.string(), &config)) {
-        *axis = AXIS_UIMODENIGHT;
-        value->intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
-        return true;
-    }
-
-    // density
-    if (getDensityName(part.string(), &config)) {
-        *axis = AXIS_DENSITY;
-        value->intValue = config.density;
-        return true;
-    }
-
-    // touchscreen
-    if (getTouchscreenName(part.string(), &config)) {
-        *axis = AXIS_TOUCHSCREEN;
-        value->intValue = config.touchscreen;
-        return true;
-    }
-
-    // keyboard hidden
-    if (getKeysHiddenName(part.string(), &config)) {
-        *axis = AXIS_KEYSHIDDEN;
-        value->intValue = config.inputFlags;
-        return true;
-    }
-
-    // keyboard
-    if (getKeyboardName(part.string(), &config)) {
-        *axis = AXIS_KEYBOARD;
-        value->intValue = config.keyboard;
-        return true;
-    }
-
-    // navigation hidden
-    if (getNavHiddenName(part.string(), &config)) {
-        *axis = AXIS_NAVHIDDEN;
-        value->intValue = config.inputFlags;
-        return 0;
-    }
-
-    // navigation
-    if (getNavigationName(part.string(), &config)) {
-        *axis = AXIS_NAVIGATION;
-        value->intValue = config.navigation;
-        return true;
-    }
-
-    // screen size
-    if (getScreenSizeName(part.string(), &config)) {
-        *axis = AXIS_SCREENSIZE;
-        value->intValue = config.screenSize;
-        return true;
-    }
-
-    // version
-    if (getVersionName(part.string(), &config)) {
-        *axis = AXIS_VERSION;
-        value->intValue = config.version;
-        return true;
-    }
-
-    return false;
-}
-
-AxisValue
-AaptGroupEntry::getConfigValueForAxis(const ResTable_config& config, int axis)
-{
-    AxisValue value;
-    switch (axis) {
-        case AXIS_MCC:
-            value.intValue = config.mcc;
-            break;
-        case AXIS_MNC:
-            value.intValue = config.mnc;
-            break;
-        case AXIS_LOCALE:
-            value.localeValue.initFromResTable(config);
-            break;
-        case AXIS_LAYOUTDIR:
-            value.intValue = config.screenLayout&ResTable_config::MASK_LAYOUTDIR;
-            break;
-        case AXIS_SCREENLAYOUTSIZE:
-            value.intValue = config.screenLayout&ResTable_config::MASK_SCREENSIZE;
-            break;
-        case AXIS_ORIENTATION:
-            value.intValue = config.orientation;
-            break;
-        case AXIS_UIMODETYPE:
-            value.intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
-            break;
-        case AXIS_UIMODENIGHT:
-            value.intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
-            break;
-        case AXIS_DENSITY:
-            value.intValue = config.density;
-            break;
-        case AXIS_TOUCHSCREEN:
-            value.intValue = config.touchscreen;
-            break;
-        case AXIS_KEYSHIDDEN:
-            value.intValue = config.inputFlags;
-            break;
-        case AXIS_KEYBOARD:
-            value.intValue = config.keyboard;
-            break;
-        case AXIS_NAVIGATION:
-            value.intValue = config.navigation;
-            break;
-        case AXIS_SCREENSIZE:
-            value.intValue = config.screenSize;
-            break;
-        case AXIS_SMALLESTSCREENWIDTHDP:
-            value.intValue = config.smallestScreenWidthDp;
-            break;
-        case AXIS_SCREENWIDTHDP:
-            value.intValue = config.screenWidthDp;
-            break;
-        case AXIS_SCREENHEIGHTDP:
-            value.intValue = config.screenHeightDp;
-            break;
-        case AXIS_VERSION:
-            value.intValue = config.version;
-            break;
-    }
-
-    return value;
-}
-
-bool
-AaptGroupEntry::configSameExcept(const ResTable_config& config,
-        const ResTable_config& otherConfig, int axis)
-{
-    for (int i=AXIS_START; i<=AXIS_END; i++) {
-        if (i == axis) {
-            continue;
-        }
-        if (getConfigValueForAxis(config, i) != getConfigValueForAxis(otherConfig, i)) {
-            return false;
-        }
-    }
-    return true;
-}
-
 bool
 AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
 {
-    mParamsChanged = true;
+    const char* q = strchr(dir, '-');
+    size_t typeLen;
+    if (q != NULL) {
+        typeLen = q - dir;
+    } else {
+        typeLen = strlen(dir);
+    }
 
-    Vector<String8> parts;
-    AaptLocaleValue::splitAndLowerCase(dir, &parts, '-');
-
-    String8 mcc, mnc, layoutsize, layoutlong, orient, den;
-    String8 touch, key, keysHidden, nav, navHidden, size, layoutDir, vers;
-    String8 uiModeType, uiModeNight, smallestwidthdp, widthdp, heightdp;
-
-    AaptLocaleValue locale;
-    int numLocaleComponents = 0;
-
-    const int N = parts.size();
-    int index = 0;
-    String8 part = parts[index];
-
-    // resource type
-    if (!isValidResourceType(part)) {
+    String8 type(dir, typeLen);
+    if (!isValidResourceType(type)) {
         return false;
     }
-    *resType = part;
 
-    index++;
-    if (index == N) {
-        goto success;
-    }
-    part = parts[index];
-
-    // imsi - mcc
-    if (getMccName(part.string())) {
-        mcc = part;
-
-        index++;
-        if (index == N) {
-            goto success;
+    if (q != NULL) {
+        if (!AaptConfig::parse(String8(q + 1), &mParams)) {
+            return false;
         }
-        part = parts[index];
-    } else {
-        //printf("not mcc: %s\n", part.string());
     }
 
-    // imsi - mnc
-    if (getMncName(part.string())) {
-        mnc = part;
-
-        index++;
-        if (index == N) {
-            goto success;
-        }
-        part = parts[index];
-    } else {
-        //printf("not mnc: %s\n", part.string());
-    }
-
-    index = locale.initFromDirName(parts, index);
-    if (index == -1) {
-        return false;
-    }
-    if (index >= N){
-        goto success;
-    }
-
-    part = parts[index];
-    if (getLayoutDirectionName(part.string())) {
-        layoutDir = part;
-
-        index++;
-        if (index == N) {
-            goto success;
-        }
-        part = parts[index];
-    } else {
-        //printf("not layout direction: %s\n", part.string());
-    }
-
-    if (getSmallestScreenWidthDpName(part.string())) {
-        smallestwidthdp = part;
-
-        index++;
-        if (index == N) {
-            goto success;
-        }
-        part = parts[index];
-    } else {
-        //printf("not smallest screen width dp: %s\n", part.string());
-    }
-
-    if (getScreenWidthDpName(part.string())) {
-        widthdp = part;
-
-        index++;
-        if (index == N) {
-            goto success;
-        }
-        part = parts[index];
-    } else {
-        //printf("not screen width dp: %s\n", part.string());
-    }
-
-    if (getScreenHeightDpName(part.string())) {
-        heightdp = part;
-
-        index++;
-        if (index == N) {
-            goto success;
-        }
-        part = parts[index];
-    } else {
-        //printf("not screen height dp: %s\n", part.string());
-    }
-
-    if (getScreenLayoutSizeName(part.string())) {
-        layoutsize = part;
-
-        index++;
-        if (index == N) {
-            goto success;
-        }
-        part = parts[index];
-    } else {
-        //printf("not screen layout size: %s\n", part.string());
-    }
-
-    if (getScreenLayoutLongName(part.string())) {
-        layoutlong = part;
-
-        index++;
-        if (index == N) {
-            goto success;
-        }
-        part = parts[index];
-    } else {
-        //printf("not screen layout long: %s\n", part.string());
-    }
-
-    // orientation
-    if (getOrientationName(part.string())) {
-        orient = part;
-
-        index++;
-        if (index == N) {
-            goto success;
-        }
-        part = parts[index];
-    } else {
-        //printf("not orientation: %s\n", part.string());
-    }
-
-    // ui mode type
-    if (getUiModeTypeName(part.string())) {
-        uiModeType = part;
-
-        index++;
-        if (index == N) {
-            goto success;
-        }
-        part = parts[index];
-    } else {
-        //printf("not ui mode type: %s\n", part.string());
-    }
-
-    // ui mode night
-    if (getUiModeNightName(part.string())) {
-        uiModeNight = part;
-
-        index++;
-        if (index == N) {
-            goto success;
-        }
-        part = parts[index];
-    } else {
-        //printf("not ui mode night: %s\n", part.string());
-    }
-
-    // density
-    if (getDensityName(part.string())) {
-        den = part;
-
-        index++;
-        if (index == N) {
-            goto success;
-        }
-        part = parts[index];
-    } else {
-        //printf("not density: %s\n", part.string());
-    }
-
-    // touchscreen
-    if (getTouchscreenName(part.string())) {
-        touch = part;
-
-        index++;
-        if (index == N) {
-            goto success;
-        }
-        part = parts[index];
-    } else {
-        //printf("not touchscreen: %s\n", part.string());
-    }
-
-    // keyboard hidden
-    if (getKeysHiddenName(part.string())) {
-        keysHidden = part;
-
-        index++;
-        if (index == N) {
-            goto success;
-        }
-        part = parts[index];
-    } else {
-        //printf("not keysHidden: %s\n", part.string());
-    }
-
-    // keyboard
-    if (getKeyboardName(part.string())) {
-        key = part;
-
-        index++;
-        if (index == N) {
-            goto success;
-        }
-        part = parts[index];
-    } else {
-        //printf("not keyboard: %s\n", part.string());
-    }
-
-    // navigation hidden
-    if (getNavHiddenName(part.string())) {
-        navHidden = part;
-
-        index++;
-        if (index == N) {
-            goto success;
-        }
-        part = parts[index];
-    } else {
-        //printf("not navHidden: %s\n", part.string());
-    }
-
-    if (getNavigationName(part.string())) {
-        nav = part;
-
-        index++;
-        if (index == N) {
-            goto success;
-        }
-        part = parts[index];
-    } else {
-        //printf("not navigation: %s\n", part.string());
-    }
-
-    if (getScreenSizeName(part.string())) {
-        size = part;
-
-        index++;
-        if (index == N) {
-            goto success;
-        }
-        part = parts[index];
-    } else {
-        //printf("not screen size: %s\n", part.string());
-    }
-
-    if (getVersionName(part.string())) {
-        vers = part;
-
-        index++;
-        if (index == N) {
-            goto success;
-        }
-        part = parts[index];
-    } else {
-        //printf("not version: %s\n", part.string());
-    }
-
-    // if there are extra parts, it doesn't match
-    return false;
-
-success:
-    this->mcc = mcc;
-    this->mnc = mnc;
-    this->locale = locale;
-    this->screenLayoutSize = layoutsize;
-    this->screenLayoutLong = layoutlong;
-    this->smallestScreenWidthDp = smallestwidthdp;
-    this->screenWidthDp = widthdp;
-    this->screenHeightDp = heightdp;
-    this->orientation = orient;
-    this->uiModeType = uiModeType;
-    this->uiModeNight = uiModeNight;
-    this->density = den;
-    this->touchscreen = touch;
-    this->keysHidden = keysHidden;
-    this->keyboard = key;
-    this->navHidden = navHidden;
-    this->navigation = nav;
-    this->screenSize = size;
-    this->layoutDirection = layoutDir;
-    this->version = vers;
-
-    // what is this anyway?
-    this->vendor = "";
-
+    *resType = type;
     return true;
 }
 
 String8
-AaptGroupEntry::toString() const
-{
-    String8 s = this->mcc;
-    s += ",";
-    s += this->mnc;
-    s += ",";
-    s += locale.toDirName();
-    s += ",";
-    s += layoutDirection;
-    s += ",";
-    s += smallestScreenWidthDp;
-    s += ",";
-    s += screenWidthDp;
-    s += ",";
-    s += screenHeightDp;
-    s += ",";
-    s += screenLayoutSize;
-    s += ",";
-    s += screenLayoutLong;
-    s += ",";
-    s += this->orientation;
-    s += ",";
-    s += uiModeType;
-    s += ",";
-    s += uiModeNight;
-    s += ",";
-    s += density;
-    s += ",";
-    s += touchscreen;
-    s += ",";
-    s += keysHidden;
-    s += ",";
-    s += keyboard;
-    s += ",";
-    s += navHidden;
-    s += ",";
-    s += navigation;
-    s += ",";
-    s += screenSize;
-    s += ",";
-    s += version;
-    return s;
-}
-
-String8
 AaptGroupEntry::toDirName(const String8& resType) const
 {
     String8 s = resType;
-    if (this->mcc != "") {
+    String8 params = mParams.toString();
+    if (params.length() > 0) {
         if (s.length() > 0) {
             s += "-";
         }
-        s += mcc;
+        s += params;
     }
-    if (this->mnc != "") {
-        if (s.length() > 0) {
-            s += "-";
-        }
-        s += mnc;
-    }
-
-    const String8 localeComponent = locale.toDirName();
-    if (localeComponent != "") {
-         if (s.length() > 0) {
-             s += "-";
-         }
-         s += localeComponent;
-    }
-
-    if (this->layoutDirection != "") {
-        if (s.length() > 0) {
-            s += "-";
-        }
-        s += layoutDirection;
-    }
-    if (this->smallestScreenWidthDp != "") {
-        if (s.length() > 0) {
-            s += "-";
-        }
-        s += smallestScreenWidthDp;
-    }
-    if (this->screenWidthDp != "") {
-        if (s.length() > 0) {
-            s += "-";
-        }
-        s += screenWidthDp;
-    }
-    if (this->screenHeightDp != "") {
-        if (s.length() > 0) {
-            s += "-";
-        }
-        s += screenHeightDp;
-    }
-    if (this->screenLayoutSize != "") {
-        if (s.length() > 0) {
-            s += "-";
-        }
-        s += screenLayoutSize;
-    }
-    if (this->screenLayoutLong != "") {
-        if (s.length() > 0) {
-            s += "-";
-        }
-        s += screenLayoutLong;
-    }
-    if (this->orientation != "") {
-        if (s.length() > 0) {
-            s += "-";
-        }
-        s += orientation;
-    }
-    if (this->uiModeType != "") {
-        if (s.length() > 0) {
-            s += "-";
-        }
-        s += uiModeType;
-    }
-    if (this->uiModeNight != "") {
-        if (s.length() > 0) {
-            s += "-";
-        }
-        s += uiModeNight;
-    }
-    if (this->density != "") {
-        if (s.length() > 0) {
-            s += "-";
-        }
-        s += density;
-    }
-    if (this->touchscreen != "") {
-        if (s.length() > 0) {
-            s += "-";
-        }
-        s += touchscreen;
-    }
-    if (this->keysHidden != "") {
-        if (s.length() > 0) {
-            s += "-";
-        }
-        s += keysHidden;
-    }
-    if (this->keyboard != "") {
-        if (s.length() > 0) {
-            s += "-";
-        }
-        s += keyboard;
-    }
-    if (this->navHidden != "") {
-        if (s.length() > 0) {
-            s += "-";
-        }
-        s += navHidden;
-    }
-    if (this->navigation != "") {
-        if (s.length() > 0) {
-            s += "-";
-        }
-        s += navigation;
-    }
-    if (this->screenSize != "") {
-        if (s.length() > 0) {
-            s += "-";
-        }
-        s += screenSize;
-    }
-    if (this->version != "") {
-        if (s.length() > 0) {
-            s += "-";
-        }
-        s += version;
-    }
-
     return s;
 }
 
-bool AaptGroupEntry::getMccName(const char* name,
-                                    ResTable_config* out)
-{
-    if (strcmp(name, kWildcardName) == 0) {
-        if (out) out->mcc = 0;
-        return true;
-    }
-    const char* c = name;
-    if (tolower(*c) != 'm') return false;
-    c++;
-    if (tolower(*c) != 'c') return false;
-    c++;
-    if (tolower(*c) != 'c') return false;
-    c++;
-
-    const char* val = c;
-
-    while (*c >= '0' && *c <= '9') {
-        c++;
-    }
-    if (*c != 0) return false;
-    if (c-val != 3) return false;
-
-    int d = atoi(val);
-    if (d != 0) {
-        if (out) out->mcc = d;
-        return true;
-    }
-
-    return false;
-}
-
-bool AaptGroupEntry::getMncName(const char* name,
-                                    ResTable_config* out)
-{
-    if (strcmp(name, kWildcardName) == 0) {
-        if (out) out->mcc = 0;
-        return true;
-    }
-    const char* c = name;
-    if (tolower(*c) != 'm') return false;
-    c++;
-    if (tolower(*c) != 'n') return false;
-    c++;
-    if (tolower(*c) != 'c') return false;
-    c++;
-
-    const char* val = c;
-
-    while (*c >= '0' && *c <= '9') {
-        c++;
-    }
-    if (*c != 0) return false;
-    if (c-val == 0 || c-val > 3) return false;
-
-    if (out) {
-        out->mnc = atoi(val);
-        if (out->mnc == 0) {
-            out->mnc = ACONFIGURATION_MNC_ZERO;
-        }
-    }
-
-    return true;
-}
-
-bool AaptGroupEntry::getLayoutDirectionName(const char* name, ResTable_config* out)
-{
-    if (strcmp(name, kWildcardName) == 0) {
-        if (out) out->screenLayout =
-                (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
-                | ResTable_config::LAYOUTDIR_ANY;
-        return true;
-    } else if (strcmp(name, "ldltr") == 0) {
-        if (out) out->screenLayout =
-                (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
-                | ResTable_config::LAYOUTDIR_LTR;
-        return true;
-    } else if (strcmp(name, "ldrtl") == 0) {
-        if (out) out->screenLayout =
-                (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
-                | ResTable_config::LAYOUTDIR_RTL;
-        return true;
-    }
-
-    return false;
-}
-
-bool AaptGroupEntry::getScreenLayoutSizeName(const char* name,
-                                     ResTable_config* out)
-{
-    if (strcmp(name, kWildcardName) == 0) {
-        if (out) out->screenLayout =
-                (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
-                | ResTable_config::SCREENSIZE_ANY;
-        return true;
-    } else if (strcmp(name, "small") == 0) {
-        if (out) out->screenLayout =
-                (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
-                | ResTable_config::SCREENSIZE_SMALL;
-        return true;
-    } else if (strcmp(name, "normal") == 0) {
-        if (out) out->screenLayout =
-                (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
-                | ResTable_config::SCREENSIZE_NORMAL;
-        return true;
-    } else if (strcmp(name, "large") == 0) {
-        if (out) out->screenLayout =
-                (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
-                | ResTable_config::SCREENSIZE_LARGE;
-        return true;
-    } else if (strcmp(name, "xlarge") == 0) {
-        if (out) out->screenLayout =
-                (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
-                | ResTable_config::SCREENSIZE_XLARGE;
-        return true;
-    }
-
-    return false;
-}
-
-bool AaptGroupEntry::getScreenLayoutLongName(const char* name,
-                                     ResTable_config* out)
-{
-    if (strcmp(name, kWildcardName) == 0) {
-        if (out) out->screenLayout =
-                (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
-                | ResTable_config::SCREENLONG_ANY;
-        return true;
-    } else if (strcmp(name, "long") == 0) {
-        if (out) out->screenLayout =
-                (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
-                | ResTable_config::SCREENLONG_YES;
-        return true;
-    } else if (strcmp(name, "notlong") == 0) {
-        if (out) out->screenLayout =
-                (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
-                | ResTable_config::SCREENLONG_NO;
-        return true;
-    }
-
-    return false;
-}
-
-bool AaptGroupEntry::getOrientationName(const char* name,
-                                        ResTable_config* out)
-{
-    if (strcmp(name, kWildcardName) == 0) {
-        if (out) out->orientation = out->ORIENTATION_ANY;
-        return true;
-    } else if (strcmp(name, "port") == 0) {
-        if (out) out->orientation = out->ORIENTATION_PORT;
-        return true;
-    } else if (strcmp(name, "land") == 0) {
-        if (out) out->orientation = out->ORIENTATION_LAND;
-        return true;
-    } else if (strcmp(name, "square") == 0) {
-        if (out) out->orientation = out->ORIENTATION_SQUARE;
-        return true;
-    }
-
-    return false;
-}
-
-bool AaptGroupEntry::getUiModeTypeName(const char* name,
-                                       ResTable_config* out)
-{
-    if (strcmp(name, kWildcardName) == 0) {
-        if (out) out->uiMode =
-                (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
-                | ResTable_config::UI_MODE_TYPE_ANY;
-        return true;
-    } else if (strcmp(name, "desk") == 0) {
-      if (out) out->uiMode =
-              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
-              | ResTable_config::UI_MODE_TYPE_DESK;
-        return true;
-    } else if (strcmp(name, "car") == 0) {
-      if (out) out->uiMode =
-              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
-              | ResTable_config::UI_MODE_TYPE_CAR;
-        return true;
-    } else if (strcmp(name, "television") == 0) {
-      if (out) out->uiMode =
-              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
-              | ResTable_config::UI_MODE_TYPE_TELEVISION;
-        return true;
-    } else if (strcmp(name, "appliance") == 0) {
-      if (out) out->uiMode =
-              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
-              | ResTable_config::UI_MODE_TYPE_APPLIANCE;
-        return true;
-    } else if (strcmp(name, "watch") == 0) {
-      if (out) out->uiMode =
-              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
-              | ResTable_config::UI_MODE_TYPE_WATCH;
-        return true;
-    }
-
-    return false;
-}
-
-bool AaptGroupEntry::getUiModeNightName(const char* name,
-                                          ResTable_config* out)
-{
-    if (strcmp(name, kWildcardName) == 0) {
-        if (out) out->uiMode =
-                (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
-                | ResTable_config::UI_MODE_NIGHT_ANY;
-        return true;
-    } else if (strcmp(name, "night") == 0) {
-        if (out) out->uiMode =
-                (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
-                | ResTable_config::UI_MODE_NIGHT_YES;
-        return true;
-    } else if (strcmp(name, "notnight") == 0) {
-      if (out) out->uiMode =
-              (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
-              | ResTable_config::UI_MODE_NIGHT_NO;
-        return true;
-    }
-
-    return false;
-}
-
-bool AaptGroupEntry::getDensityName(const char* name,
-                                    ResTable_config* out)
-{
-    if (strcmp(name, kWildcardName) == 0) {
-        if (out) out->density = ResTable_config::DENSITY_DEFAULT;
-        return true;
-    }
-    
-    if (strcmp(name, "nodpi") == 0) {
-        if (out) out->density = ResTable_config::DENSITY_NONE;
-        return true;
-    }
-    
-    if (strcmp(name, "ldpi") == 0) {
-        if (out) out->density = ResTable_config::DENSITY_LOW;
-        return true;
-    }
-    
-    if (strcmp(name, "mdpi") == 0) {
-        if (out) out->density = ResTable_config::DENSITY_MEDIUM;
-        return true;
-    }
-    
-    if (strcmp(name, "tvdpi") == 0) {
-        if (out) out->density = ResTable_config::DENSITY_TV;
-        return true;
-    }
-    
-    if (strcmp(name, "hdpi") == 0) {
-        if (out) out->density = ResTable_config::DENSITY_HIGH;
-        return true;
-    }
-
-    if (strcmp(name, "xhdpi") == 0) {
-        if (out) out->density = ResTable_config::DENSITY_XHIGH;
-        return true;
-    }
-
-    if (strcmp(name, "xxhdpi") == 0) {
-        if (out) out->density = ResTable_config::DENSITY_XXHIGH;
-        return true;
-    }
-
-    if (strcmp(name, "xxxhdpi") == 0) {
-        if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
-        return true;
-    }
-
-    char* c = (char*)name;
-    while (*c >= '0' && *c <= '9') {
-        c++;
-    }
-
-    // check that we have 'dpi' after the last digit.
-    if (toupper(c[0]) != 'D' ||
-            toupper(c[1]) != 'P' ||
-            toupper(c[2]) != 'I' ||
-            c[3] != 0) {
-        return false;
-    }
-
-    // temporarily replace the first letter with \0 to
-    // use atoi.
-    char tmp = c[0];
-    c[0] = '\0';
-
-    int d = atoi(name);
-    c[0] = tmp;
-
-    if (d != 0) {
-        if (out) out->density = d;
-        return true;
-    }
-
-    return false;
-}
-
-bool AaptGroupEntry::getTouchscreenName(const char* name,
-                                        ResTable_config* out)
-{
-    if (strcmp(name, kWildcardName) == 0) {
-        if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
-        return true;
-    } else if (strcmp(name, "notouch") == 0) {
-        if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
-        return true;
-    } else if (strcmp(name, "stylus") == 0) {
-        if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
-        return true;
-    } else if (strcmp(name, "finger") == 0) {
-        if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
-        return true;
-    }
-
-    return false;
-}
-
-bool AaptGroupEntry::getKeysHiddenName(const char* name,
-                                       ResTable_config* out)
-{
-    uint8_t mask = 0;
-    uint8_t value = 0;
-    if (strcmp(name, kWildcardName) == 0) {
-        mask = ResTable_config::MASK_KEYSHIDDEN;
-        value = ResTable_config::KEYSHIDDEN_ANY;
-    } else if (strcmp(name, "keysexposed") == 0) {
-        mask = ResTable_config::MASK_KEYSHIDDEN;
-        value = ResTable_config::KEYSHIDDEN_NO;
-    } else if (strcmp(name, "keyshidden") == 0) {
-        mask = ResTable_config::MASK_KEYSHIDDEN;
-        value = ResTable_config::KEYSHIDDEN_YES;
-    } else if (strcmp(name, "keyssoft") == 0) {
-        mask = ResTable_config::MASK_KEYSHIDDEN;
-        value = ResTable_config::KEYSHIDDEN_SOFT;
-    }
-
-    if (mask != 0) {
-        if (out) out->inputFlags = (out->inputFlags&~mask) | value;
-        return true;
-    }
-
-    return false;
-}
-
-bool AaptGroupEntry::getKeyboardName(const char* name,
-                                        ResTable_config* out)
-{
-    if (strcmp(name, kWildcardName) == 0) {
-        if (out) out->keyboard = out->KEYBOARD_ANY;
-        return true;
-    } else if (strcmp(name, "nokeys") == 0) {
-        if (out) out->keyboard = out->KEYBOARD_NOKEYS;
-        return true;
-    } else if (strcmp(name, "qwerty") == 0) {
-        if (out) out->keyboard = out->KEYBOARD_QWERTY;
-        return true;
-    } else if (strcmp(name, "12key") == 0) {
-        if (out) out->keyboard = out->KEYBOARD_12KEY;
-        return true;
-    }
-
-    return false;
-}
-
-bool AaptGroupEntry::getNavHiddenName(const char* name,
-                                       ResTable_config* out)
-{
-    uint8_t mask = 0;
-    uint8_t value = 0;
-    if (strcmp(name, kWildcardName) == 0) {
-        mask = ResTable_config::MASK_NAVHIDDEN;
-        value = ResTable_config::NAVHIDDEN_ANY;
-    } else if (strcmp(name, "navexposed") == 0) {
-        mask = ResTable_config::MASK_NAVHIDDEN;
-        value = ResTable_config::NAVHIDDEN_NO;
-    } else if (strcmp(name, "navhidden") == 0) {
-        mask = ResTable_config::MASK_NAVHIDDEN;
-        value = ResTable_config::NAVHIDDEN_YES;
-    }
-
-    if (mask != 0) {
-        if (out) out->inputFlags = (out->inputFlags&~mask) | value;
-        return true;
-    }
-
-    return false;
-}
-
-bool AaptGroupEntry::getNavigationName(const char* name,
-                                     ResTable_config* out)
-{
-    if (strcmp(name, kWildcardName) == 0) {
-        if (out) out->navigation = out->NAVIGATION_ANY;
-        return true;
-    } else if (strcmp(name, "nonav") == 0) {
-        if (out) out->navigation = out->NAVIGATION_NONAV;
-        return true;
-    } else if (strcmp(name, "dpad") == 0) {
-        if (out) out->navigation = out->NAVIGATION_DPAD;
-        return true;
-    } else if (strcmp(name, "trackball") == 0) {
-        if (out) out->navigation = out->NAVIGATION_TRACKBALL;
-        return true;
-    } else if (strcmp(name, "wheel") == 0) {
-        if (out) out->navigation = out->NAVIGATION_WHEEL;
-        return true;
-    }
-
-    return false;
-}
-
-bool AaptGroupEntry::getScreenSizeName(const char* name, ResTable_config* out)
-{
-    if (strcmp(name, kWildcardName) == 0) {
-        if (out) {
-            out->screenWidth = out->SCREENWIDTH_ANY;
-            out->screenHeight = out->SCREENHEIGHT_ANY;
-        }
-        return true;
-    }
-
-    const char* x = name;
-    while (*x >= '0' && *x <= '9') x++;
-    if (x == name || *x != 'x') return false;
-    String8 xName(name, x-name);
-    x++;
-
-    const char* y = x;
-    while (*y >= '0' && *y <= '9') y++;
-    if (y == name || *y != 0) return false;
-    String8 yName(x, y-x);
-
-    uint16_t w = (uint16_t)atoi(xName.string());
-    uint16_t h = (uint16_t)atoi(yName.string());
-    if (w < h) {
-        return false;
-    }
-
-    if (out) {
-        out->screenWidth = w;
-        out->screenHeight = h;
-    }
-
-    return true;
-}
-
-bool AaptGroupEntry::getSmallestScreenWidthDpName(const char* name, ResTable_config* out)
-{
-    if (strcmp(name, kWildcardName) == 0) {
-        if (out) {
-            out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
-        }
-        return true;
-    }
-
-    if (*name != 's') return false;
-    name++;
-    if (*name != 'w') return false;
-    name++;
-    const char* x = name;
-    while (*x >= '0' && *x <= '9') x++;
-    if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
-    String8 xName(name, x-name);
-
-    if (out) {
-        out->smallestScreenWidthDp = (uint16_t)atoi(xName.string());
-    }
-
-    return true;
-}
-
-bool AaptGroupEntry::getScreenWidthDpName(const char* name, ResTable_config* out)
-{
-    if (strcmp(name, kWildcardName) == 0) {
-        if (out) {
-            out->screenWidthDp = out->SCREENWIDTH_ANY;
-        }
-        return true;
-    }
-
-    if (*name != 'w') return false;
-    name++;
-    const char* x = name;
-    while (*x >= '0' && *x <= '9') x++;
-    if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
-    String8 xName(name, x-name);
-
-    if (out) {
-        out->screenWidthDp = (uint16_t)atoi(xName.string());
-    }
-
-    return true;
-}
-
-bool AaptGroupEntry::getScreenHeightDpName(const char* name, ResTable_config* out)
-{
-    if (strcmp(name, kWildcardName) == 0) {
-        if (out) {
-            out->screenHeightDp = out->SCREENWIDTH_ANY;
-        }
-        return true;
-    }
-
-    if (*name != 'h') return false;
-    name++;
-    const char* x = name;
-    while (*x >= '0' && *x <= '9') x++;
-    if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
-    String8 xName(name, x-name);
-
-    if (out) {
-        out->screenHeightDp = (uint16_t)atoi(xName.string());
-    }
-
-    return true;
-}
-
-bool AaptGroupEntry::getVersionName(const char* name, ResTable_config* out)
-{
-    if (strcmp(name, kWildcardName) == 0) {
-        if (out) {
-            out->sdkVersion = out->SDKVERSION_ANY;
-            out->minorVersion = out->MINORVERSION_ANY;
-        }
-        return true;
-    }
-
-    if (*name != 'v') {
-        return false;
-    }
-
-    name++;
-    const char* s = name;
-    while (*s >= '0' && *s <= '9') s++;
-    if (s == name || *s != 0) return false;
-    String8 sdkName(name, s-name);
-
-    if (out) {
-        out->sdkVersion = (uint16_t)atoi(sdkName.string());
-        out->minorVersion = 0;
-    }
-
-    return true;
-}
-
-int AaptGroupEntry::compare(const AaptGroupEntry& o) const
-{
-    int v = mcc.compare(o.mcc);
-    if (v == 0) v = mnc.compare(o.mnc);
-    if (v == 0) v = locale.compare(o.locale);
-    if (v == 0) v = layoutDirection.compare(o.layoutDirection);
-    if (v == 0) v = vendor.compare(o.vendor);
-    if (v == 0) v = smallestScreenWidthDp.compare(o.smallestScreenWidthDp);
-    if (v == 0) v = screenWidthDp.compare(o.screenWidthDp);
-    if (v == 0) v = screenHeightDp.compare(o.screenHeightDp);
-    if (v == 0) v = screenLayoutSize.compare(o.screenLayoutSize);
-    if (v == 0) v = screenLayoutLong.compare(o.screenLayoutLong);
-    if (v == 0) v = orientation.compare(o.orientation);
-    if (v == 0) v = uiModeType.compare(o.uiModeType);
-    if (v == 0) v = uiModeNight.compare(o.uiModeNight);
-    if (v == 0) v = density.compare(o.density);
-    if (v == 0) v = touchscreen.compare(o.touchscreen);
-    if (v == 0) v = keysHidden.compare(o.keysHidden);
-    if (v == 0) v = keyboard.compare(o.keyboard);
-    if (v == 0) v = navHidden.compare(o.navHidden);
-    if (v == 0) v = navigation.compare(o.navigation);
-    if (v == 0) v = screenSize.compare(o.screenSize);
-    if (v == 0) v = version.compare(o.version);
-    return v;
-}
-
-const ResTable_config AaptGroupEntry::toParams() const
-{
-    if (!mParamsChanged) {
-        return mParams;
-    }
-
-    mParamsChanged = false;
-    ResTable_config& params = mParams;
-    memset(&params, 0, sizeof(ResTable_config));
-    getMccName(mcc.string(), &params);
-    getMncName(mnc.string(), &params);
-    locale.writeTo(&params);
-    getLayoutDirectionName(layoutDirection.string(), &params);
-    getSmallestScreenWidthDpName(smallestScreenWidthDp.string(), &params);
-    getScreenWidthDpName(screenWidthDp.string(), &params);
-    getScreenHeightDpName(screenHeightDp.string(), &params);
-    getScreenLayoutSizeName(screenLayoutSize.string(), &params);
-    getScreenLayoutLongName(screenLayoutLong.string(), &params);
-    getOrientationName(orientation.string(), &params);
-    getUiModeTypeName(uiModeType.string(), &params);
-    getUiModeNightName(uiModeNight.string(), &params);
-    getDensityName(density.string(), &params);
-    getTouchscreenName(touchscreen.string(), &params);
-    getKeysHiddenName(keysHidden.string(), &params);
-    getKeyboardName(keyboard.string(), &params);
-    getNavHiddenName(navHidden.string(), &params);
-    getNavigationName(navigation.string(), &params);
-    getScreenSizeName(screenSize.string(), &params);
-    getVersionName(version.string(), &params);
-    
-    // Fix up version number based on specified parameters.
-    int minSdk = 0;
-    if (params.smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
-            || params.screenWidthDp != ResTable_config::SCREENWIDTH_ANY
-            || params.screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
-        minSdk = SDK_HONEYCOMB_MR2;
-    } else if ((params.uiMode&ResTable_config::MASK_UI_MODE_TYPE)
-                != ResTable_config::UI_MODE_TYPE_ANY
-            ||  (params.uiMode&ResTable_config::MASK_UI_MODE_NIGHT)
-                != ResTable_config::UI_MODE_NIGHT_ANY) {
-        minSdk = SDK_FROYO;
-    } else if ((params.screenLayout&ResTable_config::MASK_SCREENSIZE)
-                != ResTable_config::SCREENSIZE_ANY
-            ||  (params.screenLayout&ResTable_config::MASK_SCREENLONG)
-                != ResTable_config::SCREENLONG_ANY
-            || params.density != ResTable_config::DENSITY_DEFAULT) {
-        minSdk = SDK_DONUT;
-    }
-    
-    if (minSdk > params.sdkVersion) {
-        params.sdkVersion = minSdk;
-    }
-    
-    return params;
-}
 
 // =========================================================================
 // =========================================================================
@@ -2229,9 +907,7 @@
     : AaptDir(String8(), String8()),
       mHavePrivateSymbols(false),
       mChanged(false), mHaveIncludedAssets(false),
-      mRes(NULL)
-{
-}
+      mRes(NULL) {}
 
 const SortedVector<AaptGroupEntry>& AaptAssets::getGroupEntries() const {
     if (mChanged) {
@@ -2506,7 +1182,7 @@
         String8 resType;
         bool b = group.initFromDirName(entry->d_name, &resType);
         if (!b) {
-            fprintf(stderr, "invalid resource directory name: %s/%s\n", srcDir.string(),
+            fprintf(stderr, "invalid resource directory name: %s %s\n", srcDir.string(),
                     entry->d_name);
             err = -1;
             continue;
@@ -2654,30 +1330,35 @@
 
 status_t AaptAssets::filter(Bundle* bundle)
 {
-    ResourceFilter reqFilter;
+    WeakResourceFilter reqFilter;
     status_t err = reqFilter.parse(bundle->getConfigurations());
     if (err != NO_ERROR) {
         return err;
     }
 
-    ResourceFilter prefFilter;
-    err = prefFilter.parse(bundle->getPreferredConfigurations());
-    if (err != NO_ERROR) {
-        return err;
+    uint32_t preferredDensity = 0;
+    if (bundle->getPreferredDensity().size() > 0) {
+        ResTable_config preferredConfig;
+        if (!AaptConfig::parseDensity(bundle->getPreferredDensity().string(), &preferredConfig)) {
+            fprintf(stderr, "Error parsing preferred density: %s\n",
+                    bundle->getPreferredDensity().string());
+            return UNKNOWN_ERROR;
+        }
+        preferredDensity = preferredConfig.density;
     }
 
-    if (reqFilter.isEmpty() && prefFilter.isEmpty()) {
+    if (reqFilter.isEmpty() && preferredDensity == 0) {
         return NO_ERROR;
     }
 
     if (bundle->getVerbose()) {
         if (!reqFilter.isEmpty()) {
             printf("Applying required filter: %s\n",
-                    bundle->getConfigurations());
+                    bundle->getConfigurations().string());
         }
-        if (!prefFilter.isEmpty()) {
-            printf("Applying preferred filter: %s\n",
-                    bundle->getPreferredConfigurations());
+        if (preferredDensity > 0) {
+            printf("Applying preferred density filter: %s\n",
+                    bundle->getPreferredDensity().string());
         }
     }
 
@@ -2734,89 +1415,71 @@
             }
 
             // Quick check: no preferred filters, nothing more to do.
-            if (prefFilter.isEmpty()) {
+            if (preferredDensity == 0) {
                 continue;
             }
 
             // Get the preferred density if there is one. We do not match exactly for density.
             // If our preferred density is hdpi but we only have mdpi and xhdpi resources, we
             // pick xhdpi.
-            uint32_t preferredDensity = 0;
-            const SortedVector<AxisValue>* preferredConfigs = prefFilter.configsForAxis(AXIS_DENSITY);
-            if (preferredConfigs != NULL && preferredConfigs->size() > 0) {
-                preferredDensity = (*preferredConfigs)[0].intValue;
-            }
+            for (size_t k=0; k<grp->getFiles().size(); k++) {
+                sp<AaptFile> file = grp->getFiles().valueAt(k);
+                if (k == 0 && grp->getFiles().size() == 1) {
+                    // If this is the only file left, we need to keep it.
+                    // Otherwise the resource IDs we are using will be inconsistent
+                    // with what we get when not stripping.  Sucky, but at least
+                    // for now we can rely on the back-end doing another filtering
+                    // pass to take this out and leave us with this resource name
+                    // containing no entries.
+                    continue;
+                }
+                if (file->getPath().getPathExtension() == ".xml") {
+                    // We can't remove .xml files at this point, because when
+                    // we parse them they may add identifier resources, so
+                    // removing them can cause our resource identifiers to
+                    // become inconsistent.
+                    continue;
+                }
+                const ResTable_config& config(file->getGroupEntry().toParams());
+                if (config.density != 0 && config.density != preferredDensity) {
+                    // This is a resource we would prefer not to have.  Check
+                    // to see if have a similar variation that we would like
+                    // to have and, if so, we can drop it.
+                    uint32_t bestDensity = config.density;
 
-            // Now deal with preferred configurations.
-            for (int axis=AXIS_START; axis<=AXIS_END; axis++) {
-                for (size_t k=0; k<grp->getFiles().size(); k++) {
-                    sp<AaptFile> file = grp->getFiles().valueAt(k);
-                    if (k == 0 && grp->getFiles().size() == 1) {
-                        // If this is the only file left, we need to keep it.
-                        // Otherwise the resource IDs we are using will be inconsistent
-                        // with what we get when not stripping.  Sucky, but at least
-                        // for now we can rely on the back-end doing another filtering
-                        // pass to take this out and leave us with this resource name
-                        // containing no entries.
-                        continue;
-                    }
-                    if (file->getPath().getPathExtension() == ".xml") {
-                        // We can't remove .xml files at this point, because when
-                        // we parse them they may add identifier resources, so
-                        // removing them can cause our resource identifiers to
-                        // become inconsistent.
-                        continue;
-                    }
-                    const ResTable_config& config(file->getGroupEntry().toParams());
-                    if (!prefFilter.match(axis, config)) {
-                        // This is a resource we would prefer not to have.  Check
-                        // to see if have a similar variation that we would like
-                        // to have and, if so, we can drop it.
-
-                        uint32_t bestDensity = config.density;
-
-                        for (size_t m=0; m<grp->getFiles().size(); m++) {
-                            if (m == k) continue;
-                            sp<AaptFile> mfile = grp->getFiles().valueAt(m);
-                            const ResTable_config& mconfig(mfile->getGroupEntry().toParams());
-                            if (AaptGroupEntry::configSameExcept(config, mconfig, axis)) {
-                                if (axis == AXIS_DENSITY && preferredDensity > 0) {
-                                    // See if there is a better density resource
-                                    if (mconfig.density < bestDensity &&
-                                            mconfig.density > preferredDensity &&
-                                            bestDensity > preferredDensity) {
-                                        // This density is between our best density and
-                                        // the preferred density, therefore it is better.
-                                        bestDensity = mconfig.density;
-                                    } else if (mconfig.density > bestDensity &&
-                                            bestDensity < preferredDensity) {
-                                        // This density is better than our best density and
-                                        // our best density was smaller than our preferred
-                                        // density, so it is better.
-                                        bestDensity = mconfig.density;
-                                    }
-                                } else if (prefFilter.match(axis, mconfig)) {
-                                    if (bundle->getVerbose()) {
-                                        printf("Pruning unneeded resource: %s\n",
-                                                file->getPrintableSource().string());
-                                    }
-                                    grp->removeFile(k);
-                                    k--;
-                                    break;
-                                }
-                            }
+                    for (size_t m=0; m<grp->getFiles().size(); m++) {
+                        if (m == k) {
+                            continue;
                         }
 
-                        if (axis == AXIS_DENSITY && preferredDensity > 0 &&
-                                bestDensity != config.density) {
-                            if (bundle->getVerbose()) {
-                                printf("Pruning unneeded resource: %s\n",
-                                        file->getPrintableSource().string());
+                        sp<AaptFile> mfile = grp->getFiles().valueAt(m);
+                        const ResTable_config& mconfig(mfile->getGroupEntry().toParams());
+                        if (AaptConfig::isSameExcept(config, mconfig, ResTable_config::CONFIG_DENSITY)) {
+                            // See if there is a better density resource
+                            if (mconfig.density < bestDensity &&
+                                    mconfig.density > preferredDensity &&
+                                    bestDensity > preferredDensity) {
+                                // This density is between our best density and
+                                // the preferred density, therefore it is better.
+                                bestDensity = mconfig.density;
+                            } else if (mconfig.density > bestDensity &&
+                                    bestDensity < preferredDensity) {
+                                // This density is better than our best density and
+                                // our best density was smaller than our preferred
+                                // density, so it is better.
+                                bestDensity = mconfig.density;
                             }
-                            grp->removeFile(k);
-                            k--;
                         }
                     }
+
+                    if (bestDensity != config.density) {
+                        if (bundle->getVerbose()) {
+                            printf("Pruning unneeded resource: %s\n",
+                                    file->getPrintableSource().string());
+                        }
+                        grp->removeFile(k);
+                        k--;
+                    }
                 }
             }
         }
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 82dda5f..0c2576a 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -6,22 +6,24 @@
 #ifndef __AAPT_ASSETS_H
 #define __AAPT_ASSETS_H
 
-#include <stdlib.h>
 #include <androidfw/AssetManager.h>
 #include <androidfw/ResourceTypes.h>
+#include <stdlib.h>
+#include <set>
 #include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
 #include <utils/SortedVector.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
+
+#include "AaptConfig.h"
+#include "Bundle.h"
+#include "ConfigDescription.h"
+#include "SourcePos.h"
 #include "ZipFile.h"
 
-#include "Bundle.h"
-#include "SourcePos.h"
-
 using namespace android;
 
-
 extern const char * const gDefaultIgnoreAssets;
 extern const char * gUserIgnoreAssets;
 
@@ -82,9 +84,6 @@
          return memcmp(this, &other, sizeof(AaptLocaleValue));
      }
 
-     static void splitAndLowerCase(const char* const chars, Vector<String8>* parts,
-             const char separator);
-
      inline bool operator<(const AaptLocaleValue& o) const { return compare(o) < 0; }
      inline bool operator<=(const AaptLocaleValue& o) const { return compare(o) <= 0; }
      inline bool operator==(const AaptLocaleValue& o) const { return compare(o) == 0; }
@@ -98,31 +97,6 @@
      void setVariant(const char* variant);
 };
 
-struct AxisValue {
-    // Used for all axes except AXIS_LOCALE, which is represented
-    // as a AaptLocaleValue value.
-    int intValue;
-    AaptLocaleValue localeValue;
-
-    AxisValue() : intValue(0) {
-    }
-
-    inline int compare(const AxisValue &other) const  {
-        if (intValue != other.intValue) {
-            return intValue - other.intValue;
-        }
-
-        return localeValue.compare(other.localeValue);
-    }
-
-    inline bool operator<(const AxisValue& o) const { return compare(o) < 0; }
-    inline bool operator<=(const AxisValue& o) const { return compare(o) <= 0; }
-    inline bool operator==(const AxisValue& o) const { return compare(o) == 0; }
-    inline bool operator!=(const AxisValue& o) const { return compare(o) != 0; }
-    inline bool operator>=(const AxisValue& o) const { return compare(o) >= 0; }
-    inline bool operator>(const AxisValue& o) const { return compare(o) > 0; }
-};
-
 /**
  * This structure contains a specific variation of a single file out
  * of all the variations it can have that we can have.
@@ -130,23 +104,11 @@
 struct AaptGroupEntry
 {
 public:
-    AaptGroupEntry() : mParamsChanged(true) {
-        memset(&mParams, 0, sizeof(ResTable_config));
-    }
-
     bool initFromDirName(const char* dir, String8* resType);
 
-    static bool parseFilterNamePart(const String8& part, int* axis, AxisValue* value);
+    inline const ConfigDescription& toParams() const { return mParams; }
 
-    static AxisValue getConfigValueForAxis(const ResTable_config& config, int axis);
-
-    static bool configSameExcept(const ResTable_config& config,
-            const ResTable_config& otherConfig, int axis);
-
-    int compare(const AaptGroupEntry& o) const;
-
-    const ResTable_config toParams() const;
-
+    inline int compare(const AaptGroupEntry& o) const { return mParams.compareLogical(o.mParams); }
     inline bool operator<(const AaptGroupEntry& o) const { return compare(o) < 0; }
     inline bool operator<=(const AaptGroupEntry& o) const { return compare(o) <= 0; }
     inline bool operator==(const AaptGroupEntry& o) const { return compare(o) == 0; }
@@ -154,56 +116,13 @@
     inline bool operator>=(const AaptGroupEntry& o) const { return compare(o) >= 0; }
     inline bool operator>(const AaptGroupEntry& o) const { return compare(o) > 0; }
 
-    String8 toString() const;
+    String8 toString() const { return mParams.toString(); }
     String8 toDirName(const String8& resType) const;
 
-    const String8& getVersionString() const { return version; }
+    const String8 getVersionString() const { return AaptConfig::getVersion(mParams); }
 
 private:
-    static bool getMccName(const char* name, ResTable_config* out = NULL);
-    static bool getMncName(const char* name, ResTable_config* out = NULL);
-    static bool getScreenLayoutSizeName(const char* name, ResTable_config* out = NULL);
-    static bool getScreenLayoutLongName(const char* name, ResTable_config* out = NULL);
-    static bool getOrientationName(const char* name, ResTable_config* out = NULL);
-    static bool getUiModeTypeName(const char* name, ResTable_config* out = NULL);
-    static bool getUiModeNightName(const char* name, ResTable_config* out = NULL);
-    static bool getDensityName(const char* name, ResTable_config* out = NULL);
-    static bool getTouchscreenName(const char* name, ResTable_config* out = NULL);
-    static bool getKeysHiddenName(const char* name, ResTable_config* out = NULL);
-    static bool getKeyboardName(const char* name, ResTable_config* out = NULL);
-    static bool getNavigationName(const char* name, ResTable_config* out = NULL);
-    static bool getNavHiddenName(const char* name, ResTable_config* out = NULL);
-    static bool getScreenSizeName(const char* name, ResTable_config* out = NULL);
-    static bool getSmallestScreenWidthDpName(const char* name, ResTable_config* out = NULL);
-    static bool getScreenWidthDpName(const char* name, ResTable_config* out = NULL);
-    static bool getScreenHeightDpName(const char* name, ResTable_config* out = NULL);
-    static bool getLayoutDirectionName(const char* name, ResTable_config* out = NULL);
-    static bool getVersionName(const char* name, ResTable_config* out = NULL);
-
-    String8 mcc;
-    String8 mnc;
-    AaptLocaleValue locale;
-    String8 vendor;
-    String8 smallestScreenWidthDp;
-    String8 screenWidthDp;
-    String8 screenHeightDp;
-    String8 screenLayoutSize;
-    String8 screenLayoutLong;
-    String8 orientation;
-    String8 uiModeType;
-    String8 uiModeNight;
-    String8 density;
-    String8 touchscreen;
-    String8 keysHidden;
-    String8 keyboard;
-    String8 navHidden;
-    String8 navigation;
-    String8 screenSize;
-    String8 layoutDirection;
-    String8 version;
-
-    mutable bool mParamsChanged;
-    mutable ResTable_config mParams;
+    ConfigDescription mParams;
 };
 
 inline int compare_type(const AaptGroupEntry& lhs, const AaptGroupEntry& rhs)
diff --git a/tools/aapt/AaptConfig.cpp b/tools/aapt/AaptConfig.cpp
new file mode 100644
index 0000000..69a9c7f
--- /dev/null
+++ b/tools/aapt/AaptConfig.cpp
@@ -0,0 +1,790 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <androidfw/ResourceTypes.h>
+#include <ctype.h>
+
+#include "AaptConfig.h"
+#include "AaptAssets.h"
+#include "AaptUtil.h"
+#include "ResourceFilter.h"
+
+using android::String8;
+using android::Vector;
+using android::ResTable_config;
+
+namespace AaptConfig {
+
+static const char* kWildcardName = "any";
+
+bool parse(const String8& str, ConfigDescription* out) {
+    Vector<String8> parts = AaptUtil::splitAndLowerCase(str, '-');
+
+    ConfigDescription config;
+    AaptLocaleValue locale;
+    ssize_t index = 0;
+    ssize_t localeIndex = 0;
+    const ssize_t N = parts.size();
+    const char* part = parts[index].string();
+
+    if (str.length() == 0) {
+        goto success;
+    }
+
+    if (parseMcc(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    if (parseMnc(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    // Locale spans a few '-' separators, so we let it
+    // control the index.
+    localeIndex = locale.initFromDirName(parts, index);
+    if (localeIndex < 0) {
+        return false;
+    } else if (localeIndex > index) {
+        locale.writeTo(&config);
+        index = localeIndex;
+        if (index >= N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    if (parseLayoutDirection(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    if (parseSmallestScreenWidthDp(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    if (parseScreenWidthDp(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    if (parseScreenHeightDp(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    if (parseScreenLayoutSize(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    if (parseScreenLayoutLong(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    if (parseOrientation(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    if (parseUiModeType(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    if (parseUiModeNight(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    if (parseDensity(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    if (parseTouchscreen(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    if (parseKeysHidden(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    if (parseKeyboard(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    if (parseNavHidden(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    if (parseNavigation(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    if (parseScreenSize(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    if (parseVersion(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    // Unrecognized.
+    return false;
+
+success:
+    if (out != NULL) {
+        applyVersionForCompatibility(&config);
+        *out = config;
+    }
+    return true;
+}
+
+bool parseCommaSeparatedList(const String8& str, std::set<ConfigDescription>* outSet) {
+    Vector<String8> parts = AaptUtil::splitAndLowerCase(str, ',');
+    const size_t N = parts.size();
+    for (size_t i = 0; i < N; i++) {
+        ConfigDescription config;
+        if (!parse(parts[i], &config)) {
+            return false;
+        }
+        outSet->insert(config);
+    }
+    return true;
+}
+
+void applyVersionForCompatibility(ConfigDescription* config) {
+    if (config == NULL) {
+        return;
+    }
+
+    uint16_t minSdk = 0;
+    if (config->smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
+            || config->screenWidthDp != ResTable_config::SCREENWIDTH_ANY
+            || config->screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
+        minSdk = SDK_HONEYCOMB_MR2;
+    } else if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE)
+                != ResTable_config::UI_MODE_TYPE_ANY
+            ||  (config->uiMode & ResTable_config::MASK_UI_MODE_NIGHT)
+                != ResTable_config::UI_MODE_NIGHT_ANY) {
+        minSdk = SDK_FROYO;
+    } else if ((config->screenLayout & ResTable_config::MASK_SCREENSIZE)
+                != ResTable_config::SCREENSIZE_ANY
+            ||  (config->screenLayout & ResTable_config::MASK_SCREENLONG)
+                != ResTable_config::SCREENLONG_ANY
+            || config->density != ResTable_config::DENSITY_DEFAULT) {
+        minSdk = SDK_DONUT;
+    }
+
+    if (minSdk > config->sdkVersion) {
+        config->sdkVersion = minSdk;
+    }
+}
+
+bool parseMcc(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->mcc = 0;
+        return true;
+    }
+    const char* c = name;
+    if (tolower(*c) != 'm') return false;
+    c++;
+    if (tolower(*c) != 'c') return false;
+    c++;
+    if (tolower(*c) != 'c') return false;
+    c++;
+
+    const char* val = c;
+
+    while (*c >= '0' && *c <= '9') {
+        c++;
+    }
+    if (*c != 0) return false;
+    if (c-val != 3) return false;
+
+    int d = atoi(val);
+    if (d != 0) {
+        if (out) out->mcc = d;
+        return true;
+    }
+
+    return false;
+}
+
+bool parseMnc(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->mcc = 0;
+        return true;
+    }
+    const char* c = name;
+    if (tolower(*c) != 'm') return false;
+    c++;
+    if (tolower(*c) != 'n') return false;
+    c++;
+    if (tolower(*c) != 'c') return false;
+    c++;
+
+    const char* val = c;
+
+    while (*c >= '0' && *c <= '9') {
+        c++;
+    }
+    if (*c != 0) return false;
+    if (c-val == 0 || c-val > 3) return false;
+
+    if (out) {
+        out->mnc = atoi(val);
+        if (out->mnc == 0) {
+            out->mnc = ACONFIGURATION_MNC_ZERO;
+        }
+    }
+
+    return true;
+}
+
+bool parseLayoutDirection(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
+                | ResTable_config::LAYOUTDIR_ANY;
+        return true;
+    } else if (strcmp(name, "ldltr") == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
+                | ResTable_config::LAYOUTDIR_LTR;
+        return true;
+    } else if (strcmp(name, "ldrtl") == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
+                | ResTable_config::LAYOUTDIR_RTL;
+        return true;
+    }
+
+    return false;
+}
+
+bool parseScreenLayoutSize(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+                | ResTable_config::SCREENSIZE_ANY;
+        return true;
+    } else if (strcmp(name, "small") == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+                | ResTable_config::SCREENSIZE_SMALL;
+        return true;
+    } else if (strcmp(name, "normal") == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+                | ResTable_config::SCREENSIZE_NORMAL;
+        return true;
+    } else if (strcmp(name, "large") == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+                | ResTable_config::SCREENSIZE_LARGE;
+        return true;
+    } else if (strcmp(name, "xlarge") == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+                | ResTable_config::SCREENSIZE_XLARGE;
+        return true;
+    }
+
+    return false;
+}
+
+bool parseScreenLayoutLong(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
+                | ResTable_config::SCREENLONG_ANY;
+        return true;
+    } else if (strcmp(name, "long") == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
+                | ResTable_config::SCREENLONG_YES;
+        return true;
+    } else if (strcmp(name, "notlong") == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
+                | ResTable_config::SCREENLONG_NO;
+        return true;
+    }
+
+    return false;
+}
+
+bool parseOrientation(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->orientation = out->ORIENTATION_ANY;
+        return true;
+    } else if (strcmp(name, "port") == 0) {
+        if (out) out->orientation = out->ORIENTATION_PORT;
+        return true;
+    } else if (strcmp(name, "land") == 0) {
+        if (out) out->orientation = out->ORIENTATION_LAND;
+        return true;
+    } else if (strcmp(name, "square") == 0) {
+        if (out) out->orientation = out->ORIENTATION_SQUARE;
+        return true;
+    }
+
+    return false;
+}
+
+bool parseUiModeType(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->uiMode =
+                (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+                | ResTable_config::UI_MODE_TYPE_ANY;
+        return true;
+    } else if (strcmp(name, "desk") == 0) {
+      if (out) out->uiMode =
+              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+              | ResTable_config::UI_MODE_TYPE_DESK;
+        return true;
+    } else if (strcmp(name, "car") == 0) {
+      if (out) out->uiMode =
+              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+              | ResTable_config::UI_MODE_TYPE_CAR;
+        return true;
+    } else if (strcmp(name, "television") == 0) {
+      if (out) out->uiMode =
+              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+              | ResTable_config::UI_MODE_TYPE_TELEVISION;
+        return true;
+    } else if (strcmp(name, "appliance") == 0) {
+      if (out) out->uiMode =
+              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+              | ResTable_config::UI_MODE_TYPE_APPLIANCE;
+        return true;
+    } else if (strcmp(name, "watch") == 0) {
+      if (out) out->uiMode =
+              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+              | ResTable_config::UI_MODE_TYPE_WATCH;
+        return true;
+    }
+
+    return false;
+}
+
+bool parseUiModeNight(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->uiMode =
+                (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
+                | ResTable_config::UI_MODE_NIGHT_ANY;
+        return true;
+    } else if (strcmp(name, "night") == 0) {
+        if (out) out->uiMode =
+                (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
+                | ResTable_config::UI_MODE_NIGHT_YES;
+        return true;
+    } else if (strcmp(name, "notnight") == 0) {
+      if (out) out->uiMode =
+              (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
+              | ResTable_config::UI_MODE_NIGHT_NO;
+        return true;
+    }
+
+    return false;
+}
+
+bool parseDensity(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->density = ResTable_config::DENSITY_DEFAULT;
+        return true;
+    }
+
+    if (strcmp(name, "nodpi") == 0) {
+        if (out) out->density = ResTable_config::DENSITY_NONE;
+        return true;
+    }
+
+    if (strcmp(name, "ldpi") == 0) {
+        if (out) out->density = ResTable_config::DENSITY_LOW;
+        return true;
+    }
+
+    if (strcmp(name, "mdpi") == 0) {
+        if (out) out->density = ResTable_config::DENSITY_MEDIUM;
+        return true;
+    }
+
+    if (strcmp(name, "tvdpi") == 0) {
+        if (out) out->density = ResTable_config::DENSITY_TV;
+        return true;
+    }
+
+    if (strcmp(name, "hdpi") == 0) {
+        if (out) out->density = ResTable_config::DENSITY_HIGH;
+        return true;
+    }
+
+    if (strcmp(name, "xhdpi") == 0) {
+        if (out) out->density = ResTable_config::DENSITY_XHIGH;
+        return true;
+    }
+
+    if (strcmp(name, "xxhdpi") == 0) {
+        if (out) out->density = ResTable_config::DENSITY_XXHIGH;
+        return true;
+    }
+
+    if (strcmp(name, "xxxhdpi") == 0) {
+        if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
+        return true;
+    }
+
+    char* c = (char*)name;
+    while (*c >= '0' && *c <= '9') {
+        c++;
+    }
+
+    // check that we have 'dpi' after the last digit.
+    if (toupper(c[0]) != 'D' ||
+            toupper(c[1]) != 'P' ||
+            toupper(c[2]) != 'I' ||
+            c[3] != 0) {
+        return false;
+    }
+
+    // temporarily replace the first letter with \0 to
+    // use atoi.
+    char tmp = c[0];
+    c[0] = '\0';
+
+    int d = atoi(name);
+    c[0] = tmp;
+
+    if (d != 0) {
+        if (out) out->density = d;
+        return true;
+    }
+
+    return false;
+}
+
+bool parseTouchscreen(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
+        return true;
+    } else if (strcmp(name, "notouch") == 0) {
+        if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
+        return true;
+    } else if (strcmp(name, "stylus") == 0) {
+        if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
+        return true;
+    } else if (strcmp(name, "finger") == 0) {
+        if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
+        return true;
+    }
+
+    return false;
+}
+
+bool parseKeysHidden(const char* name, ResTable_config* out) {
+    uint8_t mask = 0;
+    uint8_t value = 0;
+    if (strcmp(name, kWildcardName) == 0) {
+        mask = ResTable_config::MASK_KEYSHIDDEN;
+        value = ResTable_config::KEYSHIDDEN_ANY;
+    } else if (strcmp(name, "keysexposed") == 0) {
+        mask = ResTable_config::MASK_KEYSHIDDEN;
+        value = ResTable_config::KEYSHIDDEN_NO;
+    } else if (strcmp(name, "keyshidden") == 0) {
+        mask = ResTable_config::MASK_KEYSHIDDEN;
+        value = ResTable_config::KEYSHIDDEN_YES;
+    } else if (strcmp(name, "keyssoft") == 0) {
+        mask = ResTable_config::MASK_KEYSHIDDEN;
+        value = ResTable_config::KEYSHIDDEN_SOFT;
+    }
+
+    if (mask != 0) {
+        if (out) out->inputFlags = (out->inputFlags&~mask) | value;
+        return true;
+    }
+
+    return false;
+}
+
+bool parseKeyboard(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->keyboard = out->KEYBOARD_ANY;
+        return true;
+    } else if (strcmp(name, "nokeys") == 0) {
+        if (out) out->keyboard = out->KEYBOARD_NOKEYS;
+        return true;
+    } else if (strcmp(name, "qwerty") == 0) {
+        if (out) out->keyboard = out->KEYBOARD_QWERTY;
+        return true;
+    } else if (strcmp(name, "12key") == 0) {
+        if (out) out->keyboard = out->KEYBOARD_12KEY;
+        return true;
+    }
+
+    return false;
+}
+
+bool parseNavHidden(const char* name, ResTable_config* out) {
+    uint8_t mask = 0;
+    uint8_t value = 0;
+    if (strcmp(name, kWildcardName) == 0) {
+        mask = ResTable_config::MASK_NAVHIDDEN;
+        value = ResTable_config::NAVHIDDEN_ANY;
+    } else if (strcmp(name, "navexposed") == 0) {
+        mask = ResTable_config::MASK_NAVHIDDEN;
+        value = ResTable_config::NAVHIDDEN_NO;
+    } else if (strcmp(name, "navhidden") == 0) {
+        mask = ResTable_config::MASK_NAVHIDDEN;
+        value = ResTable_config::NAVHIDDEN_YES;
+    }
+
+    if (mask != 0) {
+        if (out) out->inputFlags = (out->inputFlags&~mask) | value;
+        return true;
+    }
+
+    return false;
+}
+
+bool parseNavigation(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->navigation = out->NAVIGATION_ANY;
+        return true;
+    } else if (strcmp(name, "nonav") == 0) {
+        if (out) out->navigation = out->NAVIGATION_NONAV;
+        return true;
+    } else if (strcmp(name, "dpad") == 0) {
+        if (out) out->navigation = out->NAVIGATION_DPAD;
+        return true;
+    } else if (strcmp(name, "trackball") == 0) {
+        if (out) out->navigation = out->NAVIGATION_TRACKBALL;
+        return true;
+    } else if (strcmp(name, "wheel") == 0) {
+        if (out) out->navigation = out->NAVIGATION_WHEEL;
+        return true;
+    }
+
+    return false;
+}
+
+bool parseScreenSize(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) {
+            out->screenWidth = out->SCREENWIDTH_ANY;
+            out->screenHeight = out->SCREENHEIGHT_ANY;
+        }
+        return true;
+    }
+
+    const char* x = name;
+    while (*x >= '0' && *x <= '9') x++;
+    if (x == name || *x != 'x') return false;
+    String8 xName(name, x-name);
+    x++;
+
+    const char* y = x;
+    while (*y >= '0' && *y <= '9') y++;
+    if (y == name || *y != 0) return false;
+    String8 yName(x, y-x);
+
+    uint16_t w = (uint16_t)atoi(xName.string());
+    uint16_t h = (uint16_t)atoi(yName.string());
+    if (w < h) {
+        return false;
+    }
+
+    if (out) {
+        out->screenWidth = w;
+        out->screenHeight = h;
+    }
+
+    return true;
+}
+
+bool parseSmallestScreenWidthDp(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) {
+            out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
+        }
+        return true;
+    }
+
+    if (*name != 's') return false;
+    name++;
+    if (*name != 'w') return false;
+    name++;
+    const char* x = name;
+    while (*x >= '0' && *x <= '9') x++;
+    if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
+    String8 xName(name, x-name);
+
+    if (out) {
+        out->smallestScreenWidthDp = (uint16_t)atoi(xName.string());
+    }
+
+    return true;
+}
+
+bool parseScreenWidthDp(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) {
+            out->screenWidthDp = out->SCREENWIDTH_ANY;
+        }
+        return true;
+    }
+
+    if (*name != 'w') return false;
+    name++;
+    const char* x = name;
+    while (*x >= '0' && *x <= '9') x++;
+    if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
+    String8 xName(name, x-name);
+
+    if (out) {
+        out->screenWidthDp = (uint16_t)atoi(xName.string());
+    }
+
+    return true;
+}
+
+bool parseScreenHeightDp(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) {
+            out->screenHeightDp = out->SCREENWIDTH_ANY;
+        }
+        return true;
+    }
+
+    if (*name != 'h') return false;
+    name++;
+    const char* x = name;
+    while (*x >= '0' && *x <= '9') x++;
+    if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
+    String8 xName(name, x-name);
+
+    if (out) {
+        out->screenHeightDp = (uint16_t)atoi(xName.string());
+    }
+
+    return true;
+}
+
+bool parseVersion(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) {
+            out->sdkVersion = out->SDKVERSION_ANY;
+            out->minorVersion = out->MINORVERSION_ANY;
+        }
+        return true;
+    }
+
+    if (*name != 'v') {
+        return false;
+    }
+
+    name++;
+    const char* s = name;
+    while (*s >= '0' && *s <= '9') s++;
+    if (s == name || *s != 0) return false;
+    String8 sdkName(name, s-name);
+
+    if (out) {
+        out->sdkVersion = (uint16_t)atoi(sdkName.string());
+        out->minorVersion = 0;
+    }
+
+    return true;
+}
+
+String8 getVersion(const ResTable_config& config) {
+    return String8::format("v%u", config.sdkVersion);
+}
+
+bool isSameExcept(const ResTable_config& a, const ResTable_config& b, int axisMask) {
+    return a.diff(b) == axisMask;
+}
+
+} // namespace AaptConfig
diff --git a/tools/aapt/AaptConfig.h b/tools/aapt/AaptConfig.h
new file mode 100644
index 0000000..2963539
--- /dev/null
+++ b/tools/aapt/AaptConfig.h
@@ -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.
+ */
+
+#ifndef __AAPT_CONFIG_H
+#define __AAPT_CONFIG_H
+
+#include <set>
+#include <utils/String8.h>
+
+#include "ConfigDescription.h"
+
+/**
+ * Utility methods for dealing with configurations.
+ */
+namespace AaptConfig {
+
+/**
+ * Parse a string of the form 'fr-sw600dp-land' and fill in the
+ * given ResTable_config with resulting configuration parameters.
+ *
+ * The resulting configuration has the appropriate sdkVersion defined
+ * for backwards compatibility.
+ */
+bool parse(const android::String8& str, ConfigDescription* out = NULL);
+
+/**
+ * Parse a comma separated list of configuration strings. Duplicate configurations
+ * will be removed.
+ *
+ * Example input: "fr,de-land,fr-sw600dp-land"
+ */
+bool parseCommaSeparatedList(const android::String8& str, std::set<ConfigDescription>* outSet);
+
+/**
+ * If the configuration uses an axis that was added after
+ * the original Android release, make sure the SDK version
+ * is set accordingly.
+ */
+void applyVersionForCompatibility(ConfigDescription* config);
+
+// Individual axis
+bool parseMcc(const char* str, android::ResTable_config* out = NULL);
+bool parseMnc(const char* str, android::ResTable_config* out = NULL);
+bool parseLayoutDirection(const char* str, android::ResTable_config* out = NULL);
+bool parseSmallestScreenWidthDp(const char* str, android::ResTable_config* out = NULL);
+bool parseScreenWidthDp(const char* str, android::ResTable_config* out = NULL);
+bool parseScreenHeightDp(const char* str, android::ResTable_config* out = NULL);
+bool parseScreenLayoutSize(const char* str, android::ResTable_config* out = NULL);
+bool parseScreenLayoutLong(const char* str, android::ResTable_config* out = NULL);
+bool parseOrientation(const char* str, android::ResTable_config* out = NULL);
+bool parseUiModeType(const char* str, android::ResTable_config* out = NULL);
+bool parseUiModeNight(const char* str, android::ResTable_config* out = NULL);
+bool parseDensity(const char* str, android::ResTable_config* out = NULL);
+bool parseTouchscreen(const char* str, android::ResTable_config* out = NULL);
+bool parseKeysHidden(const char* str, android::ResTable_config* out = NULL);
+bool parseKeyboard(const char* str, android::ResTable_config* out = NULL);
+bool parseNavHidden(const char* str, android::ResTable_config* out = NULL);
+bool parseNavigation(const char* str, android::ResTable_config* out = NULL);
+bool parseScreenSize(const char* str, android::ResTable_config* out = NULL);
+bool parseVersion(const char* str, android::ResTable_config* out = NULL);
+
+android::String8 getVersion(const android::ResTable_config& config);
+
+/**
+ * Returns true if the two configurations only differ by the specified axis.
+ * The axis mask is a bitmask of CONFIG_* constants.
+ */
+bool isSameExcept(const android::ResTable_config& a, const android::ResTable_config& b, int configMask);
+
+} // namespace AaptConfig
+
+#endif // __AAPT_CONFIG_H
diff --git a/tools/aapt/AaptUtil.cpp b/tools/aapt/AaptUtil.cpp
new file mode 100644
index 0000000..293e144
--- /dev/null
+++ b/tools/aapt/AaptUtil.cpp
@@ -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.
+ */
+
+#include "AaptUtil.h"
+
+using android::Vector;
+using android::String8;
+
+namespace AaptUtil {
+
+Vector<String8> split(const String8& str, const char sep) {
+    Vector<String8> parts;
+    const char* p = str.string();
+    const char* q;
+
+    while (true) {
+        q = strchr(p, sep);
+        if (q == NULL) {
+            parts.add(String8(p, strlen(p)));
+            return parts;
+        }
+
+        parts.add(String8(p, q-p));
+        p = q + 1;
+    }
+    return parts;
+}
+
+Vector<String8> splitAndLowerCase(const String8& str, const char sep) {
+    Vector<String8> parts;
+    const char* p = str.string();
+    const char* q;
+
+    while (true) {
+        q = strchr(p, sep);
+        if (q == NULL) {
+            String8 val(p, strlen(p));
+            val.toLower();
+            parts.add(val);
+            return parts;
+        }
+
+        String8 val(p, q-p);
+        val.toLower();
+        parts.add(val);
+        p = q + 1;
+    }
+    return parts;
+}
+
+} // namespace AaptUtil
diff --git a/tools/aapt/AaptUtil.h b/tools/aapt/AaptUtil.h
new file mode 100644
index 0000000..47a704a
--- /dev/null
+++ b/tools/aapt/AaptUtil.h
@@ -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.
+ */
+
+#ifndef __AAPT_UTIL_H
+#define __AAPT_UTIL_H
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+namespace AaptUtil {
+
+android::Vector<android::String8> split(const android::String8& str, const char sep);
+android::Vector<android::String8> splitAndLowerCase(const android::String8& str, const char sep);
+
+} // namespace AaptUtil
+
+#endif // __AAPT_UTIL_H
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index 806f8ff..700afa1 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -1,104 +1,168 @@
-# 
-# Copyright 2006 The Android Open Source Project
 #
-# Android Asset Packaging Tool
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 tool is prebuilt if we're doing an app-only build.
 ifeq ($(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)),)
 
+# ==========================================================
+# Setup some common variables for the different build
+# targets here.
+# ==========================================================
+LOCAL_PATH:= $(call my-dir)
 
-aapt_src_files := \
-	AaptAssets.cpp \
-	Command.cpp \
-	CrunchCache.cpp \
-	FileFinder.cpp \
-	Main.cpp \
-	Package.cpp \
-	StringPool.cpp \
-	XMLNode.cpp \
-	ResourceFilter.cpp \
-	ResourceIdCache.cpp \
-	ResourceTable.cpp \
-	Images.cpp \
-	Resource.cpp \
+aaptMain := Main.cpp
+aaptSources := \
+    AaptAssets.cpp \
+    AaptConfig.cpp \
+    AaptUtil.cpp \
+    ApkBuilder.cpp \
+    Command.cpp \
+    CrunchCache.cpp \
+    FileFinder.cpp \
+    Package.cpp \
+    StringPool.cpp \
+    XMLNode.cpp \
+    ResourceFilter.cpp \
+    ResourceIdCache.cpp \
+    ResourceTable.cpp \
+    Images.cpp \
+    Resource.cpp \
     pseudolocalize.cpp \
     SourcePos.cpp \
-	WorkQueue.cpp \
+    WorkQueue.cpp \
     ZipEntry.cpp \
     ZipFile.cpp \
-	qsort_r_compat.c
+    qsort_r_compat.c
 
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
+aaptTests := \
+    tests/AaptConfig_test.cpp \
+    tests/AaptGroupEntry_test.cpp \
+    tests/ResourceFilter_test.cpp
 
-LOCAL_SRC_FILES := $(aapt_src_files)
+aaptCIncludes := \
+    external/libpng \
+    external/zlib
 
-LOCAL_CFLAGS += -Wno-format-y2k
-ifeq (darwin,$(HOST_OS))
-LOCAL_CFLAGS += -D_DARWIN_UNLIMITED_STREAMS
-endif
-
-LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
-
-LOCAL_C_INCLUDES += external/libpng
-LOCAL_C_INCLUDES += external/zlib
-
-LOCAL_STATIC_LIBRARIES := \
-	libandroidfw \
-	libutils \
-	libcutils \
-	libexpat \
-	libpng \
-	liblog \
-	libziparchive-host
+aaptHostLdLibs :=
+aaptHostStaticLibs := \
+    libandroidfw \
+    libpng \
+    liblog \
+    libutils \
+    libcutils \
+    libexpat \
+    libziparchive-host
 
 ifeq ($(HOST_OS),linux)
-LOCAL_LDLIBS += -lrt -ldl -lpthread
+    aaptHostLdLibs += -lrt -ldl -lpthread
 endif
 
 # Statically link libz for MinGW (Win SDK under Linux),
 # and dynamically link for all others.
 ifneq ($(strip $(USE_MINGW)),)
-  LOCAL_STATIC_LIBRARIES += libz
+    aaptHostStaticLibs += libz
 else
-  LOCAL_LDLIBS += -lz
+    aaptHostLdLibs += -lz
 endif
 
+
+# ==========================================================
+# Build the host static library: libaapt
+# ==========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libaapt
+
+LOCAL_SRC_FILES := $(aaptSources)
+LOCAL_C_INCLUDES += $(aaptCIncludes)
+
+LOCAL_CFLAGS += -Wno-format-y2k
+LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
+ifeq (darwin,$(HOST_OS))
+LOCAL_CFLAGS += -D_DARWIN_UNLIMITED_STREAMS
+endif
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+# ==========================================================
+# Build the host executable: aapt
+# ==========================================================
+include $(CLEAR_VARS)
+
 LOCAL_MODULE := aapt
 
+LOCAL_SRC_FILES := $(aaptMain)
+
+LOCAL_STATIC_LIBRARIES += \
+    libaapt \
+    $(aaptHostStaticLibs)
+LOCAL_LDLIBS += $(aaptHostLdLibs)
+
 include $(BUILD_HOST_EXECUTABLE)
 
-# aapt for running on the device
-# =========================================================
+
+# ==========================================================
+# Build the host tests: libaapt_tests
+# ==========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libaapt_tests
+
+LOCAL_SRC_FILES += $(aaptTests)
+LOCAL_C_INCLUDES += $(LOCAL_PATH)
+
+LOCAL_STATIC_LIBRARIES += \
+    libaapt \
+    $(aaptHostStaticLibs)
+LOCAL_LDLIBS += $(aaptHostLdLibs)
+
+include $(BUILD_HOST_NATIVE_TEST)
+
+
+# ==========================================================
+# Build the device executable: aapt
+# ==========================================================
 ifneq ($(SDK_ONLY),true)
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := $(aapt_src_files)
-
 LOCAL_MODULE := aapt
 
-LOCAL_C_INCLUDES += bionic
-LOCAL_C_INCLUDES += bionic/libstdc++/include
-LOCAL_C_INCLUDES += external/stlport/stlport
-LOCAL_C_INCLUDES += external/libpng
-LOCAL_C_INCLUDES += external/zlib
-
-LOCAL_CFLAGS += -Wno-non-virtual-dtor
+LOCAL_SRC_FILES := $(aaptSources) $(aaptMain)
+LOCAL_C_INCLUDES += \
+    $(aaptCIncludes) \
+    bionic \
+    external/stlport/stlport
 
 LOCAL_SHARED_LIBRARIES := \
-        libandroidfw \
-        libutils \
-        libcutils \
-        libpng \
-        liblog \
-        libz
+    libandroidfw \
+    libutils \
+    libcutils \
+    libpng \
+    liblog \
+    libz
 
 LOCAL_STATIC_LIBRARIES := \
-        libstlport_static \
-        libexpat_static
+    libstlport_static \
+    libexpat_static
+
+LOCAL_CPPFLAGS += -Wno-non-virtual-dtor
 
 include $(BUILD_EXECUTABLE)
-endif
+
+endif # Not SDK_ONLY
 
 endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK
diff --git a/tools/aapt/ApkBuilder.cpp b/tools/aapt/ApkBuilder.cpp
new file mode 100644
index 0000000..12f6040
--- /dev/null
+++ b/tools/aapt/ApkBuilder.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AaptAssets.h"
+#include "ApkBuilder.h"
+
+using namespace android;
+
+ApkBuilder::ApkBuilder(const sp<WeakResourceFilter>& configFilter)
+    : mConfigFilter(configFilter)
+    , mDefaultFilter(new AndResourceFilter()) {
+    // Add the default split, which is present for all APKs.
+    mDefaultFilter->addFilter(mConfigFilter);
+    mSplits.add(new ApkSplit(std::set<ConfigDescription>(), mDefaultFilter, true));
+}
+
+status_t ApkBuilder::createSplitForConfigs(const std::set<ConfigDescription>& configs) {
+    const size_t N = mSplits.size();
+    for (size_t i = 0; i < N; i++) {
+        const std::set<ConfigDescription>& splitConfigs = mSplits[i]->getConfigs();
+        std::set<ConfigDescription>::const_iterator iter = configs.begin();
+        for (; iter != configs.end(); iter++) {
+            if (splitConfigs.count(*iter) > 0) {
+                // Can't have overlapping configurations.
+                fprintf(stderr, "ERROR: Split configuration '%s' is already defined "
+                        "in another split.\n", iter->toString().string());
+                return ALREADY_EXISTS;
+            }
+        }
+    }
+
+    sp<StrongResourceFilter> splitFilter = new StrongResourceFilter(configs);
+
+    // Add the inverse filter of this split filter to the base apk filter so it will
+    // omit resources that belong in this split.
+    mDefaultFilter->addFilter(new InverseResourceFilter(splitFilter));
+
+    // Now add the apk-wide config filter to our split filter.
+    sp<AndResourceFilter> filter = new AndResourceFilter();
+    filter->addFilter(splitFilter);
+    filter->addFilter(mConfigFilter);
+    mSplits.add(new ApkSplit(configs, filter));
+    return NO_ERROR;
+}
+
+status_t ApkBuilder::addEntry(const String8& path, const sp<AaptFile>& file) {
+    const size_t N = mSplits.size();
+    for (size_t i = 0; i < N; i++) {
+        if (mSplits[i]->matches(file)) {
+            return mSplits.editItemAt(i)->addEntry(path, file);
+        }
+    }
+    // Entry can be dropped if it doesn't match any split. This will only happen
+    // if the enry doesn't mConfigFilter.
+    return NO_ERROR;
+}
+
+void ApkBuilder::print() const {
+    fprintf(stderr, "APK Builder\n");
+    fprintf(stderr, "-----------\n");
+    const size_t N = mSplits.size();
+    for (size_t i = 0; i < N; i++) {
+        mSplits[i]->print();
+        fprintf(stderr, "\n");
+    }
+}
+
+ApkSplit::ApkSplit(const std::set<ConfigDescription>& configs, const sp<ResourceFilter>& filter, bool isBase)
+    : mConfigs(configs), mFilter(filter), mIsBase(isBase) {
+    std::set<ConfigDescription>::const_iterator iter = configs.begin();
+    for (; iter != configs.end(); iter++) {
+        if (mName.size() > 0) {
+            mName.append(",");
+            mDirName.append("_");
+        }
+
+        String8 configStr = iter->toString();
+        mName.append(configStr);
+        mDirName.append(configStr);
+    }
+}
+
+status_t ApkSplit::addEntry(const String8& path, const sp<AaptFile>& file) {
+    if (!mFiles.insert(OutputEntry(path, file)).second) {
+        // Duplicate file.
+        return ALREADY_EXISTS;
+    }
+    return NO_ERROR;
+}
+
+void ApkSplit::print() const {
+    fprintf(stderr, "APK Split '%s'\n", mName.string());
+
+    std::set<OutputEntry>::const_iterator iter = mFiles.begin();
+    for (; iter != mFiles.end(); iter++) {
+        fprintf(stderr, "  %s (%s)\n", iter->getPath().string(), iter->getFile()->getSourceFile().string());
+    }
+}
diff --git a/tools/aapt/ApkBuilder.h b/tools/aapt/ApkBuilder.h
new file mode 100644
index 0000000..db23c84
--- /dev/null
+++ b/tools/aapt/ApkBuilder.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __APK_BUILDER_H
+#define __APK_BUILDER_H
+
+#include <set>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+#include <utils/Vector.h>
+
+#include "ConfigDescription.h"
+#include "OutputSet.h"
+#include "ResourceFilter.h"
+
+class ApkSplit;
+class AaptFile;
+
+class ApkBuilder : public android::RefBase {
+public:
+    ApkBuilder(const sp<WeakResourceFilter>& configFilter);
+
+    /**
+     * Tells the builder to generate a separate APK for resources that
+     * match the configurations specified. Split APKs can not have
+     * overlapping resources.
+     *
+     * NOTE: All splits should be set up before any files are added.
+     */
+    android::status_t createSplitForConfigs(const std::set<ConfigDescription>& configs);
+
+    /**
+     * Adds a file to be written to the final APK. It's name must not collide
+     * with that of any files previously added. When a Split APK is being
+     * generated, duplicates can exist as long as they are in different splits
+     * (resources.arsc, AndroidManifest.xml).
+     */
+    android::status_t addEntry(const String8& path, const android::sp<AaptFile>& file);
+
+    android::Vector<sp<ApkSplit> >& getSplits() {
+        return mSplits;
+    }
+
+    android::sp<ApkSplit> getBaseSplit() {
+        return mSplits[0];
+    }
+
+    void print() const;
+
+private:
+    android::sp<ResourceFilter> mConfigFilter;
+    android::sp<AndResourceFilter> mDefaultFilter;
+    android::Vector<sp<ApkSplit> > mSplits;
+};
+
+class ApkSplit : public OutputSet {
+public:
+    android::status_t addEntry(const String8& path, const android::sp<AaptFile>& file);
+
+    const std::set<OutputEntry>& getEntries() const {
+        return mFiles;
+    }
+
+    const std::set<ConfigDescription>& getConfigs() const {
+        return mConfigs;
+    }
+
+    bool matches(const sp<AaptFile>& file) const {
+        return mFilter->match(file->getGroupEntry().toParams());
+    }
+
+    sp<ResourceFilter> getResourceFilter() const {
+        return mFilter;
+    }
+
+    const android::String8& getPrintableName() const {
+        return mName;
+    }
+
+    const android::String8& getDirectorySafeName() const {
+        return mDirName;
+    }
+
+    bool isBase() const {
+        return mIsBase;
+    }
+
+    void print() const;
+
+private:
+    friend class ApkBuilder;
+
+    ApkSplit(const std::set<ConfigDescription>& configs, const android::sp<ResourceFilter>& filter, bool isBase=false);
+
+    std::set<ConfigDescription> mConfigs;
+    const sp<ResourceFilter> mFilter;
+    const bool mIsBase;
+    String8 mName;
+    String8 mDirName;
+    std::set<OutputEntry> mFiles;
+};
+
+#endif // __APK_BUILDER_H
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index ebe1bed..ceb52a0 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -151,10 +151,12 @@
     void setPublicOutputFile(const char* file) { mPublicOutputFile = file; }
     const char* getRClassDir() const { return mRClassDir; }
     void setRClassDir(const char* dir) { mRClassDir = dir; }
-    const char* getConfigurations() const { return mConfigurations.size() > 0 ? mConfigurations.string() : NULL; }
+    const android::String8& getConfigurations() const { return mConfigurations; }
     void addConfigurations(const char* val) { if (mConfigurations.size() > 0) { mConfigurations.append(","); mConfigurations.append(val); } else { mConfigurations = val; } }
-    const char* getPreferredConfigurations() const { return mPreferredConfigurations.size() > 0 ? mPreferredConfigurations.string() : NULL; }
-    void addPreferredConfigurations(const char* val) { if (mPreferredConfigurations.size() > 0) { mPreferredConfigurations.append(","); mPreferredConfigurations.append(val); } else { mPreferredConfigurations = val; } }
+    const android::String8& getPreferredDensity() const { return mPreferredDensity; }
+    void setPreferredDensity(const char* val) { mPreferredDensity = val; }
+    void addSplitConfigurations(const char* val) { mPartialConfigurations.add(android::String8(val)); }
+    const android::Vector<android::String8>& getSplitConfigurations() const { return mPartialConfigurations; }
     const char* getResourceIntermediatesDir() const { return mResourceIntermediatesDir; }
     void setResourceIntermediatesDir(const char* dir) { mResourceIntermediatesDir = dir; }
     const android::Vector<const char*>& getPackageIncludes() const { return mPackageIncludes; }
@@ -286,7 +288,8 @@
     const char* mRClassDir;
     const char* mResourceIntermediatesDir;
     android::String8 mConfigurations;
-    android::String8 mPreferredConfigurations;
+    android::String8 mPreferredDensity;
+    android::Vector<android::String8> mPartialConfigurations;
     android::Vector<const char*> mPackageIncludes;
     android::Vector<const char*> mJarFiles;
     android::Vector<const char*> mNoCompressExtensions;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 0af1ce1..dca25e5 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -3,6 +3,7 @@
 //
 // Android Asset Packaging Tool main entry point.
 //
+#include "ApkBuilder.h"
 #include "Main.h"
 #include "Bundle.h"
 #include "ResourceFilter.h"
@@ -2034,6 +2035,58 @@
     return (result != NO_ERROR);
 }
 
+static status_t addResourcesToBuilder(const sp<AaptDir>& dir, const sp<ApkBuilder>& builder, bool ignoreConfig=false) {
+    const size_t numDirs = dir->getDirs().size();
+    for (size_t i = 0; i < numDirs; i++) {
+        bool ignore = ignoreConfig;
+        const sp<AaptDir>& subDir = dir->getDirs().valueAt(i);
+        const char* dirStr = subDir->getLeaf().string();
+        if (!ignore && strstr(dirStr, "mipmap") == dirStr) {
+            ignore = true;
+        }
+        status_t err = addResourcesToBuilder(subDir, builder, ignore);
+        if (err != NO_ERROR) {
+            return err;
+        }
+    }
+
+    const size_t numFiles = dir->getFiles().size();
+    for (size_t i = 0; i < numFiles; i++) {
+        sp<AaptGroup> gp = dir->getFiles().valueAt(i);
+        const size_t numConfigs = gp->getFiles().size();
+        for (size_t j = 0; j < numConfigs; j++) {
+            status_t err = NO_ERROR;
+            if (ignoreConfig) {
+                err = builder->getBaseSplit()->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
+            } else {
+                err = builder->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
+            }
+            if (err != NO_ERROR) {
+                fprintf(stderr, "Failed to add %s (%s) to builder.\n",
+                        gp->getPath().string(), gp->getFiles()[j]->getPrintableSource().string());
+                return err;
+            }
+        }
+    }
+    return NO_ERROR;
+}
+
+static String8 buildApkName(const String8& original, const sp<ApkSplit>& split) {
+    if (split->isBase()) {
+        return original;
+    }
+
+    String8 ext(original.getPathExtension());
+    if (ext == String8(".apk")) {
+        return String8::format("%s_%s%s",
+                original.getBasePath().string(),
+                split->getDirectorySafeName().string(),
+                ext.string());
+    }
+
+    return String8::format("%s_%s", original.string(),
+            split->getDirectorySafeName().string());
+}
 
 /*
  * Package up an asset directory and associated application files.
@@ -2047,17 +2100,18 @@
     int N;
     FILE* fp;
     String8 dependencyFile;
+    sp<ApkBuilder> builder;
 
     // -c en_XA or/and ar_XB means do pseudolocalization
-    ResourceFilter filter;
-    err = filter.parse(bundle->getConfigurations());
+    sp<WeakResourceFilter> configFilter = new WeakResourceFilter();
+    err = configFilter->parse(bundle->getConfigurations());
     if (err != NO_ERROR) {
         goto bail;
     }
-    if (filter.containsPseudo()) {
+    if (configFilter->containsPseudo()) {
         bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_ACCENTED);
     }
-    if (filter.containsPseudoBidi()) {
+    if (configFilter->containsPseudoBidi()) {
         bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_BIDI);
     }
 
@@ -2105,9 +2159,32 @@
         assets->print(String8());
     }
 
+    // Create the ApkBuilder, which will collect the compiled files
+    // to write to the final APK (or sets of APKs if we are building
+    // a Split APK.
+    builder = new ApkBuilder(configFilter);
+
+    // If we are generating a Split APK, find out which configurations to split on.
+    if (bundle->getSplitConfigurations().size() > 0) {
+        const Vector<String8>& splitStrs = bundle->getSplitConfigurations();
+        const size_t numSplits = splitStrs.size();
+        for (size_t i = 0; i < numSplits; i++) {
+            std::set<ConfigDescription> configs;
+            if (!AaptConfig::parseCommaSeparatedList(splitStrs[i], &configs)) {
+                fprintf(stderr, "ERROR: failed to parse split configuration '%s'\n", splitStrs[i].string());
+                goto bail;
+            }
+
+            err = builder->createSplitForConfigs(configs);
+            if (err != NO_ERROR) {
+                goto bail;
+            }
+        }
+    }
+
     // If they asked for any fileAs that need to be compiled, do so.
     if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) {
-        err = buildResources(bundle, assets);
+        err = buildResources(bundle, assets, builder);
         if (err != 0) {
             goto bail;
         }
@@ -2194,11 +2271,24 @@
 
     // Write the apk
     if (outputAPKFile) {
-        err = writeAPK(bundle, assets, String8(outputAPKFile));
+        // Gather all resources and add them to the APK Builder. The builder will then
+        // figure out which Split they belong in.
+        err = addResourcesToBuilder(assets, builder);
         if (err != NO_ERROR) {
-            fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputAPKFile);
             goto bail;
         }
+
+        const Vector<sp<ApkSplit> >& splits = builder->getSplits();
+        const size_t numSplits = splits.size();
+        for (size_t i = 0; i < numSplits; i++) {
+            const sp<ApkSplit>& split = splits[i];
+            String8 outputPath = buildApkName(String8(outputAPKFile), split);
+            err = writeAPK(bundle, outputPath, split);
+            if (err != NO_ERROR) {
+                fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputPath.string());
+                goto bail;
+            }
+        }
     }
 
     // If we've been asked to generate a dependency file, we need to finish up here.
diff --git a/tools/aapt/ConfigDescription.h b/tools/aapt/ConfigDescription.h
new file mode 100644
index 0000000..779c423
--- /dev/null
+++ b/tools/aapt/ConfigDescription.h
@@ -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.
+ */
+
+#ifndef __CONFIG_DESCRIPTION_H
+#define __CONFIG_DESCRIPTION_H
+
+#include <androidfw/ResourceTypes.h>
+
+/**
+ * Subclass of ResTable_config that adds convenient
+ * initialization and comparison methods.
+ */
+struct ConfigDescription : public android::ResTable_config {
+    ConfigDescription() {
+        memset(this, 0, sizeof(*this));
+        size = sizeof(android::ResTable_config);
+    }
+    ConfigDescription(const android::ResTable_config&o) {
+        *static_cast<android::ResTable_config*>(this) = o;
+        size = sizeof(android::ResTable_config);
+    }
+    ConfigDescription(const ConfigDescription&o) {
+        *static_cast<android::ResTable_config*>(this) = o;
+    }
+
+    ConfigDescription& operator=(const android::ResTable_config& o) {
+        *static_cast<android::ResTable_config*>(this) = o;
+        size = sizeof(android::ResTable_config);
+        return *this;
+    }
+    ConfigDescription& operator=(const ConfigDescription& o) {
+        *static_cast<android::ResTable_config*>(this) = o;
+        return *this;
+    }
+
+    inline bool operator<(const ConfigDescription& o) const { return compare(o) < 0; }
+    inline bool operator<=(const ConfigDescription& o) const { return compare(o) <= 0; }
+    inline bool operator==(const ConfigDescription& o) const { return compare(o) == 0; }
+    inline bool operator!=(const ConfigDescription& o) const { return compare(o) != 0; }
+    inline bool operator>=(const ConfigDescription& o) const { return compare(o) >= 0; }
+    inline bool operator>(const ConfigDescription& o) const { return compare(o) > 0; }
+};
+
+#endif // __CONFIG_DESCRIPTION_H
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 1cf4783..5a60014 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -70,6 +70,7 @@
         "        [-F apk-file] [-J R-file-dir] \\\n"
         "        [--product product1,product2,...] \\\n"
         "        [-c CONFIGS] [--preferred-configurations CONFIGS] \\\n"
+        "        [--split CONFIGS [--split CONFIGS]] \\\n"
         "        [raw-files-dir [raw-files-dir] ...] \\\n"
         "        [--output-text-symbols DIR]\n"
         "\n"
@@ -166,10 +167,12 @@
         "       generate dependency files in the same directories for R.java and resource package\n"
         "   --auto-add-overlay\n"
         "       Automatically add resources that are only in overlays.\n"
-        "   --preferred-configurations\n"
-        "       Like the -c option for filtering out unneeded configurations, but\n"
-        "       only expresses a preference.  If there is no resource available with\n"
-        "       the preferred configuration then it will not be stripped.\n"
+        "   --preferred-density\n"
+        "       Specifies a preference for a particular density. Resources that do not\n"
+        "       match this density and have variants that are a closer match are removed.\n"
+        "   --split\n"
+        "       Builds a separate split APK for the configurations listed. This can\n"
+        "       be loaded alongside the base APK at runtime.\n"
         "   --rename-manifest-package\n"
         "       Rewrite the manifest so that its package name is the package name\n"
         "       given here.  Relative class names (for example .Foo) will be\n"
@@ -568,15 +571,24 @@
                     bundle.setGenDependencies(true);
                 } else if (strcmp(cp, "-utf16") == 0) {
                     bundle.setWantUTF16(true);
-                } else if (strcmp(cp, "-preferred-configurations") == 0) {
+                } else if (strcmp(cp, "-preferred-density") == 0) {
                     argc--;
                     argv++;
                     if (!argc) {
-                        fprintf(stderr, "ERROR: No argument supplied for '--preferred-configurations' option\n");
+                        fprintf(stderr, "ERROR: No argument supplied for '--preferred-density' option\n");
                         wantUsage = true;
                         goto bail;
                     }
-                    bundle.addPreferredConfigurations(argv[0]);
+                    bundle.setPreferredDensity(argv[0]);
+                } else if (strcmp(cp, "-split") == 0) {
+                    argc--;
+                    argv++;
+                    if (!argc) {
+                        fprintf(stderr, "ERROR: No argument supplied for '--split' option\n");
+                        wantUsage = true;
+                        goto bail;
+                    }
+                    bundle.addSplitConfigurations(argv[0]);
                 } else if (strcmp(cp, "-rename-manifest-package") == 0) {
                     argc--;
                     argv++;
diff --git a/tools/aapt/Main.h b/tools/aapt/Main.h
index a6b39ac..34c4496 100644
--- a/tools/aapt/Main.h
+++ b/tools/aapt/Main.h
@@ -10,8 +10,12 @@
 #include <utils/threads.h>
 #include <utils/List.h>
 #include <utils/Errors.h>
-#include "Bundle.h"
+#include <utils/StrongPointer.h>
+
 #include "AaptAssets.h"
+#include "ApkBuilder.h"
+#include "Bundle.h"
+#include "ResourceFilter.h"
 #include "ZipFile.h"
 
 
@@ -22,6 +26,8 @@
     #include <time.h>
 #endif /* BENCHMARK */
 
+class OutputSet;
+
 extern int doVersion(Bundle* bundle);
 extern int doList(Bundle* bundle);
 extern int doDump(Bundle* bundle);
@@ -34,13 +40,13 @@
 extern int calcPercent(long uncompressedLen, long compressedLen);
 
 extern android::status_t writeAPK(Bundle* bundle,
-    const sp<AaptAssets>& assets,
-    const android::String8& outputFile);
+    const android::String8& outputFile,
+    const android::sp<OutputSet>& outputSet);
 
 extern android::status_t updatePreProcessedCache(Bundle* bundle);
 
 extern android::status_t buildResources(Bundle* bundle,
-    const sp<AaptAssets>& assets);
+    const sp<AaptAssets>& assets, sp<ApkBuilder>& builder);
 
 extern android::status_t writeResourceSymbols(Bundle* bundle,
     const sp<AaptAssets>& assets, const String8& pkgName, bool includePrivate);
@@ -49,8 +55,6 @@
 
 extern bool isValidResourceType(const String8& type);
 
-ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptAssets>& assets);
-
 extern status_t filterResources(Bundle* bundle, const sp<AaptAssets>& assets);
 
 int dumpResources(Bundle* bundle);
diff --git a/tools/aapt/OutputSet.h b/tools/aapt/OutputSet.h
new file mode 100644
index 0000000..ea9ef70
--- /dev/null
+++ b/tools/aapt/OutputSet.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __OUTPUT_SET_H
+#define __OUTPUT_SET_H
+
+#include <set>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+
+class AaptFile;
+
+class OutputEntry {
+public:
+    OutputEntry() {}
+    OutputEntry(const android::String8& path, const android::sp<const AaptFile>& file)
+        : mPath(path), mFile(file) {}
+
+    inline const android::sp<const AaptFile>& getFile() const {
+        return mFile;
+    }
+
+    inline const android::String8& getPath() const {
+        return mPath;
+    }
+
+    bool operator<(const OutputEntry& o) const { return getPath() < o.mPath; }
+    bool operator==(const OutputEntry& o) const { return getPath() == o.mPath; }
+
+private:
+    android::String8 mPath;
+    android::sp<const AaptFile> mFile;
+};
+
+class OutputSet : public virtual android::RefBase {
+public:
+    virtual const std::set<OutputEntry>& getEntries() const = 0;
+
+    virtual ~OutputSet() {}
+};
+
+#endif // __OUTPUT_SET_H
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index 872d95c..dc16e35 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -5,6 +5,7 @@
 //
 #include "Main.h"
 #include "AaptAssets.h"
+#include "OutputSet.h"
 #include "ResourceTable.h"
 #include "ResourceFilter.h"
 
@@ -36,11 +37,8 @@
 };
 
 /* fwd decls, so I can write this downward */
-ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptAssets>& assets);
-ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptDir>& dir,
-                        const AaptGroupEntry& ge, const ResourceFilter* filter);
-bool processFile(Bundle* bundle, ZipFile* zip,
-                        const sp<AaptGroup>& group, const sp<AaptFile>& file);
+ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<const OutputSet>& outputSet);
+bool processFile(Bundle* bundle, ZipFile* zip, String8 storageName, const sp<const AaptFile>& file);
 bool okayToCompress(Bundle* bundle, const String8& pathName);
 ssize_t processJarFiles(Bundle* bundle, ZipFile* zip);
 
@@ -51,8 +49,7 @@
  * On success, "bundle->numPackages" will be the number of Zip packages
  * we created.
  */
-status_t writeAPK(Bundle* bundle, const sp<AaptAssets>& assets,
-                       const String8& outputFile)
+status_t writeAPK(Bundle* bundle, const String8& outputFile, const sp<OutputSet>& outputSet)
 {
     #if BENCHMARK
     fprintf(stdout, "BENCHMARK: Starting APK Bundling \n");
@@ -112,7 +109,7 @@
         printf("Writing all files...\n");
     }
 
-    count = processAssets(bundle, zip, assets);
+    count = processAssets(bundle, zip, outputSet);
     if (count < 0) {
         fprintf(stderr, "ERROR: unable to process assets while packaging '%s'\n",
                 outputFile.string());
@@ -218,72 +215,24 @@
     return result;
 }
 
-ssize_t processAssets(Bundle* bundle, ZipFile* zip,
-                      const sp<AaptAssets>& assets)
-{
-    ResourceFilter filter;
-    status_t status = filter.parse(bundle->getConfigurations());
-    if (status != NO_ERROR) {
-        return -1;
-    }
-
-    ssize_t count = 0;
-
-    const size_t N = assets->getGroupEntries().size();
-    for (size_t i=0; i<N; i++) {
-        const AaptGroupEntry& ge = assets->getGroupEntries()[i];
-
-        ssize_t res = processAssets(bundle, zip, assets, ge, &filter);
-        if (res < 0) {
-            return res;
-        }
-
-        count += res;
-    }
-
-    return count;
-}
-
-ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptDir>& dir,
-        const AaptGroupEntry& ge, const ResourceFilter* filter)
+ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<const OutputSet>& outputSet)
 {
     ssize_t count = 0;
-
-    const size_t ND = dir->getDirs().size();
-    size_t i;
-    for (i=0; i<ND; i++) {
-        const sp<AaptDir>& subDir = dir->getDirs().valueAt(i);
-
-        const bool filterable = filter != NULL && subDir->getLeaf().find("mipmap-") != 0;
-
-        if (filterable && subDir->getLeaf() != subDir->getPath() && !filter->match(ge.toParams())) {
-            continue;
-        }
-
-        ssize_t res = processAssets(bundle, zip, subDir, ge, filterable ? filter : NULL);
-        if (res < 0) {
-            return res;
-        }
-        count += res;
-    }
-
-    if (filter != NULL && !filter->match(ge.toParams())) {
-        return count;
-    }
-
-    const size_t NF = dir->getFiles().size();
-    for (i=0; i<NF; i++) {
-        sp<AaptGroup> gp = dir->getFiles().valueAt(i);
-        ssize_t fi = gp->getFiles().indexOfKey(ge);
-        if (fi >= 0) {
-            sp<AaptFile> fl = gp->getFiles().valueAt(fi);
-            if (!processFile(bundle, zip, gp, fl)) {
+    const std::set<OutputEntry>& entries = outputSet->getEntries();
+    std::set<OutputEntry>::const_iterator iter = entries.begin();
+    for (; iter != entries.end(); iter++) {
+        const OutputEntry& entry = *iter;
+        if (entry.getFile() == NULL) {
+            fprintf(stderr, "warning: null file being processed.\n");
+        } else {
+            String8 storagePath(entry.getPath());
+            storagePath.convertToResPath();
+            if (!processFile(bundle, zip, storagePath, entry.getFile())) {
                 return UNKNOWN_ERROR;
             }
             count++;
         }
     }
-
     return count;
 }
 
@@ -294,12 +243,10 @@
  * delete the existing entry before adding the new one.
  */
 bool processFile(Bundle* bundle, ZipFile* zip,
-                 const sp<AaptGroup>& group, const sp<AaptFile>& file)
+                 String8 storageName, const sp<const AaptFile>& file)
 {
     const bool hasData = file->hasData();
 
-    String8 storageName(group->getPath());
-    storageName.convertToResPath();
     ZipEntry* entry;
     bool fromGzip = false;
     status_t result;
@@ -403,8 +350,8 @@
             fprintf(stderr, "      Unable to add '%s': file already in archive (try '-u'?)\n",
                     file->getPrintableSource().string());
         } else {
-            fprintf(stderr, "      Unable to add '%s': Zip add failed\n", 
-                    file->getPrintableSource().string());
+            fprintf(stderr, "      Unable to add '%s': Zip add failed (%d)\n",
+                    file->getPrintableSource().string(), result);
         }
         return false;
     }
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index d0581f6..e599643 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -179,24 +179,6 @@
         || type == "color" || type == "menu" || type == "mipmap";
 }
 
-static sp<AaptFile> getResourceFile(const sp<AaptAssets>& assets, bool makeIfNecessary=true)
-{
-    sp<AaptGroup> group = assets->getFiles().valueFor(String8("resources.arsc"));
-    sp<AaptFile> file;
-    if (group != NULL) {
-        file = group->getFiles().valueFor(AaptGroupEntry());
-        if (file != NULL) {
-            return file;
-        }
-    }
-
-    if (!makeIfNecessary) {
-        return NULL;
-    }
-    return assets->addFile(String8("resources.arsc"), AaptGroupEntry(), String8(),
-                            NULL, String8());
-}
-
 static status_t parsePackage(Bundle* bundle, const sp<AaptAssets>& assets,
     const sp<AaptGroup>& grp)
 {
@@ -359,23 +341,6 @@
     return (hasErrors || (res < NO_ERROR)) ? UNKNOWN_ERROR : NO_ERROR;
 }
 
-status_t postProcessImages(const sp<AaptAssets>& assets,
-                           ResourceTable* table,
-                           const sp<ResourceTypeSet>& set)
-{
-    ResourceDirIterator it(set, String8("drawable"));
-    bool hasErrors = false;
-    ssize_t res;
-    while ((res=it.next()) == NO_ERROR) {
-        res = postProcessImage(assets, table, it.getFile());
-        if (res < NO_ERROR) {
-            hasErrors = true;
-        }
-    }
-
-    return (hasErrors || (res < NO_ERROR)) ? UNKNOWN_ERROR : NO_ERROR;
-}
-
 static void collect_files(const sp<AaptDir>& dir,
         KeyedVector<String8, sp<ResourceTypeSet> >* resources)
 {
@@ -906,7 +871,38 @@
     return 0;
 }
 
-status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
+status_t generateAndroidManifestForSplit(const String16& package, const sp<ApkSplit>& split,
+        sp<AaptFile>& outFile) {
+    const String8 filename("AndroidManifest.xml");
+    const String16 androidPrefix("android");
+    const String16 androidNSUri("http://schemas.android.com/apk/res/android");
+    sp<XMLNode> root = XMLNode::newNamespace(filename, androidPrefix, androidNSUri);
+
+    // Build the <manifest> tag
+    sp<XMLNode> manifest = XMLNode::newElement(filename, String16(), String16("manifest"));
+
+    // Add the 'package' attribute which is set to the original package name.
+    manifest->addAttribute(String16(), String16("package"), package);
+
+    // Add the 'split' attribute which describes the configurations included.
+    String8 splitName("config_");
+    splitName.append(split->getDirectorySafeName());
+    manifest->addAttribute(String16(), String16("split"), String16(splitName));
+
+    // Build an empty <application> tag (required).
+    sp<XMLNode> app = XMLNode::newElement(filename, String16(), String16("application"));
+    manifest->addChild(app);
+    root->addChild(manifest);
+
+    status_t err = root->flatten(outFile, true, true);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    outFile->setCompressionMethod(ZipEntry::kCompressDeflated);
+    return NO_ERROR;
+}
+
+status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuilder>& builder)
 {
     // First, look for a package file to parse.  This is required to
     // be able to generate the resource information.
@@ -1122,12 +1118,6 @@
     // --------------------------------------------------------------------
 
     if (table.hasResources()) {
-        sp<AaptFile> resFile(getResourceFile(assets));
-        if (resFile == NULL) {
-            fprintf(stderr, "Error: unable to generate entry for resource data\n");
-            return UNKNOWN_ERROR;
-        }
-
         err = table.assignResourceIds();
         if (err < NO_ERROR) {
             return err;
@@ -1235,16 +1225,24 @@
     }
 
     if (drawables != NULL) {
-        err = postProcessImages(assets, &table, drawables);
-        if (err != NO_ERROR) {
+        ResourceDirIterator it(drawables, String8("drawable"));
+        while ((err=it.next()) == NO_ERROR) {
+            err = postProcessImage(assets, &table, it.getFile());
+            if (err != NO_ERROR) {
+                hasErrors = true;
+            }
+        }
+
+        if (err < NO_ERROR) {
             hasErrors = true;
         }
+        err = NO_ERROR;
     }
 
     if (colors != NULL) {
         ResourceDirIterator it(colors, String8("color"));
         while ((err=it.next()) == NO_ERROR) {
-          err = compileXmlFile(assets, it.getFile(), &table, xmlFlags);
+            err = compileXmlFile(assets, it.getFile(), &table, xmlFlags);
             if (err != NO_ERROR) {
                 hasErrors = true;
             }
@@ -1261,12 +1259,13 @@
         while ((err=it.next()) == NO_ERROR) {
             String8 src = it.getFile()->getPrintableSource();
             err = compileXmlFile(assets, it.getFile(), &table, xmlFlags);
-            if (err != NO_ERROR) {
+            if (err == NO_ERROR) {
+                ResXMLTree block;
+                block.setTo(it.getFile()->getData(), it.getFile()->getSize(), true);
+                checkForIds(src, block);
+            } else {
                 hasErrors = true;
             }
-            ResXMLTree block;
-            block.setTo(it.getFile()->getData(), it.getFile()->getSize(), true);
-            checkForIds(src, block);
         }
 
         if (err < NO_ERROR) {
@@ -1319,15 +1318,35 @@
             return err;
         }
 
-        resFile = getResourceFile(assets);
-        if (resFile == NULL) {
-            fprintf(stderr, "Error: unable to generate entry for resource data\n");
-            return UNKNOWN_ERROR;
-        }
+        Vector<sp<ApkSplit> >& splits = builder->getSplits();
+        const size_t numSplits = splits.size();
+        for (size_t i = 0; i < numSplits; i++) {
+            sp<ApkSplit>& split = splits.editItemAt(i);
+            sp<AaptFile> flattenedTable = new AaptFile(String8("resources.arsc"),
+                    AaptGroupEntry(), String8());
+            err = table.flatten(bundle, split->getResourceFilter(), flattenedTable);
+            if (err != NO_ERROR) {
+                fprintf(stderr, "Failed to generate resource table for split '%s'\n",
+                        split->getPrintableName().string());
+                return err;
+            }
+            split->addEntry(String8("resources.arsc"), flattenedTable);
 
-        err = table.flatten(bundle, resFile);
-        if (err < NO_ERROR) {
-            return err;
+            if (split->isBase()) {
+                resFile = flattenedTable;
+                finalResTable.add(flattenedTable->getData(), flattenedTable->getSize());
+            } else {
+                sp<AaptFile> generatedManifest = new AaptFile(String8("AndroidManifest.xml"),
+                        AaptGroupEntry(), String8());
+                err = generateAndroidManifestForSplit(String16(assets->getPackage()), split,
+                        generatedManifest);
+                if (err != NO_ERROR) {
+                    fprintf(stderr, "Failed to generate AndroidManifest.xml for split '%s'\n",
+                            split->getPrintableName().string());
+                    return err;
+                }
+                split->addEntry(String8("AndroidManifest.xml"), generatedManifest);
+            }
         }
 
         if (bundle->getPublicOutputFile()) {
@@ -1343,18 +1362,13 @@
             table.writePublicDefinitions(String16(assets->getPackage()), fp);
             fclose(fp);
         }
-        
-        // Read resources back in,
-        finalResTable.add(resFile->getData(), resFile->getSize());
-        
-#if 0
-        NOISY(
-              printf("Generated resources:\n");
-              finalResTable.print();
-        )
-#endif
+
+        if (finalResTable.getTableCount() == 0 || resFile == NULL) {
+            fprintf(stderr, "No resource table was generated.\n");
+            return UNKNOWN_ERROR;
+        }
     }
-    
+
     // Perform a basic validation of the manifest file.  This time we
     // parse it with the comments intact, so that we can use them to
     // generate java docs...  so we are not going to write this one
diff --git a/tools/aapt/ResourceFilter.cpp b/tools/aapt/ResourceFilter.cpp
index 8ca852e..de8b4fc 100644
--- a/tools/aapt/ResourceFilter.cpp
+++ b/tools/aapt/ResourceFilter.cpp
@@ -1,119 +1,92 @@
 //
-// Copyright 2011 The Android Open Source Project
+// Copyright 2014 The Android Open Source Project
 //
 // Build resource files from raw assets.
 //
 
 #include "ResourceFilter.h"
+#include "AaptUtil.h"
+#include "AaptConfig.h"
 
 status_t
-ResourceFilter::parse(const char* arg)
+WeakResourceFilter::parse(const String8& str)
 {
-    if (arg == NULL) {
-        return 0;
-    }
-
-    const char* p = arg;
-    const char* q;
-
-    while (true) {
-        q = strchr(p, ',');
-        if (q == NULL) {
-            q = p + strlen(p);
-        }
-
-        String8 part(p, q-p);
-
+    Vector<String8> configStrs = AaptUtil::split(str, ',');
+    const size_t N = configStrs.size();
+    mConfigs.clear();
+    mConfigMask = 0;
+    mConfigs.resize(N);
+    for (size_t i = 0; i < N; i++) {
+        const String8& part = configStrs[i];
         if (part == "en_XA") {
             mContainsPseudoAccented = true;
         } else if (part == "ar_XB") {
             mContainsPseudoBidi = true;
         }
-        int axis;
-        AxisValue value;
-        if (!AaptGroupEntry::parseFilterNamePart(part, &axis, &value)) {
-            fprintf(stderr, "Invalid configuration: %s\n", arg);
-            fprintf(stderr, "                       ");
-            for (int i=0; i<p-arg; i++) {
-                fprintf(stderr, " ");
-            }
-            for (int i=0; i<q-p; i++) {
-                fprintf(stderr, "^");
-            }
-            fprintf(stderr, "\n");
-            return 1;
+
+        std::pair<ConfigDescription, uint32_t>& entry = mConfigs.editItemAt(i);
+
+        AaptLocaleValue val;
+        if (val.initFromFilterString(part)) {
+            // For backwards compatibility, we accept configurations that
+            // only specify locale in the standard 'en_US' format.
+            val.writeTo(&entry.first);
+        } else if (!AaptConfig::parse(part, &entry.first)) {
+            fprintf(stderr, "Invalid configuration: %s\n", part.string());
+            return UNKNOWN_ERROR;
         }
 
-        ssize_t index = mData.indexOfKey(axis);
-        if (index < 0) {
-            mData.add(axis, SortedVector<AxisValue>());
-        }
-        SortedVector<AxisValue>& sv = mData.editValueFor(axis);
-        sv.add(value);
+        entry.second = mDefault.diff(entry.first);
 
-        // If it's a locale with a region, script or variant, we should also match an
-        // unmodified locale of the same language
-        if (axis == AXIS_LOCALE) {
-            if (value.localeValue.region[0] || value.localeValue.script[0] ||
-                value.localeValue.variant[0]) {
-                AxisValue copy;
-                memcpy(copy.localeValue.language, value.localeValue.language,
-                       sizeof(value.localeValue.language));
-                sv.add(copy);
-            }
-        }
-        p = q;
-        if (!*p) break;
-        p++;
+        // Ignore the version
+        entry.second &= ~ResTable_config::CONFIG_VERSION;
+
+        mConfigMask |= entry.second;
     }
 
     return NO_ERROR;
 }
 
 bool
-ResourceFilter::isEmpty() const
+WeakResourceFilter::match(const ResTable_config& config) const
 {
-    return mData.size() == 0;
-}
-
-bool
-ResourceFilter::match(int axis, const AxisValue& value) const
-{
-    if (value.intValue == 0 && (value.localeValue.language[0] == 0)) {
-        // they didn't specify anything so take everything
+    uint32_t mask = mDefault.diff(config);
+    if ((mConfigMask & mask) == 0) {
+        // The two configurations don't have any common axis.
         return true;
     }
-    ssize_t index = mData.indexOfKey(axis);
-    if (index < 0) {
-        // we didn't request anything on this axis so take everything
-        return true;
-    }
-    const SortedVector<AxisValue>& sv = mData.valueAt(index);
-    return sv.indexOf(value) >= 0;
-}
 
-bool
-ResourceFilter::match(int axis, const ResTable_config& config) const
-{
-    return match(axis, AaptGroupEntry::getConfigValueForAxis(config, axis));
-}
-
-bool
-ResourceFilter::match(const ResTable_config& config) const
-{
-    for (int i=AXIS_START; i<=AXIS_END; i++) {
-        if (!match(i, AaptGroupEntry::getConfigValueForAxis(config, i))) {
-            return false;
+    const size_t N = mConfigs.size();
+    for (size_t i = 0; i < N; i++) {
+        const std::pair<ConfigDescription, uint32_t>& entry = mConfigs[i];
+        uint32_t diff = entry.first.diff(config);
+        if ((diff & entry.second) == 0) {
+            return true;
+        } else if ((diff & entry.second) == ResTable_config::CONFIG_LOCALE) {
+            // If the locales differ, but the languages are the same and
+            // the locale we are matching only has a language specified,
+            // we match.
+            if (config.language[0] && memcmp(config.language, entry.first.language, sizeof(config.language)) == 0) {
+                if (config.country[0] == 0) {
+                    return true;
+                }
+            }
         }
     }
-    return true;
+    return false;
 }
 
-const SortedVector<AxisValue>* ResourceFilter::configsForAxis(int axis) const
-{
-    ssize_t index = mData.indexOfKey(axis);
-    if (index < 0) {
-        return NULL;
+status_t
+StrongResourceFilter::parse(const String8& str) {
+    Vector<String8> configStrs = AaptUtil::split(str, ',');
+    ConfigDescription config;
+    mConfigs.clear();
+    for (size_t i = 0; i < configStrs.size(); i++) {
+        if (!AaptConfig::parse(configStrs[i], &config)) {
+            fprintf(stderr, "Invalid configuration: %s\n", configStrs[i].string());
+            return UNKNOWN_ERROR;
+        }
+        mConfigs.insert(config);
     }
-    return &mData.valueAt(index);
+    return NO_ERROR;
 }
diff --git a/tools/aapt/ResourceFilter.h b/tools/aapt/ResourceFilter.h
index c57770e..f459584 100644
--- a/tools/aapt/ResourceFilter.h
+++ b/tools/aapt/ResourceFilter.h
@@ -7,31 +7,137 @@
 #ifndef RESOURCE_FILTER_H
 #define RESOURCE_FILTER_H
 
+#include <androidfw/ResourceTypes.h>
+#include <set>
+#include <utility>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+#include <utils/Vector.h>
+
 #include "AaptAssets.h"
+#include "ConfigDescription.h"
+
+class ResourceFilter : public virtual android::RefBase {
+public:
+    virtual bool match(const android::ResTable_config& config) const = 0;
+};
 
 /**
  * Implements logic for parsing and handling "-c" and "--preferred-configurations"
  * options.
  */
-class ResourceFilter
-{
+class WeakResourceFilter : public ResourceFilter {
 public:
-    ResourceFilter() : mData(), mContainsPseudoAccented(false),
-        mContainsPseudoBidi(false) {}
-    status_t parse(const char* arg);
-    bool isEmpty() const;
-    bool match(int axis, const ResTable_config& config) const;
-    bool match(const ResTable_config& config) const;
-    const SortedVector<AxisValue>* configsForAxis(int axis) const;
-    inline bool containsPseudo() const { return mContainsPseudoAccented; }
-    inline bool containsPseudoBidi() const { return mContainsPseudoBidi; }
+    WeakResourceFilter()
+        : mContainsPseudoAccented(false)
+        , mContainsPseudoBidi(false) {}
+
+    android::status_t parse(const android::String8& str);
+
+    bool match(const android::ResTable_config& config) const;
+
+    inline bool isEmpty() const {
+        return mConfigMask == 0;
+    }
+
+    inline bool containsPseudo() const {
+        return mContainsPseudoAccented;
+    }
+
+    inline bool containsPseudoBidi() const {
+        return mContainsPseudoBidi;
+    }
 
 private:
-    bool match(int axis, const AxisValue& value) const;
+    ConfigDescription mDefault;
+    uint32_t mConfigMask;
+    android::Vector<std::pair<ConfigDescription, uint32_t> > mConfigs;
 
-    KeyedVector<int,SortedVector<AxisValue> > mData;
     bool mContainsPseudoAccented;
     bool mContainsPseudoBidi;
 };
 
+/**
+ * Matches resources that have at least one of the configurations
+ * that this filter is looking for. In order to match a configuration,
+ * the resource must have the exact same configuration.
+ *
+ * This filter acts as a logical OR when matching resources.
+ *
+ * For example, if the filter is looking for resources with
+ * fr-land, de-land, or sw600dp:
+ *
+ * (PASS) fr-land
+ * (FAIL) fr
+ * (PASS) de-land
+ * (FAIL) de
+ * (FAIL) de-sw600dp
+ * (PASS) sw600dp
+ * (FAIL) sw600dp-land
+ */
+class StrongResourceFilter : public ResourceFilter {
+public:
+    StrongResourceFilter() {}
+    StrongResourceFilter(const std::set<ConfigDescription>& configs)
+        : mConfigs(configs) {}
+
+    android::status_t parse(const android::String8& str);
+
+    bool match(const android::ResTable_config& config) const {
+        std::set<ConfigDescription>::const_iterator iter = mConfigs.begin();
+        for (; iter != mConfigs.end(); iter++) {
+            if (iter->compare(config) == 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    inline const std::set<ConfigDescription>& getConfigs() const {
+        return mConfigs;
+    }
+
+private:
+    std::set<ConfigDescription> mConfigs;
+};
+
+/**
+ * Negates the response of the target filter.
+ */
+class InverseResourceFilter : public ResourceFilter {
+public:
+    InverseResourceFilter(const android::sp<ResourceFilter>& filter)
+        : mFilter(filter) {}
+
+    bool match(const android::ResTable_config& config) const {
+        return !mFilter->match(config);
+    }
+
+private:
+    const android::sp<ResourceFilter> mFilter;
+};
+
+/**
+ * A logical AND of all the added filters.
+ */
+class AndResourceFilter : public ResourceFilter {
+public:
+    void addFilter(const android::sp<ResourceFilter>& filter) {
+        mFilters.add(filter);
+    }
+
+    bool match(const android::ResTable_config& config) const {
+        const size_t N = mFilters.size();
+        for (size_t i = 0; i < N; i++) {
+            if (!mFilters[i]->match(config)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+private:
+    android::Vector<android::sp<ResourceFilter> > mFilters;
+};
 #endif
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 25bb26e..efbba40 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -865,6 +865,21 @@
         pseudoBidiParams.country[0] = 'X';
         pseudoBidiParams.country[1] = 'B';
 
+    // We should skip resources for pseudolocales if they were
+    // already added automatically. This is a fix for a transition period when
+    // manually pseudolocalized resources may be expected.
+    // TODO: remove this check after next SDK version release.
+    if ((bundle->getPseudolocalize() & PSEUDO_ACCENTED &&
+         curParams.locale == pseudoParams.locale) ||
+        (bundle->getPseudolocalize() & PSEUDO_BIDI &&
+         curParams.locale == pseudoBidiParams.locale)) {
+        SourcePos(in->getPrintableSource(), 0).warning(
+                "Resource file %s is skipped as pseudolocalization"
+                " was done automatically.",
+                in->getPrintableSource().string());
+        return NO_ERROR;
+    }
+
     while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
         if (code == ResXMLTree::START_TAG) {
             const String16* curTag = NULL;
@@ -1340,7 +1355,6 @@
                                 name,
                                 locale,
                                 SourcePos(in->getPrintableSource(), block.getLineNumber()));
-                        curIsPseudolocalizable = fileIsTranslatable;
                     }
 
                     if (formatted == false16) {
@@ -1352,7 +1366,7 @@
                 curType = string16;
                 curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_STRING;
                 curIsStyled = true;
-                curIsPseudolocalizable = (translatable != false16);
+                curIsPseudolocalizable = fileIsTranslatable && (translatable != false16);
             } else if (strcmp16(block.getElementName(&len), drawable16.string()) == 0) {
                 curTag = &drawable16;
                 curType = drawable16;
@@ -2081,10 +2095,10 @@
     return mNumLocal > 0;
 }
 
-sp<AaptFile> ResourceTable::flatten(Bundle* bundle)
+sp<AaptFile> ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter)
 {
     sp<AaptFile> data = new AaptFile(String8(), AaptGroupEntry(), String8());
-    status_t err = flatten(bundle, data);
+    status_t err = flatten(bundle, filter, data);
     return err == NO_ERROR ? data : NULL;
 }
 
@@ -2644,8 +2658,8 @@
         }
 
         // Check that all requested localizations are present for this string
-        if (mBundle->getConfigurations() != NULL && mBundle->getRequireLocalization()) {
-            const char* allConfigs = mBundle->getConfigurations();
+        if (mBundle->getConfigurations().size() > 0 && mBundle->getRequireLocalization()) {
+            const char* allConfigs = mBundle->getConfigurations().string();
             const char* start = allConfigs;
             const char* comma;
             
@@ -2699,14 +2713,8 @@
     return err;
 }
 
-status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
+status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter, const sp<AaptFile>& dest)
 {
-    ResourceFilter filter;
-    status_t err = filter.parse(bundle->getConfigurations());
-    if (err != NO_ERROR) {
-        return err;
-    }
-
     const ConfigDescription nullConfig;
 
     const size_t N = mOrderedPackages.size();
@@ -2781,7 +2789,7 @@
                 const size_t N = c->getEntries().size();
                 for (size_t ei=0; ei<N; ei++) {
                     ConfigDescription config = c->getEntries().keyAt(ei);
-                    if (filterable && !filter.match(config)) {
+                    if (filterable && !filter->match(config)) {
                         continue;
                     }
                     sp<Entry> e = c->getEntries().valueAt(ei);
@@ -2873,7 +2881,7 @@
             return amt;
         }
 
-        err = flattenLibraryTable(data, libraryPackages);
+        status_t err = flattenLibraryTable(data, libraryPackages);
         if (err != NO_ERROR) {
             fprintf(stderr, "ERROR: failed to write library table\n");
             return err;
@@ -2929,11 +2937,11 @@
                     }
                     const size_t CN = cl->getEntries().size();
                     for (size_t ci=0; ci<CN; ci++) {
-                        if (filterable && !filter.match(cl->getEntries().keyAt(ci))) {
+                        if (filterable && !filter->match(cl->getEntries().keyAt(ci))) {
                             continue;
                         }
                         for (size_t cj=ci+1; cj<CN; cj++) {
-                            if (filterable && !filter.match(cl->getEntries().keyAt(cj))) {
+                            if (filterable && !filter->match(cl->getEntries().keyAt(cj))) {
                                 continue;
                             }
                             typeSpecFlags[ei] |= htodl(
@@ -2975,7 +2983,7 @@
                       config.screenHeightDp,
                       config.layoutDirection));
                       
-                if (filterable && !filter.match(config)) {
+                if (filterable && !filter->match(config)) {
                     continue;
                 }
                 
@@ -3094,7 +3102,7 @@
     }
     
     ssize_t strStart = dest->getSize();
-    err = valueStrings.writeStringBlock(dest);
+    status_t err = valueStrings.writeStringBlock(dest);
     if (err != NO_ERROR) {
         return err;
     }
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index ec8fd175e..a73993c 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -7,8 +7,10 @@
 #ifndef RESOURCE_TABLE_H
 #define RESOURCE_TABLE_H
 
+#include "ConfigDescription.h"
 #include "StringPool.h"
 #include "SourcePos.h"
+#include "ResourceFilter.h"
 
 #include <set>
 #include <map>
@@ -76,37 +78,6 @@
     class Type;
     class Entry;
 
-    struct ConfigDescription : public ResTable_config {
-        ConfigDescription() {
-            memset(this, 0, sizeof(*this));
-            size = sizeof(ResTable_config);
-        }
-        ConfigDescription(const ResTable_config&o) {
-            *static_cast<ResTable_config*>(this) = o;
-            size = sizeof(ResTable_config);
-        }
-        ConfigDescription(const ConfigDescription&o) {
-            *static_cast<ResTable_config*>(this) = o;
-        }
-
-        ConfigDescription& operator=(const ResTable_config& o) {
-            *static_cast<ResTable_config*>(this) = o;
-            size = sizeof(ResTable_config);
-            return *this;
-        }
-        ConfigDescription& operator=(const ConfigDescription& o) {
-            *static_cast<ResTable_config*>(this) = o;
-            return *this;
-        }
-
-        inline bool operator<(const ConfigDescription& o) const { return compare(o) < 0; }
-        inline bool operator<=(const ConfigDescription& o) const { return compare(o) <= 0; }
-        inline bool operator==(const ConfigDescription& o) const { return compare(o) == 0; }
-        inline bool operator!=(const ConfigDescription& o) const { return compare(o) != 0; }
-        inline bool operator>=(const ConfigDescription& o) const { return compare(o) >= 0; }
-        inline bool operator>(const ConfigDescription& o) const { return compare(o) > 0; }
-    };
-
     ResourceTable(Bundle* bundle, const String16& assetsPackage);
 
     status_t addIncludedResources(Bundle* bundle, const sp<AaptAssets>& assets);
@@ -182,7 +153,7 @@
     size_t numLocalResources() const;
     bool hasResources() const;
 
-    sp<AaptFile> flatten(Bundle*);
+    sp<AaptFile> flatten(Bundle* bundle, const sp<const ResourceFilter>& filter);
 
     static inline uint32_t makeResId(uint32_t packageId,
                                      uint32_t typeId,
@@ -223,7 +194,7 @@
     void addLocalization(const String16& name, const String8& locale, const SourcePos& src);
     status_t validateLocalizations(void);
 
-    status_t flatten(Bundle*, const sp<AaptFile>& dest);
+    status_t flatten(Bundle* bundle, const sp<const ResourceFilter>& filter, const sp<AaptFile>& dest);
     status_t flattenLibraryTable(const sp<AaptFile>& dest, const Vector<sp<Package> >& libs);
 
     void writePublicDefinitions(const String16& package, FILE* fp);
diff --git a/tools/aapt/tests/AaptConfig_test.cpp b/tools/aapt/tests/AaptConfig_test.cpp
new file mode 100644
index 0000000..e795d818
--- /dev/null
+++ b/tools/aapt/tests/AaptConfig_test.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <utils/String8.h>
+#include <gtest/gtest.h>
+
+#include "AaptConfig.h"
+#include "ConfigDescription.h"
+#include "TestHelper.h"
+
+using android::String8;
+
+static ::testing::AssertionResult TestParse(const String8& input, ConfigDescription* config=NULL) {
+    if (AaptConfig::parse(String8(input), config)) {
+        return ::testing::AssertionSuccess() << input << " was successfully parsed";
+    }
+    return ::testing::AssertionFailure() << input << " could not be parsed";
+}
+
+static ::testing::AssertionResult TestParse(const char* input, ConfigDescription* config=NULL) {
+    return TestParse(String8(input), config);
+}
+
+TEST(AaptConfigTest, ParseFailWhenQualifiersAreOutOfOrder) {
+    EXPECT_FALSE(TestParse("en-sw600dp-ldrtl"));
+    EXPECT_FALSE(TestParse("land-en"));
+    EXPECT_FALSE(TestParse("hdpi-320dpi"));
+}
+
+TEST(AaptConfigTest, ParseFailWhenQualifiersAreNotMatched) {
+    EXPECT_FALSE(TestParse("en-sw600dp-ILLEGAL"));
+}
+
+TEST(AaptConfigTest, ParseFailWhenQualifiersHaveTrailingDash) {
+    EXPECT_FALSE(TestParse("en-sw600dp-land-"));
+}
+
+TEST(AaptConfigTest, ParseBasicQualifiers) {
+    ConfigDescription config;
+    EXPECT_TRUE(TestParse("", &config));
+    EXPECT_EQ(String8(""), config.toString());
+
+    EXPECT_TRUE(TestParse("fr-land", &config));
+    EXPECT_EQ(String8("fr-land"), config.toString());
+
+    EXPECT_TRUE(TestParse("mcc310-pl-sw720dp-normal-long-port-night-"
+                "xhdpi-keyssoft-qwerty-navexposed-nonav", &config));
+    EXPECT_EQ(String8("mcc310-pl-sw720dp-normal-long-port-night-"
+                "xhdpi-keyssoft-qwerty-navexposed-nonav-v13"), config.toString());
+}
+
+TEST(AaptConfigTest, ParseLocales) {
+    ConfigDescription config;
+    EXPECT_TRUE(TestParse("en-rUS", &config));
+    EXPECT_EQ(String8("en-US"), config.toString());
+}
+
+TEST(AaptConfigTest, ParseQualifierAddedInApi13) {
+    ConfigDescription config;
+    EXPECT_TRUE(TestParse("sw600dp", &config));
+    EXPECT_EQ(String8("sw600dp-v13"), config.toString());
+
+    EXPECT_TRUE(TestParse("sw600dp-v8", &config));
+    EXPECT_EQ(String8("sw600dp-v13"), config.toString());
+}
diff --git a/tools/aapt/tests/AaptGroupEntry_test.cpp b/tools/aapt/tests/AaptGroupEntry_test.cpp
new file mode 100644
index 0000000..7348a08
--- /dev/null
+++ b/tools/aapt/tests/AaptGroupEntry_test.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <utils/String8.h>
+#include <gtest/gtest.h>
+
+#include "AaptAssets.h"
+#include "ResourceFilter.h"
+#include "TestHelper.h"
+
+using android::String8;
+
+static ::testing::AssertionResult TestParse(AaptGroupEntry& entry, const String8& dirName,
+        String8* outType) {
+    if (entry.initFromDirName(dirName, outType)) {
+        return ::testing::AssertionSuccess() << dirName << " was successfully parsed";
+    }
+    return ::testing::AssertionFailure() << dirName << " could not be parsed";
+}
+
+static ::testing::AssertionResult TestParse(AaptGroupEntry& entry, const char* input,
+        String8* outType) {
+    return TestParse(entry, String8(input), outType);
+}
+
+TEST(AaptGroupEntryTest, ParseNoQualifier) {
+    AaptGroupEntry entry;
+    String8 type;
+    EXPECT_TRUE(TestParse(entry, "menu", &type));
+    EXPECT_EQ(String8("menu"), type);
+}
+
+TEST(AaptGroupEntryTest, ParseCorrectType) {
+    AaptGroupEntry entry;
+    String8 type;
+    EXPECT_TRUE(TestParse(entry, "anim", &type));
+    EXPECT_EQ(String8("anim"), type);
+
+    EXPECT_TRUE(TestParse(entry, "animator", &type));
+    EXPECT_EQ(String8("animator"), type);
+}
diff --git a/tools/aapt/tests/ResourceFilter_test.cpp b/tools/aapt/tests/ResourceFilter_test.cpp
new file mode 100644
index 0000000..30697bb
--- /dev/null
+++ b/tools/aapt/tests/ResourceFilter_test.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <androidfw/ResourceTypes.h>
+#include <utils/String8.h>
+#include <gtest/gtest.h>
+
+#include "AaptConfig.h"
+#include "ResourceFilter.h"
+#include "ConfigDescription.h"
+
+using android::String8;
+
+// In this context, 'Axis' represents a particular field in the configuration,
+// such as language or density.
+
+TEST(WeakResourceFilterTest, EmptyFilterMatchesAnything) {
+    WeakResourceFilter filter;
+    ASSERT_EQ(NO_ERROR, filter.parse(String8("")));
+
+    ConfigDescription config;
+    config.density = 320;
+
+    EXPECT_TRUE(filter.match(config));
+
+    config.language[0] = 'f';
+    config.language[1] = 'r';
+
+    EXPECT_TRUE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, MatchesConfigWithUnrelatedAxis) {
+    WeakResourceFilter filter;
+    ASSERT_EQ(NO_ERROR, filter.parse(String8("fr")));
+
+    ConfigDescription config;
+    config.density = 320;
+
+    EXPECT_TRUE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, MatchesConfigWithSameValueAxis) {
+    WeakResourceFilter filter;
+    ASSERT_EQ(NO_ERROR, filter.parse(String8("fr")));
+
+    ConfigDescription config;
+    config.language[0] = 'f';
+    config.language[1] = 'r';
+
+    EXPECT_TRUE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, MatchesConfigWithSameValueAxisAndOtherUnrelatedAxis) {
+    WeakResourceFilter filter;
+    ASSERT_EQ(NO_ERROR, filter.parse(String8("fr")));
+
+    ConfigDescription config;
+    config.language[0] = 'f';
+    config.language[1] = 'r';
+    config.density = 320;
+
+    EXPECT_TRUE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, DoesNotMatchConfigWithDifferentValueAxis) {
+    WeakResourceFilter filter;
+    ASSERT_EQ(NO_ERROR, filter.parse(String8("fr")));
+
+    ConfigDescription config;
+    config.language[0] = 'd';
+    config.language[1] = 'e';
+
+    EXPECT_FALSE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, MatchesConfigWithSameLanguageButNoRegionSpecified) {
+    WeakResourceFilter filter;
+    ASSERT_EQ(NO_ERROR, filter.parse(String8("de-rDE")));
+
+    ConfigDescription config;
+    config.language[0] = 'd';
+    config.language[1] = 'e';
+
+    EXPECT_TRUE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, ParsesStandardLocaleOnlyString) {
+    WeakResourceFilter filter;
+    EXPECT_EQ(NO_ERROR, filter.parse(String8("de_DE")));
+}
+
+TEST(WeakResourceFilterTest, IgnoresVersion) {
+    WeakResourceFilter filter;
+    ASSERT_EQ(NO_ERROR, filter.parse(String8("normal-v4")));
+
+    ConfigDescription config;
+    config.smallestScreenWidthDp = 600;
+    config.version = 13;
+
+    // The configs don't match on any axis besides version, which should be ignored.
+    EXPECT_TRUE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, MatchesConfigWithRegion) {
+    WeakResourceFilter filter;
+    ASSERT_EQ(NO_ERROR, filter.parse(String8("kok,kok_IN,kok_419")));
+
+    ConfigDescription config;
+    AaptLocaleValue val;
+    ASSERT_TRUE(val.initFromFilterString(String8("kok_IN")));
+    val.writeTo(&config);
+
+    EXPECT_TRUE(filter.match(config));
+}
+
diff --git a/tools/aapt/tests/TestHelper.h b/tools/aapt/tests/TestHelper.h
new file mode 100644
index 0000000..79174832
--- /dev/null
+++ b/tools/aapt/tests/TestHelper.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TEST_HELPER_H
+#define __TEST_HELPER_H
+
+#include <utils/String8.h>
+
+namespace android {
+
+/**
+ * Stream operator for nicely printing String8's in gtest output.
+ */
+inline std::ostream& operator<<(std::ostream& stream, const String8& str) {
+    return stream << str.string();
+}
+
+}
+
+#endif
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index bb05d45..aede236 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -71,7 +71,7 @@
      * Returns the native delegate associated to a given {@link Canvas} object.
      */
     public static Canvas_Delegate getDelegate(Canvas canvas) {
-        return sManager.getDelegate(canvas.mNativeCanvas);
+        return sManager.getDelegate(canvas.getNativeCanvas());
     }
 
     /**
@@ -102,7 +102,7 @@
     @LayoutlibDelegate
     /*package*/ static boolean isOpaque(Canvas thisCanvas) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return false;
         }
@@ -113,7 +113,7 @@
     @LayoutlibDelegate
     /*package*/ static int getWidth(Canvas thisCanvas) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return 0;
         }
@@ -124,7 +124,7 @@
     @LayoutlibDelegate
     /*package*/ static int getHeight(Canvas thisCanvas) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return 0;
         }
@@ -135,7 +135,7 @@
     @LayoutlibDelegate
    /*package*/ static void translate(Canvas thisCanvas, float dx, float dy) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return;
         }
@@ -146,7 +146,7 @@
     @LayoutlibDelegate
     /*package*/ static void rotate(Canvas thisCanvas, float degrees) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return;
         }
@@ -157,7 +157,7 @@
     @LayoutlibDelegate
    /*package*/ static void scale(Canvas thisCanvas, float sx, float sy) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return;
         }
@@ -168,7 +168,7 @@
     @LayoutlibDelegate
    /*package*/ static void skew(Canvas thisCanvas, float kx, float ky) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return;
         }
@@ -204,7 +204,7 @@
     /*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right,
             float bottom) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return false;
         }
@@ -227,7 +227,7 @@
     @LayoutlibDelegate
     /*package*/ static int save(Canvas thisCanvas, int saveFlags) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return 0;
         }
@@ -238,7 +238,7 @@
     @LayoutlibDelegate
     /*package*/ static void restore(Canvas thisCanvas) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return;
         }
@@ -249,7 +249,7 @@
     @LayoutlibDelegate
     /*package*/ static int getSaveCount(Canvas thisCanvas) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return 0;
         }
@@ -260,7 +260,7 @@
     @LayoutlibDelegate
     /*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return;
         }
@@ -287,7 +287,7 @@
     /*package*/ static void drawLines(Canvas thisCanvas,
             final float[] pts, final int offset, final int count,
             Paint paint) {
-        draw(thisCanvas.mNativeCanvas, paint.mNativePaint, false /*compositeOnly*/,
+        draw(thisCanvas.getNativeCanvas(), paint.mNativePaint, false /*compositeOnly*/,
                 false /*forceSrcMode*/, new GcSnapshot.Drawable() {
                     @Override
                     public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
diff --git a/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java b/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
index 4bef424..cdb839a 100644
--- a/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
@@ -16,6 +16,12 @@
 
 package com.android.internal.view.menu;
 
+import com.android.layoutlib.bridge.android.BridgeContext;
+
+import android.content.Context;
+import android.view.ContextThemeWrapper;
+import android.view.View;
+
 /**
  * An extension of the {@link MenuItemImpl} to store the view cookie also.
  */
@@ -27,6 +33,7 @@
      * at the time of rendering.
      */
     private Object viewCookie;
+    private BridgeContext mContext;
 
     /**
      * Instantiates this menu item.
@@ -34,14 +41,28 @@
     BridgeMenuItemImpl(MenuBuilder menu, int group, int id, int categoryOrder, int ordering,
             CharSequence title, int showAsAction) {
         super(menu, group, id, categoryOrder, ordering, title, showAsAction);
+        Context context = menu.getContext();
+        if (context instanceof ContextThemeWrapper) {
+            context = ((ContextThemeWrapper) context).getBaseContext();
+        }
+        if (context instanceof BridgeContext) {
+            mContext = ((BridgeContext) context);
+        }
     }
 
-
     public Object getViewCookie() {
         return viewCookie;
     }
 
     public void setViewCookie(Object viewCookie) {
+        // If the menu item has an associated action provider view,
+        // directly set the cookie in the view to cookie map stored in BridgeContext.
+        View actionView = getActionView();
+        if (actionView != null && mContext != null) {
+            mContext.addViewKey(actionView, viewCookie);
+            // We don't need to add the view cookie to the this item now. But there's no harm in
+            // storing it, in case we need it in the future.
+        }
         this.viewCookie = viewCookie;
     }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
index 08512e7..936ab4f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
@@ -50,6 +50,7 @@
 import android.view.MenuInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.ActionMenuView;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.ListAdapter;
@@ -179,8 +180,9 @@
             Predicate<View> overflowMenuButtonTest = new Predicate<View>() {
                 @Override
                 public boolean apply(View view) {
-                    return view.getClass().getName()
-                            .equals("android.widget.ActionMenuPresenter$OverflowMenuButton");
+                    ViewGroup.LayoutParams lp = view.getLayoutParams();
+                    return lp instanceof ActionMenuView.LayoutParams &&
+                            ((ActionMenuView.LayoutParams) lp).isOverflowButton;
                 }
             };
             View overflowMenu = null;
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 9787432..4af73cf 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
@@ -183,6 +183,7 @@
         SessionParams params = getParams();
         BridgeContext context = getContext();
 
+
         RenderResources resources = getParams().getResources();
         DisplayMetrics metrics = getContext().getMetrics();
 
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 813a895..59979ce 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
@@ -137,6 +137,7 @@
         "android.text.format.DateFormat#is24HourFormat",
         "android.view.Choreographer#getRefreshRate",
         "android.view.Display#updateDisplayInfoLocked",
+        "android.view.Display#getWindowManager",
         "android.view.LayoutInflater#rInflate",
         "android.view.LayoutInflater#parseInclude",
         "android.view.View#isInEditMode",
diff --git a/wifi/java/android/net/wifi/IWifiScanner.aidl b/wifi/java/android/net/wifi/IWifiScanner.aidl
new file mode 100644
index 0000000..fef2d11
--- /dev/null
+++ b/wifi/java/android/net/wifi/IWifiScanner.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.os.Messenger;
+
+/**
+ * {@hide}
+ */
+interface IWifiScanner
+{
+    Messenger getMessenger();
+}
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index d7ecaff..1cb9546 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -56,6 +56,13 @@
     public long timestamp;
 
     /**
+     * Timestamp representing date when this result was last seen, in milliseconds from 1970
+     * {@hide}
+     */
+    public long seen;
+
+
+    /**
      * The approximate distance to the AP in centimeter, if available.  Else
      * {@link UNSPECIFIED}.
      * {@hide}
@@ -114,9 +121,17 @@
             timestamp = source.timestamp;
             distanceCm = source.distanceCm;
             distanceSdCm = source.distanceSdCm;
+            seen = source.seen;
         }
     }
 
+    /** empty scan result
+     *
+     * {@hide}
+     * */
+    public ScanResult() {
+    }
+
     @Override
     public String toString() {
         StringBuffer sb = new StringBuffer();
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 6562462..85b81d9 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -21,6 +21,7 @@
 import android.os.Parcel;
 import android.text.TextUtils;
 
+import java.util.HashMap;
 import java.util.BitSet;
 
 /**
@@ -302,6 +303,156 @@
 
     /**
      * @hide
+     * dhcp server MAC address if known
+     */
+    public String dhcpServer;
+
+    /**
+     * @hide
+     * default Gateway MAC address if known
+     */
+    public String defaultGwMacAddress;
+
+    /**
+     * @hide
+     * BSSID list on which this configuration was seen.
+     * TODO: prevent this list to grow infinitely, age-out the results
+     */
+    public HashMap<String, ScanResult> scanResultCache;
+
+    /** @hide **/
+    public static int INVALID_RSSI = -127;
+
+    /**
+     * @hide
+     * A summary of the RSSI and Band status for that configuration
+     * This is used as a temporary value by the auto-join controller
+     */
+    public final class Visibility
+    {
+        public int rssi5;   // strongest 5GHz RSSI
+        public int rssi24;  // strongest 2.4GHz RSSI
+        public int num5;    // number of BSSIDs on 5GHz
+        public int num24;   // number of BSSIDs on 2.4GHz
+        public long age5;  // timestamp of the strongest 5GHz BSSID (last time it was seen)
+        public long age24;   // timestamp of the strongest 2.4GHz BSSID (last time it was seen)
+        public Visibility()
+        {
+            rssi5 = INVALID_RSSI;
+            rssi24 = INVALID_RSSI;
+        }
+        public Visibility(Visibility source)
+        {
+            rssi5 = source.rssi5;
+            rssi24 = source.rssi24;
+            age24 = source.age24;
+            age5 = source.age5;
+            num24 = source.num24;
+            num5 = source.num5;
+        }
+    }
+
+    /** @hide
+     * Cache the visibility status of this configuration.
+     * Visibility can change at any time depending on scan results availability.
+     * Owner of the WifiConfiguration is responsible to set this field based on
+     * recent scan results.
+     ***/
+    public Visibility visibility;
+
+    /** @hide
+     * calculate and set Visibility for that configuration.
+     *
+     * age in milliseconds: we will consider only ScanResults that are more recent,
+     * i.e. younger.
+     ***/
+    public Visibility setVisibility(long age) {
+        if (scanResultCache == null) {
+            visibility = null;
+            return null;
+        }
+
+        Visibility status = new Visibility();
+
+        long now_ms = System.currentTimeMillis();
+        for(ScanResult result : scanResultCache.values()) {
+            if (result.seen == 0)
+                continue;
+
+            if ((result.frequency > 4900) && (result.frequency < 5900)) {
+                //strictly speaking: [4915, 5825]
+                //number of known BSSID on 5GHz band
+                status.num5 = status.num5 + 1;
+            } else if ((result.frequency > 2400) && (result.frequency < 2500)) {
+                //strictly speaking: [2412, 2482]
+                //number of known BSSID on 2.4Ghz band
+                status.num24 = status.num24 + 1;
+            }
+
+            if ((now_ms - result.seen) > age) continue;
+
+            if ((result.frequency > 4900) && (result.frequency < 5900)) {
+                if (result.level > status.rssi5) {
+                    status.rssi5 = result.level;
+                    status.age5 = result.seen;
+                }
+            } else if ((result.frequency > 2400) && (result.frequency < 2500)) {
+                if (result.level > status.rssi24) {
+                    status.rssi24 = result.level;
+                    status.age24 = result.seen;
+                }
+            }
+        }
+        visibility = status;
+        return status;
+    }
+
+    /** @hide */
+    public static final int AUTO_JOIN_ENABLED                   = 0;
+    /** @hide */
+    public static final int AUTO_JOIN_DISABLED_ON_AUTH_FAILURE  = 1;
+    /**
+     * @hide
+     */
+    public int autoJoinStatus;
+
+    /**
+     * @hide
+     * Indicate that a WifiConfiguration is temporary and should not be saved
+     * nor considered by AutoJoin.
+     */
+    public boolean ephemeral;
+
+    /**
+     * @hide
+     * Connect choices
+     *
+     * remember the keys identifying the known WifiConfiguration over which this configuration
+     * was preferred by user or a "WiFi Network Management app", that is,
+     * a WifiManager.CONNECT_NETWORK or SELECT_NETWORK was received while this configuration
+     * was visible to the user:
+     * configKey is : "SSID"-WEP-WPA_PSK-WPA_EAP
+     *
+     * The integer represents the configuration's RSSI at that time (useful?)
+     *
+     * The overall auto-join algorithm make use of past connect choice so as to sort configuration,
+     * the exact algorithm still fluctuating as of 5/7/2014
+     *
+     */
+    public HashMap<String, Integer> connectChoices;
+
+    /**
+     * @hide
+     * Linked Configurations: represent the set of Wificonfigurations that are equivalent
+     * regarding roaming and auto-joining.
+     * The linked configuration may or may not have same SSID, and may or may not have same
+     * credentials.
+     * For instance, linked configurations will have same defaultGwMacAddress or same dhcp server.
+     */
+    public HashMap<String, Integer>  linkedConfigurations;
+
+    /**
+     * @hide
      */
     public enum ProxySettings {
         /* No proxy is to be used. Any existing proxy settings
@@ -346,6 +497,7 @@
         ipAssignment = IpAssignment.UNASSIGNED;
         proxySettings = ProxySettings.UNASSIGNED;
         linkProperties = new LinkProperties();
+        autoJoinStatus = AUTO_JOIN_ENABLED;
     }
 
     /**
@@ -354,6 +506,12 @@
      * @hide
      */
     public boolean isValid() {
+        if (SSID == null)
+            return false;
+
+        if (allowedKeyManagement == null)
+            return false;
+
         if (allowedKeyManagement.cardinality() > 1) {
             if (allowedKeyManagement.cardinality() != 2) {
                 return false;
@@ -369,6 +527,32 @@
 
         // TODO: Add more checks
         return true;
+
+    }
+
+    /**
+     * most recent time we have seen this configuration
+     * @return most recent scanResult
+     * @hide
+     */
+    public ScanResult lastSeen() {
+        ScanResult mostRecent = null;
+
+        if (scanResultCache == null) {
+            return null;
+        }
+
+        for (ScanResult result : scanResultCache.values()) {
+            if (mostRecent == null) {
+                if (result.seen != 0)
+                   mostRecent = result;
+            } else {
+                if (result.seen > mostRecent.seen) {
+                   mostRecent = result;
+                }
+            }
+        }
+        return mostRecent;
     }
 
     @Override
@@ -570,7 +754,48 @@
         return KeyMgmt.NONE;
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /* @hide
+     * Cache the config key, this seems useful as a speed up since a lot of
+     * lookups in the config store are done and based on this key.
+     */
+    String mCachedConfigKey;
+
+    /** @hide
+     *  return the string used to calculate the hash in WifiConfigStore
+     *  and uniquely identify this WifiConfiguration
+     */
+    public String configKey(boolean allowCached) {
+        String key;
+        if (allowCached && mCachedConfigKey != null) {
+            key = mCachedConfigKey;
+        } else {
+            key = this.SSID;
+            if (key == null)
+                key = "";
+            if (this.wepKeys[0] != null) {
+                key = key + "-WEP";
+            }
+            if (this.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
+                key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_PSK];
+            }
+            if (this.allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
+                    this.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
+                key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_EAP];
+            }
+            mCachedConfigKey = key;
+        }
+        return key;
+    }
+
+    /** @hide
+     * get configKey, force calculating the config string
+     */
+    public String configKey() {
+        return configKey(false);
+    }
+
+
+        /** Implement the Parcelable interface {@hide} */
     public int describeContents() {
         return 0;
     }
@@ -603,8 +828,32 @@
 
             ipAssignment = source.ipAssignment;
             proxySettings = source.proxySettings;
+
+            defaultGwMacAddress = source.defaultGwMacAddress;
+
             linkProperties = new LinkProperties(source.linkProperties);
-        }
+            if ((source.scanResultCache != null) && (source.scanResultCache.size() > 0)) {
+                scanResultCache = new HashMap<String, ScanResult>();
+                scanResultCache.putAll(source.scanResultCache);
+            }
+
+            if ((source.connectChoices != null) && (source.connectChoices.size() > 0)) {
+                connectChoices = new HashMap<String, Integer>();
+                connectChoices.putAll(source.connectChoices);
+            }
+
+            if ((source.linkedConfigurations != null)
+                    && (source.linkedConfigurations.size() > 0)) {
+                linkedConfigurations = new HashMap<String, Integer>();
+                linkedConfigurations.putAll(source.linkedConfigurations);
+            }
+            mCachedConfigKey = null; //force null configKey
+            autoJoinStatus = source.autoJoinStatus;
+
+            if (source.visibility != null) {
+                visibility = new Visibility(source.visibility);
+            }
+       }
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -633,6 +882,10 @@
         dest.writeString(ipAssignment.name());
         dest.writeString(proxySettings.name());
         dest.writeParcelable(linkProperties, flags);
+
+        dest.writeString(dhcpServer);
+        dest.writeString(defaultGwMacAddress);
+        dest.writeInt(autoJoinStatus);
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -664,6 +917,10 @@
                 config.proxySettings = ProxySettings.valueOf(in.readString());
                 config.linkProperties = in.readParcelable(null);
 
+                config.dhcpServer = in.readString();
+                config.defaultGwMacAddress = in.readString();
+                config.autoJoinStatus = in.readInt();
+
                 return config;
             }
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 5af1e4e..15b65c1 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -402,12 +402,12 @@
     public static final String EXTRA_LINK_PROPERTIES = "linkProperties";
 
     /**
-     * The lookup key for a {@link android.net.LinkCapabilities} object associated with the
+     * The lookup key for a {@link android.net.NetworkCapabilities} object associated with the
      * Wi-Fi network. Retrieve with
      * {@link android.content.Intent#getParcelableExtra(String)}.
      * @hide
      */
-    public static final String EXTRA_LINK_CAPABILITIES = "linkCapabilities";
+    public static final String EXTRA_NETWORK_CAPABILITIES = "networkCapabilities";
 
     /**
      * The network IDs of the configured networks could have changed.
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
new file mode 100644
index 0000000..e02e14c
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+
+/**
+ * This class provides a way to scan the Wifi universe around the device
+ * Get an instance of this class by calling
+ * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context
+ * .WIFI_SCANNING_SERVICE)}.
+ * @hide
+ */
+public class WifiScanner {
+
+    public static final int WIFI_BAND_UNSPECIFIED = 0;      /* not specified */
+    public static final int WIFI_BAND_24_GHZ = 1;           /* 2.4 GHz band */
+    public static final int WIFI_BAND_5_GHZ = 2;            /* 5 GHz band without DFS channels */
+    public static final int WIFI_BAND_5_GHZ_DFS_ONLY  = 4;  /* 5 GHz band with DFS channels */
+    public static final int WIFI_BAND_5_GHZ_WITH_DFS  = 6;  /* 5 GHz band with DFS channels */
+    public static final int WIFI_BAND_BOTH = 3;             /* both bands without DFS channels */
+    public static final int WIFI_BAND_BOTH_WITH_DFS = 7;    /* both bands with DFS channels */
+
+    public static final int MIN_SCAN_PERIOD_MS = 300;       /* minimum supported period */
+    public static final int MAX_SCAN_PERIOD_MS = 1024000;   /* maximum supported period */
+
+    public static final int REASON_SUCCEEDED = 0;
+    public static final int REASON_UNSPECIFIED = -1;
+    public static final int REASON_INVALID_LISTENER = -2;
+    public static final int REASON_INVALID_REQUEST = -3;
+    public static final int REASON_CONFLICTING_REQUEST = -4;
+
+    public static interface ActionListener {
+        public void onSuccess(Object result);
+        public void onFailure(int reason, Object exception);
+    }
+
+    /**
+     * gives you all the possible channels; channel is specified as an
+     * integer with frequency in MHz i.e. channel 1 is 2412
+     */
+    public List<Integer> getAvailableChannels(int band) {
+        return null;
+    }
+
+    /**
+     * provides channel specification to the APIs
+     */
+    public static class ChannelSpec {
+        public int frequency;
+        public boolean passive;                                    /* ignored on DFS channels */
+        public int dwellTimeMS;                                    /* not supported for now */
+
+        public ChannelSpec(int frequency) {
+            this.frequency = frequency;
+            passive = false;
+            dwellTimeMS = 0;
+        }
+    }
+
+    public static final int REPORT_EVENT_AFTER_BUFFER_FULL = 0;
+    public static final int REPORT_EVENT_AFTER_EACH_SCAN = 1;
+    public static final int REPORT_EVENT_FULL_SCAN_RESULT = 2;
+
+    /**
+     * scan configuration parameters
+     */
+    public static class ScanSettings implements Parcelable {
+
+        public int band;                                           /* ignore channels if specified */
+        public ChannelSpec[] channels;                             /* list of channels to scan */
+        public int periodInMs;                                     /* period of scan */
+        public int reportEvents;                                   /* a valid REPORT_EVENT value */
+
+        /** Implement the Parcelable interface {@hide} */
+        public int describeContents() {
+            return 0;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(band);
+            dest.writeInt(periodInMs);
+            dest.writeInt(channels.length);
+
+            for (int i = 0; i < channels.length; i++) {
+                dest.writeInt(channels[i].frequency);
+                dest.writeInt(channels[i].dwellTimeMS);
+                dest.writeInt(channels[i].passive ? 1 : 0);
+            }
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public static final Creator<ScanSettings> CREATOR =
+                new Creator<ScanSettings>() {
+                    public ScanSettings createFromParcel(Parcel in) {
+
+                        ScanSettings settings = new ScanSettings();
+                        settings.band = in.readInt();
+                        settings.periodInMs = in.readInt();
+                        int num_channels = in.readInt();
+                        settings.channels = new ChannelSpec[num_channels];
+                        for (int i = 0; i < num_channels; i++) {
+                            int frequency = in.readInt();
+
+                            ChannelSpec spec = new ChannelSpec(frequency);
+                            spec.dwellTimeMS = in.readInt();
+                            spec.passive = in.readInt() == 1;
+                            settings.channels[i] = spec;
+                        }
+
+                        return settings;
+                    }
+
+                    public ScanSettings[] newArray(int size) {
+                        return new ScanSettings[size];
+                    }
+                };
+
+    }
+
+    public static class InformationElement {
+        public int id;
+        public byte[] bytes;
+    }
+
+    public static class FullScanResult {
+        public ScanResult result;
+        public InformationElement informationElements[];
+    }
+
+    /** @hide */
+    public static class ParcelableScanResults implements Parcelable {
+        public ScanResult mResults[];
+
+        public ParcelableScanResults(ScanResult[] results) {
+            mResults = results;
+        }
+
+        public ScanResult[] getResults() {
+            return mResults;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public int describeContents() {
+            return 0;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mResults.length);
+            for (int i = 0; i < mResults.length; i++) {
+                ScanResult result = mResults[i];
+                result.writeToParcel(dest, flags);
+            }
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public static final Creator<ParcelableScanResults> CREATOR =
+                new Creator<ParcelableScanResults>() {
+                    public ParcelableScanResults createFromParcel(Parcel in) {
+                        int n = in.readInt();
+                        ScanResult results[] = new ScanResult[n];
+                        for (int i = 0; i < n; i++) {
+                            results[i] = ScanResult.CREATOR.createFromParcel(in);
+                        }
+                        return new ParcelableScanResults(results);
+                    }
+
+                    public ParcelableScanResults[] newArray(int size) {
+                        return new ParcelableScanResults[size];
+                    }
+                };
+    }
+
+    /**
+     * Framework is co-ordinating scans across multiple apps; so it may not give exactly the
+     * same period requested. The period granted is stated on the onSuccess() event; and
+     * onPeriodChanged() will be called if/when it is changed because of multiple conflicting
+     * requests. This is similar to the way timers are handled.
+     */
+    public interface ScanListener extends ActionListener {
+        public void onPeriodChanged(int periodInMs);
+        public void onResults(ScanResult[] results);
+        public void onFullResult(FullScanResult fullScanResult);
+    }
+
+    public void scan(ScanSettings settings, ScanListener listener) {
+        validateChannel();
+        sAsyncChannel.sendMessage(CMD_SCAN, 0, putListener(listener), settings);
+    }
+    public void startBackgroundScan(ScanSettings settings, ScanListener listener) {
+        validateChannel();
+        sAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, putListener(listener), settings);
+    }
+    public void stopBackgroundScan(boolean flush, ScanListener listener) {
+        validateChannel();
+        sAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, removeListener(listener));
+    }
+    public void retrieveScanResults(boolean flush, ScanListener listener) {
+        validateChannel();
+        sAsyncChannel.sendMessage(CMD_GET_SCAN_RESULTS, 0, getListenerKey(listener));
+    }
+
+    public static class HotspotInfo {
+        public String bssid;
+        public int low;                                            /* minimum RSSI */
+        public int high;                                           /* maximum RSSI */
+    }
+
+    public static class WifiChangeSettings {
+        public int rssiSampleSize;                                 /* sample size for RSSI averaging */
+        public int lostApSampleSize;                               /* samples to confirm AP's loss */
+        public int unchangedSampleSize;                            /* samples to confirm no change */
+        public int minApsBreachingThreshold;                       /* change threshold to trigger event */
+        public HotspotInfo[] hotspotInfos;
+    }
+
+    /* overrides the significant wifi change state machine configuration */
+    public void configureSignificantWifiChange(
+            int rssiSampleSize,                             /* sample size for RSSI averaging */
+            int lostApSampleSize,                           /* samples to confirm AP's loss */
+            int unchangedSampleSize,                        /* samples to confirm no change */
+            int minApsBreachingThreshold,                   /* change threshold to trigger event */
+            HotspotInfo[] hotspotInfos                      /* signal thresholds to crosss */
+            )
+    {
+        validateChannel();
+        WifiChangeSettings settings = new WifiChangeSettings();
+        settings.rssiSampleSize = rssiSampleSize;
+        settings.lostApSampleSize = lostApSampleSize;
+        settings.unchangedSampleSize = unchangedSampleSize;
+        settings.minApsBreachingThreshold = minApsBreachingThreshold;
+        settings.hotspotInfos = hotspotInfos;
+
+        sAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
+    }
+
+    public interface SignificantWifiChangeListener extends ActionListener {
+        public void onChanging(ScanResult[] results);           /* changes are found */
+        public void onQuiescence(ScanResult[] results);         /* changes settled down */
+    }
+
+    public void trackSignificantWifiChange(SignificantWifiChangeListener listener) {
+        validateChannel();
+        sAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, putListener(listener));
+    }
+    public void untrackSignificantWifiChange(SignificantWifiChangeListener listener) {
+        validateChannel();
+        sAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, removeListener(listener));
+    }
+
+    public void configureSignificantWifiChange(WifiChangeSettings settings) {
+        validateChannel();
+        sAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
+    }
+
+    public static interface HotlistListener extends ActionListener {
+        public void onFound(ScanResult[] results);
+    }
+
+    /** @hide */
+    public static class HotlistSettings implements Parcelable {
+        public HotspotInfo[] hotspotInfos;
+        public int apLostThreshold;
+
+        /** Implement the Parcelable interface {@hide} */
+        public int describeContents() {
+            return 0;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(apLostThreshold);
+            dest.writeInt(hotspotInfos.length);
+            for (int i = 0; i < hotspotInfos.length; i++) {
+                HotspotInfo info = hotspotInfos[i];
+                dest.writeString(info.bssid);
+                dest.writeInt(info.low);
+                dest.writeInt(info.high);
+            }
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public static final Creator<HotlistSettings> CREATOR =
+                new Creator<HotlistSettings>() {
+                    public HotlistSettings createFromParcel(Parcel in) {
+                        HotlistSettings settings = new HotlistSettings();
+                        settings.apLostThreshold = in.readInt();
+                        int n = in.readInt();
+                        settings.hotspotInfos = new HotspotInfo[n];
+                        for (int i = 0; i < n; i++) {
+                            HotspotInfo info = new HotspotInfo();
+                            info.bssid = in.readString();
+                            info.low = in.readInt();
+                            info.high = in.readInt();
+                            settings.hotspotInfos[i] = info;
+                        }
+                        return settings;
+                    }
+
+                    public HotlistSettings[] newArray(int size) {
+                        return new HotlistSettings[size];
+                    }
+                };
+    }
+
+    public void setHotlist(HotspotInfo[] hotspots,
+            int apLostThreshold, HotlistListener listener) {
+        validateChannel();
+        HotlistSettings settings = new HotlistSettings();
+        settings.hotspotInfos = hotspots;
+        sAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, putListener(listener), settings);
+    }
+
+    public void resetHotlist(HotlistListener listener) {
+        validateChannel();
+        sAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, removeListener(listener));
+    }
+
+
+    /* private members and methods */
+
+    private static final String TAG = "WifiScanner";
+    private static final boolean DBG = true;
+
+    /* commands for Wifi Service */
+    private static final int BASE = Protocol.BASE_WIFI_SCANNER;
+
+    /** @hide */
+    public static final int CMD_SCAN                        = BASE + 0;
+    /** @hide */
+    public static final int CMD_START_BACKGROUND_SCAN       = BASE + 2;
+    /** @hide */
+    public static final int CMD_STOP_BACKGROUND_SCAN        = BASE + 3;
+    /** @hide */
+    public static final int CMD_GET_SCAN_RESULTS            = BASE + 4;
+    /** @hide */
+    public static final int CMD_SCAN_RESULT                 = BASE + 5;
+    /** @hide */
+    public static final int CMD_SET_HOTLIST                 = BASE + 6;
+    /** @hide */
+    public static final int CMD_RESET_HOTLIST               = BASE + 7;
+    /** @hide */
+    public static final int CMD_AP_FOUND                    = BASE + 9;
+    /** @hide */
+    public static final int CMD_AP_LOST                     = BASE + 10;
+    /** @hide */
+    public static final int CMD_START_TRACKING_CHANGE       = BASE + 11;
+    /** @hide */
+    public static final int CMD_STOP_TRACKING_CHANGE        = BASE + 12;
+    /** @hide */
+    public static final int CMD_CONFIGURE_WIFI_CHANGE       = BASE + 13;
+    /** @hide */
+    public static final int CMD_WIFI_CHANGE_DETECTED        = BASE + 15;
+    /** @hide */
+    public static final int CMD_WIFI_CHANGES_STABILIZED     = BASE + 16;
+    /** @hide */
+    public static final int CMD_OP_SUCCEEDED                = BASE + 17;
+    /** @hide */
+    public static final int CMD_OP_FAILED                   = BASE + 18;
+    /** @hide */
+    public static final int CMD_PERIOD_CHANGED              = BASE + 19;
+    /** @hide */
+    public static final int CMD_FULL_SCAN_RESULT            = BASE + 20;
+
+    private Context mContext;
+    private IWifiScanner mService;
+
+    private static final int INVALID_KEY = 0;
+    private static int sListenerKey = 1;
+
+    private static final SparseArray sListenerMap = new SparseArray();
+    private static final Object sListenerMapLock = new Object();
+
+    private static AsyncChannel sAsyncChannel;
+    private static CountDownLatch sConnected;
+
+    private static final Object sThreadRefLock = new Object();
+    private static int sThreadRefCount;
+    private static HandlerThread sHandlerThread;
+
+    /**
+     * Create a new WifiScanner instance.
+     * Applications will almost always want to use
+     * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
+     * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
+     * @param context the application context
+     * @param service the Binder interface
+     * @hide
+     */
+    public WifiScanner(Context context, IWifiScanner service) {
+        mContext = context;
+        mService = service;
+        init();
+    }
+
+    private void init() {
+        synchronized (sThreadRefLock) {
+            if (++sThreadRefCount == 1) {
+                Messenger messenger = null;
+                try {
+                    messenger = mService.getMessenger();
+                } catch (RemoteException e) {
+                    /* do nothing */
+                } catch (SecurityException e) {
+                    /* do nothing */
+                }
+
+                if (messenger == null) {
+                    sAsyncChannel = null;
+                    return;
+                }
+
+                sHandlerThread = new HandlerThread("WifiScanner");
+                sAsyncChannel = new AsyncChannel();
+                sConnected = new CountDownLatch(1);
+
+                sHandlerThread.start();
+                Handler handler = new ServiceHandler(sHandlerThread.getLooper());
+                sAsyncChannel.connect(mContext, handler, messenger);
+                try {
+                    sConnected.await();
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "interrupted wait at init");
+                }
+            }
+        }
+    }
+
+    private void validateChannel() {
+        if (sAsyncChannel == null) throw new IllegalStateException(
+                "No permission to access and change wifi or a bad initialization");
+    }
+
+    private static int putListener(Object listener) {
+        if (listener == null) return INVALID_KEY;
+        int key;
+        synchronized (sListenerMapLock) {
+            do {
+                key = sListenerKey++;
+            } while (key == INVALID_KEY);
+            sListenerMap.put(key, listener);
+        }
+        return key;
+    }
+
+    private static Object getListener(int key) {
+        if (key == INVALID_KEY) return null;
+        synchronized (sListenerMapLock) {
+            Object listener = sListenerMap.get(key);
+            return listener;
+        }
+    }
+
+    private static int getListenerKey(Object listener) {
+        if (listener == null) return INVALID_KEY;
+        synchronized (sListenerMapLock) {
+            int index = sListenerMap.indexOfValue(listener);
+            if (index == -1) {
+                return INVALID_KEY;
+            } else {
+                return sListenerMap.keyAt(index);
+            }
+        }
+    }
+
+    private static Object removeListener(int key) {
+        if (key == INVALID_KEY) return null;
+        synchronized (sListenerMapLock) {
+            Object listener = sListenerMap.get(key);
+            sListenerMap.remove(key);
+            return listener;
+        }
+    }
+
+    private static int removeListener(Object listener) {
+        int key = getListenerKey(listener);
+        if (key == INVALID_KEY) return key;
+        synchronized (sListenerMapLock) {
+            sListenerMap.remove(key);
+            return key;
+        }
+    }
+
+    private static class ServiceHandler extends Handler {
+        ServiceHandler(Looper looper) {
+            super(looper);
+        }
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
+                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
+                        sAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+                    } else {
+                        Log.e(TAG, "Failed to set up channel connection");
+                        // This will cause all further async API calls on the WifiManager
+                        // to fail and throw an exception
+                        sAsyncChannel = null;
+                    }
+                    sConnected.countDown();
+                    return;
+                case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
+                    return;
+                case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
+                    Log.e(TAG, "Channel connection lost");
+                    // This will cause all further async API calls on the WifiManager
+                    // to fail and throw an exception
+                    sAsyncChannel = null;
+                    getLooper().quit();
+                    return;
+            }
+
+            Object listener = getListener(msg.arg2);
+            if (DBG) Log.d(TAG, "listener key = " + msg.arg2);
+
+            switch (msg.what) {
+                    /* ActionListeners grouped together */
+                case CMD_OP_SUCCEEDED :
+                    ((ActionListener) listener).onSuccess(msg.obj);
+                    break;
+                case CMD_OP_FAILED :
+                    ((ActionListener) listener).onFailure(msg.arg1, msg.obj);
+                    break;
+                case CMD_SCAN_RESULT :
+                    ((ScanListener) listener).onResults(
+                            ((ParcelableScanResults) msg.obj).getResults());
+                    return;
+                case CMD_FULL_SCAN_RESULT :
+                    FullScanResult result = (FullScanResult) msg.obj;
+                    ((ScanListener) listener).onFullResult(result);
+                    return;
+                case CMD_AP_FOUND:
+                    ((HotlistListener) listener).onFound(
+                            ((ParcelableScanResults) msg.obj).getResults());
+                    return;
+                case CMD_WIFI_CHANGE_DETECTED:
+                    ((SignificantWifiChangeListener) listener).onChanging(
+                            ((ParcelableScanResults) msg.obj).getResults());
+                   return;
+                case CMD_WIFI_CHANGES_STABILIZED:
+                    ((SignificantWifiChangeListener) listener).onQuiescence(
+                            ((ParcelableScanResults) msg.obj).getResults());
+                    return;
+                default:
+                    if (DBG) Log.d(TAG, "Ignoring message " + msg.what);
+                    return;
+            }
+        }
+    }
+}
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
deleted file mode 100644
index 7ded171..0000000
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ /dev/null
@@ -1,326 +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.wifi;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.BaseNetworkStateTracker;
-import android.net.LinkCapabilities;
-import android.net.LinkQualityInfo;
-import android.net.LinkProperties;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
-import android.net.SamplingDataTracker;
-import android.net.WifiLinkQualityInfo;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
-import android.util.Slog;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Track the state of wifi for connectivity service.
- *
- * @hide
- */
-public class WifiStateTracker extends BaseNetworkStateTracker {
-
-    private static final String NETWORKTYPE = "WIFI";
-    private static final String TAG = "WifiStateTracker";
-
-    private static final boolean LOGV = true;
-
-    private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
-    private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
-    private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
-
-    private NetworkInfo.State mLastState = NetworkInfo.State.UNKNOWN;
-
-    private WifiInfo mWifiInfo;
-
-    /* For sending events to connectivity service handler */
-    private Handler mCsHandler;
-    private BroadcastReceiver mWifiStateReceiver;
-    private WifiManager mWifiManager;
-
-    private SamplingDataTracker mSamplingDataTracker = new SamplingDataTracker();
-
-    public WifiStateTracker(int netType, String networkName) {
-        mNetworkInfo = new NetworkInfo(netType, 0, networkName, "");
-        mLinkProperties = new LinkProperties();
-        mLinkCapabilities = new LinkCapabilities();
-
-        mNetworkInfo.setIsAvailable(false);
-        setTeardownRequested(false);
-    }
-
-
-    public void setTeardownRequested(boolean isRequested) {
-        mTeardownRequested.set(isRequested);
-    }
-
-    public boolean isTeardownRequested() {
-        return mTeardownRequested.get();
-    }
-
-    /**
-     * Begin monitoring wifi connectivity
-     */
-    public void startMonitoring(Context context, Handler target) {
-        mCsHandler = target;
-        mContext = context;
-
-        mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-        filter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
-
-        mWifiStateReceiver = new WifiStateReceiver();
-        mContext.registerReceiver(mWifiStateReceiver, filter);
-    }
-
-    /**
-     * Disable connectivity to a network
-     * TODO: do away with return value after making MobileDataStateTracker async
-     */
-    public boolean teardown() {
-        mTeardownRequested.set(true);
-        mWifiManager.stopWifi();
-        return true;
-    }
-
-    /**
-     * Re-enable connectivity to a network after a {@link #teardown()}.
-     */
-    public boolean reconnect() {
-        mTeardownRequested.set(false);
-        mWifiManager.startWifi();
-        return true;
-    }
-
-    @Override
-    public void captivePortalCheckCompleted(boolean isCaptivePortal) {
-        // not implemented
-    }
-
-    /**
-     * Turn the wireless radio off for a network.
-     * @param turnOn {@code true} to turn the radio on, {@code false}
-     */
-    public boolean setRadio(boolean turnOn) {
-        mWifiManager.setWifiEnabled(turnOn);
-        return true;
-    }
-
-    /**
-     * Wi-Fi is considered available as long as we have a connection to the
-     * supplicant daemon and there is at least one enabled network. If a teardown
-     * was explicitly requested, then Wi-Fi can be restarted with a reconnect
-     * request, so it is considered available. If the driver has been stopped
-     * for any reason other than a teardown request, Wi-Fi is considered
-     * unavailable.
-     * @return {@code true} if Wi-Fi connections are possible
-     */
-    public boolean isAvailable() {
-        return mNetworkInfo.isAvailable();
-    }
-
-    @Override
-    public void setUserDataEnable(boolean enabled) {
-        Slog.w(TAG, "ignoring setUserDataEnable(" + enabled + ")");
-    }
-
-    @Override
-    public void setPolicyDataEnable(boolean enabled) {
-        // ignored
-    }
-
-    /**
-     * Check if private DNS route is set for the network
-     */
-    public boolean isPrivateDnsRouteSet() {
-        return mPrivateDnsRouteSet.get();
-    }
-
-    /**
-     * Set a flag indicating private DNS route is set
-     */
-    public void privateDnsRouteSet(boolean enabled) {
-        mPrivateDnsRouteSet.set(enabled);
-    }
-
-    /**
-     * Fetch NetworkInfo for the network
-     */
-    @Override
-    public NetworkInfo getNetworkInfo() {
-        return new NetworkInfo(mNetworkInfo);
-    }
-
-    /**
-     * Fetch LinkProperties for the network
-     */
-    @Override
-    public LinkProperties getLinkProperties() {
-        return new LinkProperties(mLinkProperties);
-    }
-
-    /**
-     * A capability is an Integer/String pair, the capabilities
-     * are defined in the class LinkSocket#Key.
-     *
-     * @return a copy of this connections capabilities, may be empty but never null.
-     */
-    @Override
-    public LinkCapabilities getLinkCapabilities() {
-        return new LinkCapabilities(mLinkCapabilities);
-    }
-
-    /**
-     * Return link info
-     * @return an object of type WifiLinkQualityInfo
-     */
-    @Override
-    public LinkQualityInfo getLinkQualityInfo() {
-        if (mNetworkInfo == null) {
-            // no data available yet; just return
-            return null;
-        }
-
-        WifiLinkQualityInfo li = new WifiLinkQualityInfo();
-        li.setNetworkType(mNetworkInfo.getType());
-
-        synchronized(mSamplingDataTracker.mSamplingDataLock) {
-            mSamplingDataTracker.setCommonLinkQualityInfoFields(li);
-            li.setTxGood(mSamplingDataTracker.getSampledTxPacketCount());
-            li.setTxBad(mSamplingDataTracker.getSampledTxPacketErrorCount());
-        }
-
-        // li.setTheoreticalRxBandwidth(??);
-        // li.setTheoreticalTxBandwidth(??);
-
-        if (mWifiInfo != null) {
-            li.setBssid(mWifiInfo.getBSSID());
-
-            int rssi = mWifiInfo.getRssi();
-            li.setRssi(rssi);
-
-            li.setNormalizedSignalStrength(mWifiManager.calculateSignalLevel(rssi,
-                    LinkQualityInfo.NORMALIZED_SIGNAL_STRENGTH_RANGE));
-        }
-
-        return li;
-    }
-
-    /**
-     * Check if default route is set
-     */
-    public boolean isDefaultRouteSet() {
-        return mDefaultRouteSet.get();
-    }
-
-    /**
-     * Set a flag indicating default route is set for the network
-     */
-    public void defaultRouteSet(boolean enabled) {
-        mDefaultRouteSet.set(enabled);
-    }
-
-    /**
-     * Return the system properties name associated with the tcp buffer sizes
-     * for this network.
-     */
-    public String getTcpBufferSizesPropName() {
-        return "net.tcp.buffersize.wifi";
-    }
-
-    private class WifiStateReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-
-            if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-                mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
-                        WifiManager.EXTRA_NETWORK_INFO);
-
-                mLinkProperties = intent.getParcelableExtra(
-                        WifiManager.EXTRA_LINK_PROPERTIES);
-                if (mLinkProperties == null) {
-                    mLinkProperties = new LinkProperties();
-                }
-                mLinkCapabilities = intent.getParcelableExtra(
-                        WifiManager.EXTRA_LINK_CAPABILITIES);
-                if (mLinkCapabilities == null) {
-                    mLinkCapabilities = new LinkCapabilities();
-                }
-
-                mWifiInfo = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
-                // don't want to send redundant state messages
-                // but send portal check detailed state notice
-                NetworkInfo.State state = mNetworkInfo.getState();
-                if (mLastState == state &&
-                        mNetworkInfo.getDetailedState() != DetailedState.CAPTIVE_PORTAL_CHECK) {
-                    return;
-                } else {
-                    mLastState = state;
-                    /* lets not sample traffic data across state changes */
-                    mSamplingDataTracker.resetSamplingData();
-                }
-
-                Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED,
-                        new NetworkInfo(mNetworkInfo));
-                msg.sendToTarget();
-            } else if (intent.getAction().equals(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION)) {
-                mLinkProperties = intent.getParcelableExtra(WifiManager.EXTRA_LINK_PROPERTIES);
-                Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
-                msg.sendToTarget();
-            }
-        }
-    }
-
-    public void setDependencyMet(boolean met) {
-        // not supported on this network
-    }
-
-    @Override
-    public void addStackedLink(LinkProperties link) {
-        mLinkProperties.addStackedLink(link);
-    }
-
-    @Override
-    public void removeStackedLink(LinkProperties link) {
-        mLinkProperties.removeStackedLink(link);
-    }
-
-    @Override
-    public void supplyMessenger(Messenger messenger) {
-        // not supported on this network
-    }
-
-    @Override
-    public void startSampling(SamplingDataTracker.SamplingSnapshot s) {
-        mSamplingDataTracker.startSampling(s);
-    }
-
-    @Override
-    public void stopSampling(SamplingDataTracker.SamplingSnapshot s) {
-        mSamplingDataTracker.stopSampling(s);
-    }
-}
-